Google Pay API จะแสดงวิธีการชำระเงินในPaymentMethodTokenเพย์โหลดที่ลงนามและเข้ารหัส
วิธีการชำระเงินที่ส่งคืนคือบัตรที่มี PAN หรือบัตรที่แปลงเป็นโทเค็นซึ่งมี PAN ของอุปกรณ์และรหัสลับ
เพย์โหลดมีฟิลด์ชื่อ protocolVersion ซึ่งจะบอกผู้รับเพย์โหลดว่า
มีการใช้ฟังก์ชันการเข้ารหัสลับใดและรูปแบบที่คาดไว้
คู่มือนี้ให้ข้อมูลเกี่ยวกับวิธีสร้างคีย์สาธารณะเพื่อขอโทเค็นวิธีการชำระเงินที่เข้ารหัสและลงนามโดย Google รวมถึงรายละเอียดขั้นตอนที่ต้องดำเนินการเพื่อยืนยันและถอดรหัสโทเค็น
คำแนะนำนี้ใช้กับ protocolVersion = ECv2 เท่านั้น
เนื่องจากคุณได้รับข้อมูลบัตรชำระเงินโดยตรง โปรดตรวจสอบว่าแอปของคุณเป็นไปตาม PCI DSS และเซิร์ฟเวอร์ของคุณมีโครงสร้างพื้นฐานที่จำเป็นในการจัดการข้อมูลเข้าสู่ระบบการชำระเงินของผู้ใช้อย่างปลอดภัยก่อนที่จะดำเนินการต่อ
ขั้นตอนต่อไปนี้จะอธิบายสิ่งที่ผู้ผสานรวมต้องทำเพื่อใช้เพย์โหลดของ Google Pay API
ECv2 PaymentMethodToken
- ดึงข้อมูลคีย์การลงนามรูทของ Google
- ตรวจสอบว่าลายเซ็นของคีย์การลงนามระดับกลางถูกต้องโดยใช้คีย์การลงนามรูทที่ยังไม่หมดอายุ
- ตรวจสอบว่าคีย์การลงนามระดับกลางของเพย์โหลดยังไม่หมดอายุ
- ตรวจสอบว่าลายเซ็นของเพย์โหลดถูกต้องโดยใช้คีย์การลงนามระดับกลาง
- ถอดรหัสเนื้อหาของเพย์โหลดหลังจากยืนยันลายเซ็นแล้ว
- ตรวจสอบว่าข้อความยังไม่หมดอายุ ซึ่งกำหนดให้คุณต้องตรวจสอบว่าเวลาปัจจุบันน้อยกว่าฟิลด์
messageExpirationในเนื้อหาที่ถอดรหัสแล้ว - ใช้วิธีการชำระเงินในเนื้อหาที่ถอดรหัสแล้วและเรียกเก็บเงิน
โค้ดตัวอย่างในไลบรารี Tink จะดำเนินการตามขั้นตอนที่ 1-6
โครงสร้างโทเค็นวิธีการชำระเงิน
ข้อความที่ Google ส่งคืนในการตอบกลับ PaymentData คือออบเจ็กต์ JSON ที่เข้ารหัส UTF-8
และซีเรียลไลซ์โดยมีคีย์ที่ระบุในตารางต่อไปนี้
| ชื่อ | ประเภท | คำอธิบาย |
|---|---|---|
protocolVersion |
สตริง | ระบุรูปแบบการเข้ารหัสหรือการลงนามที่ใช้สร้างข้อความ ซึ่งจะช่วยให้โปรโตคอลพัฒนาไปตามกาลเวลาได้หากจำเป็น |
signature |
สตริง | ยืนยันว่าข้อความมาจาก Google โดยจะเข้ารหัส Base64 และสร้างด้วย ECDSA โดย คีย์การลงชื่อระดับกลาง |
intermediateSigningKey |
วัตถุ | ออบเจ็กต์ JSON ที่มีคีย์การลงนามระดับกลางจาก Google โดยมี signedKey ที่มี keyValue, keyExpiration และ signatures โดยจะมีการแปลงเป็นอนุกรมเพื่อลดความซับซ้อนของกระบวนการยืนยันลายเซ็นคีย์การลงนามระดับกลาง
|
signedMessage |
สตริง | ออบเจ็กต์ JSON ที่แปลงเป็นสตริงที่ปลอดภัยสำหรับ HTML ซึ่งมี encryptedMessage, ephemeralPublicKey และ tag โดยจะ
จัดรูปแบบเป็นอนุกรมเพื่อลดความซับซ้อนของกระบวนการยืนยันลายเซ็น |
ตัวอย่าง
ต่อไปนี้คือการตอบกลับโทเค็นวิธีการชำระเงินใน JSON
{ "protocolVersion":"ECv2", "signature":"MEQCIH6Q4OwQ0jAceFEkGF0JID6sJNXxOEi4r+mA7biRxqBQAiAondqoUpU/bdsrAOpZIsrHQS9nwiiNwOrr24RyPeHA0Q\u003d\u003d", "intermediateSigningKey":{ "signedKey": "{\"keyExpiration\":\"1542323393147\",\"keyValue\":\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/1+3HBVSbdv+j7NaArdgMyoSAM43yRydzqdg1TxodSzA96Dj4Mc1EiKroxxunavVIvdxGnJeFViTzFvzFRxyCw\\u003d\\u003d\"}", "signatures": ["MEYCIQCO2EIi48s8VTH+ilMEpoXLFfkxAwHjfPSCVED/QDSHmQIhALLJmrUlNAY8hDQRV/y1iKZGsWpeNmIP+z+tCQHQxP0v"] }, "signedMessage":"{\"tag\":\"jpGz1F1Bcoi/fCNxI9n7Qrsw7i7KHrGtTf3NrRclt+U\\u003d\",\"ephemeralPublicKey\":\"BJatyFvFPPD21l8/uLP46Ta1hsKHndf8Z+tAgk+DEPQgYTkhHy19cF3h/bXs0tWTmZtnNm+vlVrKbRU9K8+7cZs\\u003d\",\"encryptedMessage\":\"mKOoXwi8OavZ\"}" }
คีย์การลงชื่อระดับกลาง
intermediateSigningKey คือออบเจ็กต์ JSON ที่เข้ารหัส UTF-8 และจัดรูปแบบเป็นอนุกรมซึ่งมีค่าต่อไปนี้
| ชื่อ | ประเภท | คำอธิบาย |
|---|---|---|
signedKey |
สตริง | ข้อความที่เข้ารหัส Base64 ซึ่งมีคำอธิบายการชำระเงินของคีย์ |
signatures |
สตริง | ยืนยันว่าคีย์การลงนามระดับกลางมาจาก Google โดยจะเข้ารหัส Base64 และ สร้างด้วย ECDSA |
คีย์ที่ลงนาม
signedKey คือออบเจ็กต์ JSON ที่เข้ารหัส UTF-8 และจัดรูปแบบเป็นอนุกรมซึ่งมีค่าต่อไปนี้
| ชื่อ | ประเภท | คำอธิบาย |
|---|---|---|
keyValue |
สตริง | คีย์เวอร์ชัน Base64 ที่เข้ารหัสในประเภท ASN.1 SubjectPublicKeyInfo มีคำจำกัดความในมาตรฐาน X.509 |
keyExpiration |
สตริง | วันที่และเวลาที่คีย์ระดับกลางหมดอายุเป็นมิลลิวินาที UTC ตั้งแต่ Epoch ผู้ผสานรวมจะปฏิเสธคีย์ที่หมดอายุ |
ข้อความที่ลงชื่อ
signedMessage คือออบเจ็กต์ JSON ที่เข้ารหัส UTF-8 และจัดรูปแบบเป็นอนุกรมซึ่งมีค่าต่อไปนี้
| ชื่อ | ประเภท | คำอธิบาย |
|---|---|---|
encryptedMessage |
สตริง | ข้อความที่เข้ารหัสซึ่งเข้ารหัส Base64 ที่มีข้อมูลการชำระเงินและฟิลด์ความปลอดภัยเพิ่มเติมบางส่วน |
ephemeralPublicKey |
สตริง | คีย์สาธารณะชั่วคราวที่เข้ารหัส Base64 ซึ่งเชื่อมโยงกับคีย์ส่วนตัวเพื่อเข้ารหัส ข้อความในรูปแบบพอยต์ที่ไม่ได้บีบอัด ดูข้อมูลเพิ่มเติมได้ที่ รูปแบบคีย์สาธารณะสำหรับการเข้ารหัส |
tag |
สตริง | MAC ที่เข้ารหัส Base64 ของ encryptedMessage |
ข้อความที่เข้ารหัส
encryptedMessage ที่ถอดรหัสแล้วคือออบเจ็กต์ JSON ที่เข้ารหัส UTF-8 และแปลงเป็นอนุกรม
JSON มี 2 ระดับ ระดับนอกสุดมีข้อมูลเมตาและฟิลด์ที่รวมไว้เพื่อความปลอดภัย ส่วน
ระดับในสุดคือออบเจ็กต์ JSON อีกรายการที่แสดงข้อมูลเข้าสู่ระบบการชำระเงินจริง
ดูรายละเอียดเพิ่มเติมเกี่ยวกับ encryptedMessage ได้ในตารางต่อไปนี้และ
ตัวอย่างออบเจ็กต์ JSON
| ชื่อ | ประเภท | คำอธิบาย |
|---|---|---|
messageExpiration |
สตริง | วันที่และเวลาที่ข้อความหมดอายุเป็นมิลลิวินาที UTC ตั้งแต่ Epoch ผู้ผสานรวมควรปฏิเสธข้อความที่หมดอายุแล้ว |
messageId |
สตริง | รหัสที่ไม่ซ้ำกันซึ่งระบุข้อความในกรณีที่ต้องเพิกถอนหรือค้นหาในภายหลัง |
paymentMethod |
สตริง | ประเภทของข้อมูลเข้าสู่ระบบการชำระเงิน
ปัจจุบันรองรับเฉพาะ CARD เท่านั้น
|
paymentMethodDetails |
วัตถุ | ข้อมูลเข้าสู่ระบบการชำระเงิน รูปแบบของออบเจ็กต์นี้กำหนดโดย
paymentMethod และอธิบายไว้ในตารางต่อไปนี้ |
การ์ด
พร็อพเพอร์ตี้ต่อไปนี้ประกอบกันเป็นข้อมูลเข้าสู่ระบบการชำระเงินสำหรับวิธีการชำระเงินCARD
| ชื่อ | ประเภท | คำอธิบาย |
|---|---|---|
pan |
สตริง | หมายเลขบัญชีส่วนตัวที่เรียกเก็บเงิน สตริงนี้มีเฉพาะตัวเลข |
expirationMonth |
ตัวเลข | เดือนที่บัตรหมดอายุ โดย 1 แทนเดือนมกราคม 2 แทนเดือนกุมภาพันธ์ และอื่นๆ |
expirationYear |
ตัวเลข | ปีที่บัตรหมดอายุซึ่งเป็นตัวเลข 4 หลัก เช่น 2020 |
authMethod |
สตริง | วิธีการตรวจสอบสิทธิ์ของธุรกรรมในบัตร |
PAN_ONLY
ข้อมูลโค้ด JSON ต่อไปนี้เป็นตัวอย่างของ encryptedMessage แบบเต็มสำหรับ
CARD paymentMethod
ที่มี PAN_ONLY authMethod
{ "paymentMethod": "CARD", "paymentMethodDetails": { "authMethod": "PAN_ONLY", "pan": "1111222233334444", "expirationMonth": 10, "expirationYear": 2025 }, "gatewayMerchantId": "some-merchant-id", "messageId": "some-message-id", "messageExpiration": "1759309000000" }
CRYPTOGRAM_3DS
CARD ที่ได้รับการตรวจสอบสิทธิ์โดยใช้รหัสลับ 3-D Secure
CRYPTOGRAM_3DS authMethod โดยจะมีช่องเพิ่มเติมต่อไปนี้
| ชื่อ | ประเภท | คำอธิบาย |
|---|---|---|
cryptogram |
สตริง | รหัสคริปโตแกรม 3-D Secure |
eciIndicator |
สตริง | สตริงนี้อาจไม่มีอยู่เสมอไป โดยจะแสดงเฉพาะธุรกรรมโทเค็นอุปกรณ์ที่ผ่านการตรวจสอบสิทธิ์ใน Android (CRYPTOGRAM_3DS) ค่านี้ต้องส่งผ่านโฟลว์การประมวลผลการชำระเงิน |
ข้อมูลโค้ด JSON ต่อไปนี้เป็นตัวอย่างของ encryptedMessage แบบเต็มสำหรับ
CARD paymentMethod ที่มี
CRYPTOGRAM_3DS authMethod
{ "paymentMethod": "CARD", "paymentMethodDetails": { "authMethod": "CRYPTOGRAM_3DS", "pan": "1111222233334444", "expirationMonth": 10, "expirationYear": 2025, "cryptogram": "AAAAAA...", "eciIndicator": "eci indicator" }, "messageId": "some-message-id", "messageExpiration": "1759309000000" }
eciIndicator
เครือข่ายบัตรอาจระบุ eciIndicator สำหรับธุรกรรมโทเค็นอุปกรณ์ที่ได้รับการตรวจสอบสิทธิ์ (CRYPTOGRAM_3DS)
คุณต้องส่งค่า eciIndicator ในธุรกรรมการให้สิทธิ์โดยไม่มีการดัดแปลงหรือฮาร์ดโค้ด มิฉะนั้นธุรกรรมจะล้มเหลว ตารางต่อไปนี้แสดงรายละเอียดค่าของ eciIndicator
| ค่า eciIndicator | เครือข่ายบัตร | ผู้รับผิด | authMethod |
|---|---|---|---|
""(empty) |
Mastercard | ผู้ขาย/ผู้รับชำระเงิน | CRYPTOGRAM_3DS |
02 |
Mastercard | ผู้ออกบัตร | CRYPTOGRAM_3DS |
06 |
Mastercard | ผู้ขาย/ผู้รับชำระเงิน | CRYPTOGRAM_3DS |
05 |
Visa | ผู้ออกบัตร | CRYPTOGRAM_3DS |
07 |
Visa | ผู้ขาย/ผู้รับชำระเงิน | CRYPTOGRAM_3DS |
""(empty) |
เครือข่ายอื่น | ผู้ขาย/ผู้รับชำระเงิน | CRYPTOGRAM_3DS |
ระบบจะไม่แสดงค่า ECI อื่นๆ สำหรับ VISA และ Mastercard ที่ไม่ได้อยู่ในตารางนี้
การยืนยันลายเซ็น
หากต้องการยืนยันลายเซ็น ซึ่งรวมถึงคีย์ระดับกลางและลายเซ็นของข้อความ คุณต้องมีรายการต่อไปนี้
- อัลกอริทึมที่ใช้สร้างลายเซ็น
- สตริงไบต์ที่ใช้สร้างลายเซ็น
- คีย์สาธารณะที่ตรงกับคีย์ส่วนตัวที่ใช้สร้างลายเซ็น
- ลายเซ็น
อัลกอริทึมลายเซ็น
Google ใช้ Elliptic Curve Digital Signature Algorithm (ECDSA) เพื่อลงนามข้อความที่มีพารามิเตอร์ต่อไปนี้ ECDSA ผ่าน NIST P-256 ที่มี SHA-256 เป็นฟังก์ชันแฮช ตามที่กำหนดไว้ใน FIPS 186-4
ลายเซ็น
ลายเซ็นจะรวมอยู่ในระดับนอกสุดของข้อความ โดยจะเข้ารหัสด้วย base64 ในรูปแบบไบต์ ASN.1 ดูข้อมูลเพิ่มเติมเกี่ยวกับ ASN.1 ได้ที่ ภาคผนวก ก ของเครื่องมือ IETF ลายเซ็นประกอบด้วยจำนวนเต็ม r และ s ของ ECDSA ดูข้อมูลเพิ่มเติมได้ที่ อัลกอริทึมการสร้างลายเซ็น
ต่อไปนี้เป็นตัวอย่างของรูปแบบไบต์ ASN.1 ที่ระบุ ซึ่งเป็นรูปแบบมาตรฐาน ที่สร้างขึ้นโดยการติดตั้งใช้งาน ECDSA ของ Java Cryptography Extension (JCE)
ECDSA-Sig-Value :: = SEQUENCE {
r INTEGER,
s INTEGER
}วิธีสร้างสตริงไบต์สำหรับลายเซ็นคีย์การลงนามระดับกลาง
หากต้องการตรวจสอบลายเซ็นของคีย์การลงนามระดับกลางในโทเค็นวิธีการชำระเงินตัวอย่าง ให้สร้าง
signedStringForIntermediateSigningKeySignature ด้วยสูตรต่อไปนี้
signedStringForIntermediateSigningKeySignature = length_of_sender_id || sender_id || length_of_protocol_version || protocol_version || length_of_signed_key || signed_key
สัญกรณ์ "||" หมายถึงการต่อกัน คอมโพเนนต์แต่ละรายการ—sender_id,
protocolVersion, signedKey—ต้องเข้ารหัส UTF-8 signedKey ต้องเป็นสตริงของ intermediateSigningKey.signedKey
ความยาวของแต่ละคอมโพเนนต์คือ 4 ไบต์ในรูปแบบ Little-Endian
ตัวอย่าง
ตัวอย่างนี้ใช้โทเค็นวิธีการชำระเงินตัวอย่างต่อไปนี้
{
"protocolVersion":"ECv2",
"signature":"MEQCIH6Q4OwQ0jAceFEkGF0JID6sJNXxOEi4r+mA7biRxqBQAiAondqoUpU/bdsrAOpZIsrHQS9nwiiNwOrr24RyPeHA0Q\u003d\u003d",
"intermediateSigningKey":{
"signedKey": "{\"keyExpiration\":\"1542323393147\",\"keyValue\":\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/1+3HBVSbdv+j7NaArdgMyoSAM43yRydzqdg1TxodSzA96Dj4Mc1EiKroxxunavVIvdxGnJeFViTzFvzFRxyCw\\u003d\\u003d\"}",
"signatures": ["MEYCIQCO2EIi48s8VTH+ilMEpoXLFfkxAwHjfPSCVED/QDSHmQIhALLJmrUlNAY8hDQRV/y1iKZGsWpeNmIP+z+tCQHQxP0v"]
},
"signedMessage":"{\"tag\":\"jpGz1F1Bcoi/fCNxI9n7Qrsw7i7KHrGtTf3NrRclt+U\\u003d\",\"ephemeralPublicKey\":\"BJatyFvFPPD21l8/uLP46Ta1hsKHndf8Z+tAgk+DEPQgYTkhHy19cF3h/bXs0tWTmZtnNm+vlVrKbRU9K8+7cZs\\u003d\",\"encryptedMessage\":\"mKOoXwi8OavZ\"}"
}sender_id จะเป็น Google เสมอ และ protocol_version จะเป็น
ECv2
หาก sender_id เป็น Google signedString จะปรากฏดังที่แสดงในตัวอย่างต่อไปนี้
signedStringForIntermediateSigningKeySignature =
\x06\x00\x00\x00 || Google || | \x04\x00\x00\x00 || ECv2 || \xb5\x00\x00\x00 || {"keyExpiration":"1542323393147","keyValue":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/1+3HBVSbdv+j7NaArdgMyoSAM43yRydzqdg1TxodSzA96Dj4Mc1EiKroxxunavVIvdxGnJeFViTzFvzFRxyCw\u003d\u003d"}วิธียืนยันลายเซ็นใน signedStringForIntermediateSigningKeySignature
ระบบจะใช้อัลกอริทึมการยืนยัน ECDSA มาตรฐานเมื่อประกอบสตริงที่ลงนามสำหรับลายเซ็นคีย์การลงนามระดับกลาง
สำหรับโปรโตคอล ECv2 คุณต้องทำซ้ำลายเซ็นทั้งหมด
ใน intermediateSigningKey.signatures และพยายามตรวจสอบแต่ละรายการด้วย
คีย์การลงนามของ Google ที่ยังไม่หมดอายุใน keys.json หากการตรวจสอบลายเซ็นอย่างน้อย 1 รายการ
ใช้งานได้ ให้ถือว่าการยืนยันเสร็จสมบูรณ์ ใช้
intermediateSigningKey.signedKey.keyValue ภายหลังเพื่อยืนยัน
signedStringForMessageSignature Google ขอแนะนำให้คุณใช้ไลบรารี
การเข้ารหัสที่มีอยู่แทนที่จะใช้รหัสยืนยันของคุณเอง
วิธีสร้างสตริงไบต์สำหรับลายเซ็นข้อความ
หากต้องการตรวจสอบลายเซ็นในโทเค็นวิธีการชำระเงินตัวอย่าง ให้สร้าง
signedStringForMessageSignature โดยใช้สูตรต่อไปนี้
signedStringForMessageSignature = length_of_sender_id || sender_id || length_of_recipient_id || recipient_id || length_of_protocolVersion || protocolVersion || length_of_signedMessage || signedMessage
สัญกรณ์ "||" หมายถึงการต่อกัน คอมโพเนนต์แต่ละรายการ ได้แก่ sender_id,
recipient_id, protocolVersion, signedMessage ต้องเข้ารหัส UTF-8
ความยาวของแต่ละคอมโพเนนต์คือ 4 ไบต์ในรูปแบบ Little-Endian เมื่อสร้างสตริงไบต์ อย่าแยกวิเคราะห์หรือแก้ไข signedMessage เช่น อย่าแทนที่
\u003d ด้วยอักขระ =
ตัวอย่าง
ตัวอย่างต่อไปนี้คือโทเค็นวิธีการชำระเงินตัวอย่าง
{
"protocolVersion":"ECv2",
"signature":"MEQCIH6Q4OwQ0jAceFEkGF0JID6sJNXxOEi4r+mA7biRxqBQAiAondqoUpU/bdsrAOpZIsrHQS9nwiiNwOrr24RyPeHA0Q\u003d\u003d",
"intermediateSigningKey":{
"signedKey": "{\"keyExpiration\":\"1542323393147\",\"keyValue\":\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/1+3HBVSbdv+j7NaArdgMyoSAM43yRydzqdg1TxodSzA96Dj4Mc1EiKroxxunavVIvdxGnJeFViTzFvzFRxyCw\\u003d\\u003d\"}",
"signatures": ["MEYCIQCO2EIi48s8VTH+ilMEpoXLFfkxAwHjfPSCVED/QDSHmQIhALLJmrUlNAY8hDQRV/y1iKZGsWpeNmIP+z+tCQHQxP0v"]
},
"signedMessage":"{\"tag\":\"jpGz1F1Bcoi/fCNxI9n7Qrsw7i7KHrGtTf3NrRclt+U\\u003d\",\"ephemeralPublicKey\":\"BJatyFvFPPD21l8/uLP46Ta1hsKHndf8Z+tAgk+DEPQgYTkhHy19cF3h/bXs0tWTmZtnNm+vlVrKbRU9K8+7cZs\\u003d\",\"encryptedMessage\":\"mKOoXwi8OavZ\"}"
}sender_id จะเป็น Google เสมอ และ recipient_id จะเป็น
merchant:merchantId merchantId ตรงกับค่าที่พบในคอนโซล Google Pay และ Wallet สำหรับผู้ขายที่มีสิทธิ์เข้าถึงเวอร์ชันที่ใช้งานจริง
หาก sender_id คือ Google และ recipient_id
คือ merchant:12345 signedString จะปรากฏตามตัวอย่างต่อไปนี้
signedStringForMessageSignature =
\x06\x00\x00\x00 || Google || \x0e\x00\x00\x00 || merchant:12345 || | \x04\x00\x00\x00 || ECv2 || \xd2\x00\x00\x00 || {"tag":"jpGz1F1Bcoi/fCNxI9n7Qrsw7i7KHrGtTf3NrRclt+U\u003d","ephemeralPublicKey":"BJatyFvFPPD21l8/uLP46Ta1hsKHndf8Z+tAgk+DEPQgYTkhHy19cF3h/bXs0tWTmZtnNm+vlVrKbRU9K8+7cZs\u003d","encryptedMessage":"mKOoXwi8OavZ"}วิธียืนยันลายเซ็นใน signedStringForMessageSignature
เมื่อประกอบสตริงที่ลงนามแล้ว ระบบจะใช้อัลกอริทึมการยืนยัน ECDSA มาตรฐาน ระบบจะใช้
intermediateSigningKey.signedKey.keyValue ที่ยืนยันในขั้นตอนก่อนหน้าเพื่อ
ยืนยัน signedMessage Google ขอแนะนำให้คุณใช้ไลบรารี
การเข้ารหัสที่มีอยู่แทนที่จะใช้รหัสยืนยันของคุณเอง
ข้อกำหนดของรูปแบบการเข้ารหัส
Google ใช้รูปแบบการเข้ารหัสแบบผสานรวมของเส้นโค้งวงรี (ECIES) เพื่อรักษาความปลอดภัย โทเค็นวิธีการชำระเงินที่ส่งคืนในการตอบกลับของ Google Pay API รูปแบบการเข้ารหัสใช้พารามิเตอร์ต่อไปนี้
| พารามิเตอร์ | คำจำกัดความ |
|---|---|
| วิธีการห่อหุ้มคีย์ | ECIES-KEM ตามที่กำหนดไว้ใน ISO 18033-2
|
| ฟังก์ชันการได้คีย์ | อิงตาม HMAC ที่มี SHA-256 (
|
| อัลกอริทึมการเข้ารหัสแบบสมมาตร |
DEM2 ตามที่กำหนดไว้ใน ISO 18033-2 อัลกอริทึมการเข้ารหัส: AES-256-CTR ที่มี IV เป็น 0 และไม่มีการเพิ่มแพด |
| อัลกอริทึม MAC | HMAC_SHA256 ด้วยคีย์ 256 บิตที่ได้มาจากฟังก์ชันการสร้างคีย์ |
รูปแบบคีย์สาธารณะการเข้ารหัส
คีย์สาธารณะสำหรับการเข้ารหัสและ ephemeralPublicKey ที่ส่งคืนในเพย์โหลดของ Google จะ
จัดรูปแบบด้วยการแสดงคีย์ในรูปแบบ base64 ในรูปแบบจุดที่ไม่ได้บีบอัด ซึ่งประกอบด้วยองค์ประกอบ 2 อย่างต่อไปนี้
- หมายเลขวิเศษ 1 หมายเลขที่ระบุรูปแบบ (0x04)
- จำนวนเต็มขนาดใหญ่ 32 ไบต์ 2 จำนวนที่แสดงพิกัด X และ Y ใน Elliptic Curve
รูปแบบนี้อธิบายไว้โดยละเอียดใน "Public Key Cryptography For The Financial Services Industry: The Elliptic Curve Digital Signature Algorithm (ECDSA)," ANSI X9.62, 1998
ใช้ OpenSSL เพื่อสร้างคีย์สาธารณะ
ขั้นตอนที่ 1: สร้างคีย์ส่วนตัว
ตัวอย่างต่อไปนี้จะสร้างคีย์ส่วนตัวของ Elliptic Curve ที่เหมาะสำหรับใช้กับ NIST P-256
และเขียนลงใน key.pem:
openssl ecparam -name prime256v1 -genkey -noout -out key.pem
ไม่บังคับ: ดูคีย์ส่วนตัวและคีย์สาธารณะ
ใช้คำสั่งต่อไปนี้เพื่อดูทั้งคีย์ส่วนตัวและคีย์สาธารณะ
openssl ec -in key.pem -pubout -text -noout
คำสั่งจะสร้างเอาต์พุตที่คล้ายกับตัวอย่างต่อไปนี้
read EC key
Private-Key: (256 bit)
priv:
08:f4:ae:16:be:22:48:86:90:a6:b8:e3:72:11:cf:
c8:3b:b6:35:71:5e:d2:f0:c1:a1:3a:4f:91:86:8a:
f5:d7
pub:
04:e7:68:5c:ff:bd:02:ae:3b:dd:29:c6:c2:0d:c9:
53:56:a2:36:9b:1d:f6:f1:f6:a2:09:ea:e0:fb:43:
b6:52:c6:6b:72:a3:f1:33:df:fa:36:90:34:fc:83:
4a:48:77:25:48:62:4b:42:b2:ae:b9:56:84:08:0d:
64:a1:d8:17:66
ASN1 OID: prime256v1
ขั้นตอนที่ 2: สร้างคีย์สาธารณะที่เข้ารหัส Base64
คีย์ส่วนตัวและคีย์สาธารณะที่สร้างขึ้นในขั้นตอนที่ไม่บังคับ ก่อนหน้าจะได้รับการเข้ารหัสแบบเลขฐานสิบหก หากต้องการรับคีย์สาธารณะที่เข้ารหัสแบบ Base64 ในรูปแบบพอยต์ที่ไม่ได้บีบอัด ให้ใช้คำสั่งต่อไปนี้
openssl ec -in key.pem -pubout -text -noout 2> /dev/null | grep "pub:" -A5 | sed 1d | xxd -r -p | base64 | paste -sd "\0" - | tr -d '\n\r ' > publicKey.txt
คำสั่งจะสร้างไฟล์ publicKey.txt ซึ่งมีเนื้อหาเป็นคีย์เวอร์ชัน base64 ในรูปแบบจุดที่ไม่ได้บีบอัด
ซึ่งมีลักษณะคล้ายกับตัวอย่างต่อไปนี้
BOdoXP+9Aq473SnGwg3JU1aiNpsd9vH2ognq4PtDtlLGa3Kj8TPf+jaQNPyDSkh3JUhiS0KyrrlWhAgNZKHYF2Y=
เนื้อหาไฟล์ต้องไม่มีช่องว่างหรือการขึ้นบรรทัดใหม่ที่ไม่จำเป็น หากต้องการยืนยัน ให้เรียกใช้คำสั่งต่อไปนี้ใน Linux หรือ MacOS
od -bc publicKey.txt
ขั้นตอนที่ 3: สร้างคีย์ส่วนตัวที่เข้ารหัส Base64 ในรูปแบบ PKCS #8
ไลบรารี Tink คาดหวังว่าคีย์ส่วนตัวของคุณจะเข้ารหัส Base64 ในรูปแบบ PKCS #8 ใช้คำสั่งต่อไปนี้เพื่อสร้างคีย์ส่วนตัวในรูปแบบนี้จากคีย์ส่วนตัวที่สร้างขึ้นในขั้นตอนแรก
openssl pkcs8 -topk8 -inform PEM -outform DER -in key.pem -nocrypt | base64 | paste -sd "\0" -
คำสั่งจะสร้างเอาต์พุตที่คล้ายกับตัวอย่างต่อไปนี้
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgWV4oK8c/MZkCLk4qSCNjW0Zm6H0CBCtSYxkXkC9FBHehRANCAAQPldOnhO2/oXjdJD1dwlFPiNs6fcdoRgFu3/Z0iKj24SjTGyLRGAtYWLGXBZcDdPj3T2bJRHRVhE8Bc2AjkT7n
วิธีถอดรหัสโทเค็นวิธีการชำระเงิน
ทำตามขั้นตอนต่อไปนี้เพื่อถอดรหัสโทเค็น
- ใช้คีย์ส่วนตัวและ
ephemeralPublicKeyที่ระบุเพื่อสร้างคีย์ที่ใช้ร่วมกันยาว 512 บิต ซึ่งใช้ ECIES-KEM ใช้พารามิเตอร์ต่อไปนี้ - เส้นโค้งวงรี: NIST P-256 หรือที่รู้จักกันใน OpenSSL ว่า prime256v1
CheckMode,OldCofactorMode,SingleHashModeและCofactorModeเป็น0- ฟังก์ชันการเข้ารหัส: รูปแบบจุดที่ไม่มีการบีบอัด
- ฟังก์ชันการได้คีย์: HKDFwithSHA256 ตามที่อธิบายไว้ใน RFC 5869 โดยมีพารามิเตอร์ต่อไปนี้
- ห้ามระบุ Salt ตาม RFC แล้ว ค่านี้ต้องเทียบเท่ากับ Salt ที่มีไบต์เป็นศูนย์ 32
- แยกคีย์ที่สร้างขึ้นเป็นคีย์ 2 คีย์ที่มีความยาว 256 บิต ได้แก่
symmetricEncryptionKeyและmacKey ตรวจสอบว่าฟิลด์
tagเป็น MAC ที่ถูกต้องสำหรับencryptedMessageหากต้องการสร้าง MAC ที่คาดไว้ ให้ใช้ HMAC (RFC 5869) กับฟังก์ชันแฮช SHA256 และ
macKeyที่ได้รับในขั้นตอนที่ 2ถอดรหัส
encryptedMessageโดยใช้โหมด AES-256-CTR และใช้ ข้อมูลต่อไปนี้- IV เป็น 0
- ไม่ได้เว้นวรรค
symmetricEncryptionKeyที่ได้ในขั้นตอนที่ 2
การจัดการคีย์
คีย์การเข้ารหัสของผู้ขาย
ผู้ขายสร้างคีย์สาธารณะตามข้อกำหนดที่ระบุไว้ในข้อกำหนดของรูปแบบการเข้ารหัส
คีย์การลงนามรูทของ Google
Google เผยแพร่ชุดคีย์สาธารณะสำหรับการลงนามรูทที่ถูกต้องในปัจจุบัน ซึ่งสามารถดึงข้อมูลได้จาก URL สาธารณะ คีย์จะใช้งานได้ตราบเท่าที่ส่วนหัวของแคช HTTP ที่ URL ส่งกลับมา ระบุไว้ ระบบจะแคชคีย์จนกว่าจะหมดอายุ ซึ่งกำหนดโดยฟิลด์ keyExpiration เราขอแนะนำว่าเมื่อการดึงข้อมูลหมดอายุ ให้ดึงข้อมูลคีย์จาก URL สาธารณะอีกครั้งเพื่อรับรายการคีย์ที่ถูกต้องล่าสุด
ข้อยกเว้นสำหรับโปรโตคอล ECv2: หากเรียกข้อมูลคีย์จาก Google ในขณะรันไทม์ไม่ได้ ให้เรียกข้อมูล
keys.json จาก URL การผลิตของเรา บันทึกลงในระบบ และรีเฟรช
ด้วยตนเองเป็นระยะๆ ในสถานการณ์ปกติ Google จะออกคีย์การลงนามรูทใหม่สำหรับ ECv2 5 ปี
ก่อนที่คีย์ที่มีวันที่หมดอายุยาวที่สุดจะหมดอายุ ในกรณีที่คีย์ถูกบุกรุก Google จะแจ้งให้ผู้ขายทุกรายทราบผ่านข้อมูลติดต่อที่ระบุไว้ในพอร์ทัลแบบบริการตนเองเพื่อขอให้โหลด keys.json เร็วขึ้น เราขอแนะนำให้ผู้ขายที่เลือกบันทึกคีย์ของ Google ในเนื้อหาของkeys.jsonรีเฟรชทุกปีเป็นส่วนหนึ่งของการหมุนเวียนคีย์ประจำปีของตนเอง เพื่อให้คุณไม่พลาดการหมุนเวียนปกติ
ระบบจะแมปคีย์ที่ระบุผ่าน URL สาธารณะในรูปแบบต่อไปนี้
{ "keys": [ { "keyValue": "encoded public key", "protocolVersion": "ECv2" "keyExpiration":"2000000000000" }, { "keyValue": "encoded public key", "protocolVersion": "ECv2" "keyExpiration":"3000000000000" } ] }
keyValue คือเวอร์ชัน base64 ของคีย์ที่เข้ารหัสใน ASN.1
ประเภท SubjectPublicKeyInfo ที่กำหนดไว้ในมาตรฐาน X.509 โดยไม่มีการตัดหรือเพิ่มอักขระแทรก ใน Java การเข้ารหัส ASN.1 ที่อ้างอิง
จะแสดงโดยคลาส X509EncodedKeySpec
โดยสามารถรับได้ด้วย ECPublicKey.getEncoded()
URL สำหรับทั้งสภาพแวดล้อมการทดสอบและสภาพแวดล้อมการใช้งานจริงมีให้ในลิงก์ต่อไปนี้
- ทดสอบ:
https://payments.developers.google.com/paymentmethodtoken/test/keys.json - การผลิต:
https://payments.developers.google.com/paymentmethodtoken/keys.json
การหมุนเวียนคีย์
หากถอดรหัสโทเค็นวิธีการชำระเงินในเซิร์ฟเวอร์โดยตรงด้วยการผสานรวมโดยตรง คุณจะต้องหมุนเวียนคีย์ทุกปี
ทำตามขั้นตอนต่อไปนี้เพื่อหมุนเวียนคีย์การเข้ารหัส
- ใช้ OpenSSL เพื่อสร้างคู่คีย์ใหม่
- เปิด Google Pay & Wallet Console ขณะลงชื่อเข้าใช้ด้วยบัญชี Google ที่เคยใช้จัดการแอปกับ Google Play
- ในแท็บ Google Pay API ภายใต้บานหน้าต่างการผสานรวมโดยตรง ให้คลิกจัดการข้างคีย์สาธารณะที่มีอยู่ คลิกเพิ่มคีย์อื่น
- เลือกช่องป้อนข้อความคีย์การเข้ารหัสสาธารณะ แล้วเพิ่มคีย์สาธารณะที่สร้างขึ้นใหม่ ซึ่งเข้ารหัส Base64 ในรูปแบบจุดที่ไม่ได้บีบอัด
- คลิกบันทึกคีย์การเข้ารหัส
โปรดรองรับการถอดรหัสทั้งคีย์ส่วนตัวใหม่และเก่าขณะเปลี่ยนคีย์เพื่อให้การหมุนเวียนคีย์เป็นไปอย่างราบรื่น
หากใช้ไลบรารี Tink เพื่อถอดรหัสโทเค็น ให้ใช้โค้ด Java ต่อไปนี้เพื่อรองรับคีย์ส่วนตัวหลายรายการ
String decryptedMessage = new PaymentMethodTokenRecipient.Builder() .addRecipientPrivateKey(newPrivateKey) .addRecipientPrivateKey(oldPrivateKey);
ตรวจสอบว่าได้ติดตั้งใช้งานโค้ดสำหรับการถอดรหัสในการทำงานจริงแล้ว และตรวจสอบการถอดรหัสที่สำเร็จ
เปลี่ยนคีย์สาธารณะที่ใช้ในโค้ด
แทนที่ค่าของแอตทริบิวต์
publicKeyในพร็อพเพอร์ตี้PaymentMethodTokenizationSpecificationparameters/** * @param publicKey public key retrieved from your server */ private static JSONObject getTokenizationSpecification(String publicKey) { JSONObject tokenizationSpecification = new JSONObject(); tokenizationSpecification.put("type", "DIRECT"); tokenizationSpecification.put( "parameters", new JSONObject() .put("protocolVersion", "ECv2") .put("publicKey", publicKey)); return tokenizationSpecification; }
- นำโค้ดจากขั้นตอนที่ 4 ไปใช้งานจริง เมื่อติดตั้งใช้งานโค้ดแล้ว ธุรกรรมการเข้ารหัสและ การถอดรหัสจะใช้คู่คีย์ใหม่
ยืนยันว่าไม่ได้ใช้คีย์สาธารณะเดิมเพื่อเข้ารหัสธุรกรรมใดๆ อีกต่อไป
- นำคีย์ส่วนตัวเก่าออก
- เปิด Google Pay & Wallet Console ขณะลงชื่อเข้าใช้ด้วยบัญชี Google ที่คุณเคยใช้ลงชื่อสมัครใช้เป็นนักพัฒนาแอปด้วย Google Pay
- ในแท็บ Google Pay API ภายใต้บานหน้าต่างการผสานรวมโดยตรง ให้คลิกจัดการข้างคีย์สาธารณะที่มีอยู่ คลิกลบข้างคีย์สาธารณะเก่า แล้วคลิกบันทึกคีย์การเข้ารหัส
Google ใช้คีย์ที่ระบุในพร็อพเพอร์ตี้ publicKey ภายในออบเจ็กต์
PaymentMethodTokenizationSpecification parameters ดังที่แสดง
ในตัวอย่างต่อไปนี้
{
"protocolVersion": "ECv2",
"publicKey": "BOdoXP+9Aq473SnGwg3JU1..."
}ใช้ไลบรารี Tink เพื่อจัดการการตอบกลับที่เข้ารหัส
หากต้องการยืนยันลายเซ็นและถอดรหัสข้อความ ให้ใช้ไลบรารีโทเค็น paymentmethod ของ Tink ไลบรารีนี้ใช้ได้เฉพาะใน Java หากต้องการใช้ฟีเจอร์นี้ ให้ทำตามขั้นตอนต่อไปนี้
ใน
pom.xmlให้เพิ่มแอป Tinkpaymentmethodtokenเป็นทรัพยากร Dependency ดังนี้<dependencies> <!-- other dependencies ... --> <dependency> <groupId>com.google.crypto.tink</groupId> <artifactId>apps-paymentmethodtoken</artifactId> <version>1.9.1</version> <!-- or latest version --> </dependency> </dependencies>เมื่อเซิร์ฟเวอร์เริ่มต้น ให้ดึงข้อมูลคีย์การลงนามของ Google ล่วงหน้าเพื่อให้คีย์พร้อมใช้งานในหน่วยความจำ ซึ่งจะช่วยป้องกันไม่ให้ผู้ใช้เห็นเวลาในการตอบสนองของเครือข่ายขณะที่กระบวนการ ถอดรหัสกำลังดึงข้อมูลคีย์
GooglePaymentsPublicKeysManager.INSTANCE_PRODUCTION.refreshInBackground();
ถอดรหัสข้อความด้วยโค้ดต่อไปนี้ ซึ่งถือว่า
paymentMethodTokenจัดเก็บไว้ในตัวแปรencryptedMessageและแทนที่ส่วนที่เป็นตัวหนา ตามสถานการณ์ของคุณสำหรับการทดสอบที่ไม่ใช่เวอร์ชันที่ใช้งานจริง ให้แทนที่
INSTANCE_PRODUCTIONด้วยINSTANCE_TESTและหากการผสานรวมไม่ทำงานหรือไม่ได้กำหนดค่าคีย์การเข้ารหัส ไว้ ให้แทนที่ [YOUR MERCHANT ID] ด้วย- ใช้งานอยู่
- เปิดใช้การผสานรวมโดยตรง
- กำหนดค่าคีย์การเข้ารหัสแล้ว
อย่าแทนที่ [YOUR MERCHANT ID]
String decryptedMessage = new PaymentMethodTokenRecipient.Builder() .fetchSenderVerifyingKeysWith( GooglePaymentsPublicKeysManager.INSTANCE_PRODUCTION) .recipientId("merchant:[YOUR MERCHANT ID]") // This guide applies only to protocolVersion = ECv2 .protocolVersion("ECv2") // Multiple private keys can be added to support graceful // key rotations. .addRecipientPrivateKey(PrivateKey1) .addRecipientPrivateKey(PrivateKey2) .build() .unseal(encryptedMessage);
แทนที่
PrivateKey1ด้วยค่าคีย์ส่วนตัวที่เหมาะสมซึ่งเชื่อมโยงกับ ค่าคีย์สาธารณะที่ลงทะเบียนกับ Google จากเตรียมคีย์และลงทะเบียนกับ Google คุณเพิ่มค่าคีย์ส่วนตัวอื่นๆ ได้ในภายหลังเมื่อระบบขอให้คุณหมุนเวียนคีย์กับ Google ตัวแปรอาจเป็นสตริง PKCS8 ที่เข้ารหัส Base64 หรือออบเจ็กต์ECPrivateKeyก็ได้ ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีสร้างคีย์ส่วนตัว PKCS8 ที่เข้ารหัส base64 ได้ที่เตรียมคีย์และลงทะเบียนกับ Googleหากโทรหาเซิร์ฟเวอร์ของ Google ไม่ได้ทุกครั้งที่ถอดรหัสคีย์ ให้ถอดรหัสด้วยโค้ดต่อไปนี้ และแทนที่ส่วนที่เป็นตัวหนาตามสถานการณ์ของคุณ
String decryptedMessage = new PaymentMethodTokenRecipient.Builder() .addSenderVerifyingKey("ECv2 key fetched from test or production url") .recipientId("merchant:[YOUR MERCHANT ID]") // This guide applies only to protocolVersion = ECv2 .protocolVersion("ECv2") // Multiple private keys can be added to support graceful // key rotations. .addRecipientPrivateKey(PrivateKey1) .addRecipientPrivateKey(PrivateKey2) .build() .unseal(encryptedMessage);
คีย์ปัจจุบันในสภาพแวดล้อมการใช้งานจริงจะใช้งานได้จนถึงวันที่ 14/04/2038 ภายใต้สถานการณ์ปกติ ยกเว้นในกรณีที่คีย์ถูกบุกรุก ในกรณีที่คีย์ถูกบุกรุก Google จะแจ้งให้ผู้ขายทุกรายทราบ ผ่านข้อมูลติดต่อที่ระบุไว้ในพอร์ทัลแบบบริการตนเองเพื่อขอให้โหลด
keys.jsonซ้ำเร็วขึ้นข้อมูลโค้ดจะจัดการรายละเอียดด้านความปลอดภัยต่อไปนี้เพื่อให้คุณมุ่งเน้นไปที่การใช้เพย์โหลดได้
- คีย์การลงนามของ Google ที่ดึงและแคชไว้ในหน่วยความจำ
- การยืนยันลายเซ็น
- การถอดรหัส