Kriptografi data pembayaran untuk penjual

Google Pay API menampilkan metode pembayaran dalam payload PaymentMethodToken yang ditandatangani dan dienkripsi. Metode pembayaran yang dikembalikan adalah kartu yang terdiri dari PAN, atau kartu yang di-tokenisasi yang terdiri dari PAN perangkat dan kriptogram.

Payload berisi kolom bernama protocolVersion yang memberi tahu penerima payload tentang primitif kriptografi yang digunakan dan format yang diharapkan.

Panduan ini memberikan informasi tentang cara membuat kunci publik untuk meminta token metode pembayaran terenkripsi dan bertanda tangan Google, serta menjelaskan langkah-langkah yang harus dilakukan untuk memverifikasi dan mendekripsi token.

Panduan ini hanya berlaku untuk protocolVersion = ECv2.

Karena Anda menerima informasi kartu pembayaran secara langsung, pastikan aplikasi Anda mematuhi PCI DSS dan server Anda memiliki infrastruktur yang diperlukan untuk menangani kredensial pembayaran pengguna dengan aman sebelum Anda melanjutkan.

Langkah-langkah berikut menguraikan tindakan yang harus dilakukan integrator untuk menggunakan payload ECv2 PaymentMethodToken Google Pay API:

  1. Ambil kunci penandatanganan root Google.
  2. Verifikasi bahwa tanda tangan kunci penandatanganan perantara valid dengan salah satu kunci penandatanganan root yang belum habis masa berlakunya.
  3. Pastikan masa berlaku kunci penandatanganan perantara payload belum berakhir.
  4. Pastikan tanda tangan payload valid dengan kunci penandatanganan perantara.
  5. Dekripsi isi payload setelah Anda memverifikasi tanda tangan.
  6. Pastikan masa berlaku pesan belum berakhir. Hal ini mengharuskan Anda memeriksa bahwa waktu saat ini kurang dari kolom messageExpiration dalam konten yang didekripsi.
  7. Gunakan metode pembayaran dalam konten yang didekripsi dan kenakan biaya.

Kode contoh di library Tink kami melakukan langkah 1–6.

Struktur token metode pembayaran

Pesan yang ditampilkan oleh Google dalam respons PaymentData adalah objek JSON berserial yang dienkode UTF-8, dengan kunci yang ditentukan dalam tabel berikut:

Nama Jenis Deskripsi
protocolVersion String Mengidentifikasi skema penandatanganan atau enkripsi yang digunakan untuk membuat pesan. Hal ini memungkinkan protokol berkembang seiring waktu, jika diperlukan.
signature String Memverifikasi bahwa pesan berasal dari Google. Tanda tangan ini dienkode base64, dan dibuat dengan ECDSA oleh kunci penandatanganan perantara.
intermediateSigningKey Objek Objek JSON yang berisi kunci penandatanganan perantara dari Google. Berisi signedKey dengan keyValue, keyExpiration, dan signatures. Objek ini diserialisasi untuk menyederhanakan proses verifikasi tanda tangan kunci penandatanganan perantara.
signedMessage String Objek JSON yang diserialisasi sebagai string aman untuk HTML yang berisi encryptedMessage, ephemeralPublicKey, dan tag. Objek ini diserialisasi untuk menyederhanakan proses verifikasi tanda tangan.

Contoh

Berikut adalah respons token metode pembayaran dalam 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\"}"
}

Kunci penandatanganan perantara

intermediateSigningKey adalah objek JSON serial yang dienkode UTF-8 yang berisi nilai berikut:

Nama Jenis Deskripsi
signedKey String Pesan berenkode base64 yang berisi deskripsi pembayaran kunci.
signatures String Memverifikasi bahwa kunci penandatanganan perantara berasal dari Google. Di-encode base64, dan dibuat dengan ECDSA.

Kunci yang ditandatangani

signedKey adalah objek JSON yang diserialisasi dan dienkode UTF-8 yang berisi nilai-nilai berikut:

Nama Jenis Deskripsi
keyValue String Versi base64 kunci yang dienkode dalam jenis ASN.1. SubjectPublicKeyInfo ditentukan dalam standar X.509.
keyExpiration String Tanggal dan waktu saat kunci perantara berakhir sebagai milidetik UTC sejak epoch. Integrator menolak kunci yang sudah habis masa berlakunya.

Pesan bertanda tangan

signedMessage adalah objek JSON yang diserialisasi dan dienkode UTF-8 yang berisi nilai-nilai berikut:

Nama Jenis Deskripsi
encryptedMessage String Pesan terenkripsi berenkode base64 yang berisi informasi pembayaran dan beberapa kolom keamanan tambahan.
ephemeralPublicKey String Kunci publik sementara berenkode base64 yang terkait dengan kunci pribadi untuk mengenkripsi pesan dalam format titik yang tidak dikompresi. Untuk mengetahui informasi selengkapnya, lihat Format kunci publik enkripsi.
tag String MAC encryptedMessage berenkode base64.

Pesan terenkripsi

encryptedMessage yang didekripsi adalah objek JSON yang diserialisasi dan dienkode UTF-8. JSON berisi dua tingkat. Tingkat luar berisi metadata dan kolom yang disertakan untuk keamanan, sedangkan tingkat dalam adalah objek JSON lain yang merepresentasikan kredensial pembayaran sebenarnya.

Untuk mengetahui detail selengkapnya tentang encryptedMessage, lihat tabel dan contoh objek JSON berikut:

Nama Jenis Deskripsi
messageExpiration String Tanggal dan waktu saat pesan berakhir sebagai milidetik UTC sejak epoch. Integrator harus menolak pesan apa pun yang telah habis masa berlakunya.
messageId String ID unik yang mengidentifikasi pesan jika perlu dibatalkan atau ditemukan di lain waktu.
paymentMethod String Jenis kredensial pembayaran. Saat ini, hanya CARD yang didukung.
paymentMethodDetails Objek Kredensial pembayaran itu sendiri. Format objek ini ditentukan oleh paymentMethod dan dijelaskan dalam tabel berikut.

Kartu

Properti berikut membentuk kredensial pembayaran untuk metode pembayaran CARD:

Nama Jenis Deskripsi
pan String Nomor rekening pribadi yang ditagih. String ini hanya berisi digit.
expirationMonth Angka Bulan habis masa berlaku kartu, dengan 1 mewakili Januari, 2 mewakili Februari, dan seterusnya.
expirationYear Angka Tahun habis masa berlaku kartu empat digit, seperti 2020.
authMethod String Metode autentikasi transaksi kartu.

PAN_ONLY

Cuplikan JSON berikut adalah contoh encryptedMessage lengkap untuk CARD paymentMethod dengan 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 diautentikasi dengan penggunaan kriptogram 3-D Secure, CRYPTOGRAM_3DS authMethod. Kolom ini mencakup kolom tambahan berikut:

Nama Jenis Deskripsi
cryptogram String Kriptogram 3-D Secure.
eciIndicator String String ini tidak selalu ada. Respons ini hanya ditampilkan untuk transaksi token perangkat yang diautentikasi di Android (CRYPTOGRAM_3DS). Nilai ini harus diteruskan dalam alur pemrosesan pembayaran.

Cuplikan JSON berikut adalah contoh encryptedMessage lengkap untuk CARD paymentMethod dengan 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

Jaringan kartu dapat memberikan eciIndicator untuk transaksi token perangkat yang diautentikasi (CRYPTOGRAM_3DS).

Anda harus meneruskan nilai eciIndicator pada transaksi otorisasi tanpa diubah atau dikodekan secara permanen; jika tidak, transaksi akan gagal. Tabel berikut menjelaskan nilai eciIndicator.

Nilai eciIndicator Jaringan Kartu Pihak yang Bertanggung Jawab authMethod
""(empty) Mastercard Penjual/Acquirer CRYPTOGRAM_3DS
02 Mastercard Penerbit kartu CRYPTOGRAM_3DS
06 Mastercard Penjual/Acquirer CRYPTOGRAM_3DS
05 Visa Penerbit kartu CRYPTOGRAM_3DS
07 Visa Penjual/Acquirer CRYPTOGRAM_3DS
""(empty) Jaringan lain Penjual/Acquirer CRYPTOGRAM_3DS

Nilai ECI lainnya untuk VISA dan Mastercard yang tidak ada dalam tabel ini tidak akan ditampilkan.

Verifikasi tanda tangan

Untuk memverifikasi tanda tangan, yang mencakup tanda tangan pesan dan kunci perantara, diperlukan item berikut:

  • Algoritma yang digunakan untuk membuat tanda tangan
  • String byte yang digunakan untuk membuat tanda tangan
  • Kunci publik yang sesuai dengan kunci pribadi yang digunakan untuk membuat tanda tangan
  • Tanda tangan itu sendiri

Algoritma tanda tangan

Google menggunakan Elliptic Curve Digital Signature Algorithm (ECDSA) untuk menandatangani pesan dengan parameter berikut: ECDSA melalui NIST P-256 dengan SHA-256 sebagai fungsi hash, sebagaimana ditentukan dalam FIPS 186-4.

Tanda tangan

Tanda tangan disertakan dalam tingkat terluar pesan. Dienkode dengan base64 dalam format byte ASN.1. Untuk mengetahui informasi selengkapnya tentang ASN.1, lihat Lampiran A Alat IETF. Tanda tangan terdiri dari bilangan bulat ECDSA r dan s. Untuk mengetahui informasi selengkapnya, lihat Algoritma pembuatan tanda tangan.

Berikut adalah contoh format byte ASN.1 yang ditentukan, yang merupakan format standar yang dihasilkan oleh implementasi ECDSA Java Cryptography Extension (JCE).

ECDSA-Sig-Value :: = SEQUENCE {
 r INTEGER,
 s INTEGER
}

Cara membuat string byte untuk tanda tangan kunci penandatanganan perantara

Untuk memvalidasi tanda tangan kunci penandatanganan perantara dalam token metode pembayaran contoh, buat signedStringForIntermediateSigningKeySignature dengan formula berikut:

signedStringForIntermediateSigningKeySignature =
length_of_sender_id || sender_id || length_of_protocol_version || protocol_version || length_of_signed_key || signed_key

Notasi "||" berarti gabungkan. Setiap komponen—sender_id, protocolVersion, signedKey—harus dienkode UTF-8. signedKey harus berupa string intermediateSigningKey.signedKey. Panjang byte setiap komponen adalah 4 byte dalam format little-endian.

Contoh

Contoh ini menggunakan token metode pembayaran contoh berikut:

{
  "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 selalu Google dan protocol_version adalah ECv2.

Jika sender_id adalah Google, signedString akan muncul seperti yang ditunjukkan dalam contoh berikut:

signedStringForIntermediateSigningKeySignature =
\x06\x00\x00\x00 || Google || | \x04\x00\x00\x00 || ECv2 || \xb5\x00\x00\x00 || {"keyExpiration":"1542323393147","keyValue":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/1+3HBVSbdv+j7NaArdgMyoSAM43yRydzqdg1TxodSzA96Dj4Mc1EiKroxxunavVIvdxGnJeFViTzFvzFRxyCw\u003d\u003d"}

Cara memverifikasi tanda tangan di signedStringForIntermediateSigningKeySignature

Algoritma verifikasi ECDSA standar digunakan saat string bertanda tangan untuk tanda tangan kunci penandatanganan perantara dirakit. Untuk protokol ECv2, Anda perlu melakukan iterasi pada semua tanda tangan di intermediateSigningKey.signatures dan mencoba memvalidasi setiap tanda tangan dengan kunci penandatanganan Google yang belum habis masa berlakunya di keys.json. Jika setidaknya satu validasi tanda tangan berhasil, anggap verifikasi selesai. Gunakan intermediateSigningKey.signedKey.keyValue nanti untuk memverifikasi signedStringForMessageSignature. Google sangat menyarankan Anda menggunakan library kriptografi yang sudah ada, bukan kode verifikasi Anda sendiri.

Cara membuat string byte untuk tanda tangan pesan

Untuk memvalidasi tanda tangan di token metode pembayaran contoh, buat signedStringForMessageSignature dengan formula berikut:

signedStringForMessageSignature =
length_of_sender_id || sender_id || length_of_recipient_id || recipient_id || length_of_protocolVersion || protocolVersion || length_of_signedMessage || signedMessage

Notasi "||" berarti gabungkan. Setiap komponen—sender_id, recipient_id, protocolVersion, signedMessage—harus dienkode UTF-8. Panjang byte setiap komponen adalah 4 byte dalam format little-endian. Saat membuat string byte, jangan mengurai atau mengubah signedMessage. Misalnya, jangan mengganti \u003d dengan karakter =.

Contoh

Contoh berikut adalah contoh token metode pembayaran:

{
  "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 selalu Google dan recipient_id adalah merchant:merchantId. merchantId cocok dengan nilai yang ditemukan di Konsol Google Pay & Wallet untuk penjual dengan akses produksi.

Jika sender_id adalah Google dan recipient_id adalah merchant:12345, signedString akan muncul seperti dalam contoh berikut:

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"}

Cara memverifikasi tanda tangan di signedStringForMessageSignature

Algoritma verifikasi ECDSA standar digunakan saat string yang ditandatangani dirakit. intermediateSigningKey.signedKey.keyValue yang diverifikasi di langkah sebelumnya digunakan untuk memverifikasi signedMessage. Google sangat menyarankan Anda menggunakan library kriptografi yang sudah ada, bukan kode verifikasi Anda sendiri.

Spesifikasi skema enkripsi

Google menggunakan Elliptic Curve Integrated Encryption Scheme (ECIES) untuk mengamankan token metode pembayaran yang ditampilkan dalam respons Google Pay API. Skema enkripsi menggunakan parameter berikut:

Parameter Definisi
Metode enkapsulasi kunci

ECIES-KEM, sebagaimana ditentukan dalam ISO 18033-2.

  • Kurva elips: NIST P-256 (juga dikenal di OpenSSL sebagai prime256v1).
  • CheckMode, OldCofactorMode, SingleHashMode, dan CofactorMode adalah 0.
  • Format titik tidak dikompresi.
Fungsi turunan kunci

Berbasis HMAC dengan SHA-256 (HKDFwithSHA256).

  • Salt tidak boleh diberikan.
  • Informasi harus dienkode Google dalam ASCII untuk versi protokol ECv2.
  • 256 bit harus diturunkan untuk kunci AES256 dan 256 bit lainnya harus diturunkan untuk kunci HMAC_SHA256.
Algoritma enkripsi simetris

DEM2, sebagaimana ditentukan dalam ISO 18033-2

Algoritma enkripsi: AES-256-CTR dengan IV nol dan tidak di-padding.

Algoritma MAC HMAC_SHA256 dengan kunci 256-bit yang berasal dari fungsi turunan kunci.

Format kunci publik enkripsi

Kunci publik enkripsi dan ephemeralPublicKey yang ditampilkan dalam payload Google diformat dengan representasi base64 dari kunci dalam format titik yang tidak dikompresi. Terdiri dari dua elemen berikut:

  • Satu angka ajaib yang menentukan format (0x04).
  • Dua bilangan bulat besar 32 byte yang merepresentasikan koordinat X dan Y dalam Kurva Elips.

Format ini dijelaskan lebih mendetail dalam "Public Key Cryptography For The Financial Services Industry: The Elliptic Curve Digital Signature Algorithm (ECDSA)," ANSI X9.62, 1998.

Menggunakan OpenSSL untuk membuat kunci publik

Langkah 1: Buat kunci pribadi

Contoh berikut menghasilkan kunci pribadi Kurva Elips yang cocok untuk digunakan dengan NIST P-256 dan menuliskannya ke key.pem:

openssl ecparam -name prime256v1 -genkey -noout -out key.pem

Opsional: Melihat kunci pribadi dan publik

Gunakan perintah berikut untuk melihat kunci pribadi dan publik:

openssl ec -in key.pem -pubout -text -noout

Perintah ini menghasilkan output yang mirip dengan berikut ini:

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

Langkah 2: Buat kunci publik berenkode base64

Kunci pribadi dan publik yang dibuat dalam contoh langkah opsional sebelumnya dienkode dalam format heksadesimal. Untuk mendapatkan kunci publik berenkode base64 dalam format titik yang tidak dikompresi, gunakan perintah berikut:

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

Perintah ini menghasilkan file publicKey.txt yang kontennya, versi base64 dari kunci dalam format titik yang tidak dikompresi, menyerupai berikut ini:

BOdoXP+9Aq473SnGwg3JU1aiNpsd9vH2ognq4PtDtlLGa3Kj8TPf+jaQNPyDSkh3JUhiS0KyrrlWhAgNZKHYF2Y=

Konten file tidak boleh memiliki spasi kosong atau carriage return tambahan. Untuk memverifikasi hal ini, jalankan perintah berikut di Linux atau MacOS:

od -bc publicKey.txt

Langkah 3: Buat kunci pribadi berenkode base64 dalam format PKCS #8

Library Tink mengharapkan kunci pribadi Anda dienkode base64 dalam format PKCS #8. Gunakan perintah berikut untuk membuat kunci pribadi dalam format ini dari kunci pribadi yang dibuat di langkah pertama:

openssl pkcs8 -topk8 -inform PEM -outform DER -in key.pem -nocrypt | base64 | paste -sd "\0" -

Perintah ini menghasilkan output yang mirip dengan berikut ini:

MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgWV4oK8c/MZkCLk4qSCNjW0Zm6H0CBCtSYxkXkC9FBHehRANCAAQPldOnhO2/oXjdJD1dwlFPiNs6fcdoRgFu3/Z0iKj24SjTGyLRGAtYWLGXBZcDdPj3T2bJRHRVhE8Bc2AjkT7n

Cara mendekripsi token metode pembayaran

Ikuti langkah-langkah berikut untuk mendekripsi token:

  1. Gunakan kunci pribadi Anda dan ephemeralPublicKey yang diberikan untuk mendapatkan kunci bersama sepanjang 512 bit yang menggunakan ECIES-KEM. Gunakan parameter berikut:
    • Kurva elips: NIST P-256, juga dikenal di OpenSSL sebagai prime256v1.
    • CheckMode, OldCofactorMode, SingleHashMode, dan CofactorMode adalah 0.
    • Fungsi encoding: Format titik yang tidak dikompresi.
    • Fungsi turunan kunci: HKDFwithSHA256, seperti yang dijelaskan dalam RFC 5869, dengan parameter berikut:
      • Salt tidak boleh diberikan. Sesuai dengan RFC, ini harus setara dengan salt 32 byte yang diisi nol.
  2. Pisahkan kunci yang dibuat menjadi dua kunci sepanjang 256 bit: symmetricEncryptionKey dan macKey.
  3. Pastikan kolom tag adalah MAC yang valid untuk encryptedMessage.

    Untuk membuat MAC yang diharapkan, gunakan HMAC (RFC 5869) dengan fungsi hash SHA256 dan macKey yang diperoleh pada Langkah 2.

  4. Dekripsi encryptedMessage dengan menggunakan mode AES-256-CTR, dan dengan berikut ini:

    • IV nol.
    • Tidak diberi padding.
    • symmetricEncryptionKey yang diperoleh pada Langkah 2.

Pengelolaan kunci

Kunci enkripsi penjual

Penjual membuat kunci publik sesuai dengan spesifikasi yang diuraikan dalam Spesifikasi skema enkripsi.

Kunci penandatanganan root Google

Google memublikasikan kumpulan kunci publik penandatanganan root yang saat ini valid dan dapat diambil dari URL publik. Kunci valid selama header cache HTTP yang ditampilkan oleh URL menunjukkan. Data di-cache hingga masa berlakunya berakhir, yang ditentukan oleh kolom keyExpiration. Sebaiknya saat pengambilan data berakhir, ambil kunci dari URL publik lagi untuk menerima daftar kunci valid saat ini.

Pengecualian untuk protokol ECv2: Jika Anda tidak dapat mengambil kunci dari Google saat runtime, ambil keys.json dari URL produksi kami, simpan ke sistem Anda, dan perbarui secara berkala secara manual. Dalam keadaan normal, Google menerbitkan kunci penandatanganan root baru untuk ECv2 lima tahun sebelum kunci dengan tanggal habis masa berlaku terpanjang berakhir. Jika terjadi kebocoran kunci, Google akan memberi tahu semua penjual melalui informasi kontak yang diberikan di portal layanan mandiri untuk meminta pemuatan ulang keys.json yang lebih cepat. Untuk memastikan Anda tidak melewatkan rotasi reguler, sebaiknya penjual yang memilih untuk menyimpan kunci Google dalam konten keys.json memperbarui kunci setiap tahun sebagai bagian dari rotasi kunci tahunan mereka sendiri.

Kunci yang disediakan melalui URL publik dipetakan dalam format berikut:

{
  "keys": [
    {
      "keyValue": "encoded public key",
      "protocolVersion": "ECv2"
      "keyExpiration":"2000000000000"
    },
    {
      "keyValue": "encoded public key",
      "protocolVersion": "ECv2"
      "keyExpiration":"3000000000000"
    }
  ]
}

keyValue adalah versi kunci yang dienkode dalam jenis ASN.1 SubjectPublicKeyInfo yang ditentukan dalam standar X.509, bukan base64 yang di-wrap atau di-pad. Di Java, encoding ASN.1 yang dirujuk diwakili oleh class X509EncodedKeySpec. Token ini dapat diperoleh dengan ECPublicKey.getEncoded().

URL untuk lingkungan pengujian dan produksi disediakan oleh link berikut:

Rotasi kunci

Jika Anda mendekripsi token metode pembayaran secara langsung di server Anda dengan integrasi langsung, maka Anda harus merotasi kunci setiap tahun.

Selesaikan langkah-langkah berikut untuk merotasi kunci enkripsi:

  1. Gunakan OpenSSL untuk membuat pasangan kunci baru.
  2. Buka Konsol Google Pay & Wallet saat login dengan Akun Google yang sebelumnya Anda gunakan untuk mendaftar sebagai developer Google Pay.
  3. Di tab Google Pay API, di bagian panel Integrasi langsung, klik Kelola di samping kunci publik yang ada. Klik Tambahkan kunci lain.
  4. Pilih kolom input teks Public encryption key dan tambahkan kunci publik yang baru dibuat yang dienkode base64 dalam format titik yang tidak dikompresi.
  5. Klik Simpan kunci enkripsi.
  6. Untuk memastikan rotasi kunci yang lancar, dukung dekripsi kunci pribadi baru dan lama saat Anda melakukan transisi kunci.

    Jika Anda menggunakan library Tink untuk mendekripsi token, gunakan kode Java berikut untuk mendukung beberapa kunci pribadi:

    String decryptedMessage =
        new PaymentMethodTokenRecipient.Builder()
            .addRecipientPrivateKey(newPrivateKey)
            .addRecipientPrivateKey(oldPrivateKey);

    Pastikan kode untuk dekripsi di-deploy ke produksi dan Anda memantau dekripsi yang berhasil.

  7. Ubah kunci publik yang digunakan dalam kode Anda.

    Ganti nilai atribut publicKey di properti PaymentMethodTokenizationSpecification parameters:

    const tokenizationSpecification = {
      "type": "DIRECT",
      "parameters": {
        "protocolVersion": "ECv2",
        "publicKey": "BOdoXP1aiNp.....kh3JUhiSZKHYF2Y="
      }
    }
  8. Deploy kode dari langkah 4 ke produksi. Setelah kode di-deploy, transaksi enkripsi dan dekripsi akan menggunakan pasangan kunci baru.
  9. Pastikan kunci publik lama tidak lagi digunakan untuk mengenkripsi transaksi apa pun.

  10. Hapus kunci pribadi lama.
  11. Buka Konsol Google Pay & Wallet saat login dengan Akun Google yang sebelumnya Anda gunakan untuk mendaftar sebagai developer dengan Google Pay.
  12. Di tab Google Pay API, di bagian panel Integrasi langsung, klik Kelola di samping kunci publik yang ada. Klik Hapus di samping kunci publik lama Anda, lalu klik Simpan kunci enkripsi.

Google menggunakan kunci yang ditentukan dalam properti publicKey dalam objek PaymentMethodTokenizationSpecification parameters, seperti yang ditunjukkan dalam contoh berikut:

{
  "protocolVersion": "ECv2",
  "publicKey": "BOdoXP+9Aq473SnGwg3JU1..."
}

Gunakan library Tink untuk mengelola respons terenkripsi

Untuk melakukan verifikasi tanda tangan dan dekripsi pesan, gunakan library paymentmethodtoken Tink. Library ini hanya tersedia di Java. Untuk menggunakannya, selesaikan langkah-langkah berikut:

  1. Di pom.xml, tambahkan aplikasi paymentmethodtoken Tink sebagai dependensi:

    <dependencies>
      <!-- other dependencies ... -->
      <dependency>
        <groupId>com.google.crypto.tink</groupId>
        <artifactId>apps-paymentmethodtoken</artifactId>
        <version>1.9.1</version>  <!-- or latest version -->
      </dependency>
    </dependencies>
  2. Saat server dimulai, ambil kunci penandatanganan Google terlebih dahulu agar kunci tersedia di memori. Hal ini mencegah tampilan pengguna tentang latensi jaringan apa pun saat proses dekripsi mengambil kunci.

    GooglePaymentsPublicKeysManager.INSTANCE_PRODUCTION.refreshInBackground();
  3. Dekripsi pesan dengan kode berikut, yang mengasumsikan paymentMethodToken disimpan dalam variabel encryptedMessage, dan ganti bagian yang dicetak tebal sesuai dengan skenario Anda.

    Untuk pengujian non-produksi, ganti INSTANCE_PRODUCTION dengan INSTANCE_TEST, dan jika integrasi Anda tidak aktif atau tidak memiliki kunci enkripsi yang dikonfigurasi, ganti [YOUR MERCHANT ID] dengan 12345678901234567890.

    • Aktif
    • Telah mengaktifkan integrasi LANGSUNG
    • Telah mengonfigurasi kunci enkripsi

    jangan mengganti [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);
  4. Ganti PrivateKey1 dengan nilai kunci pribadi yang sesuai yang terkait dengan nilai kunci publik yang terdaftar dengan Google dari Siapkan kunci Anda dan daftarkan ke Google. Anda dapat menambahkan beberapa nilai kunci pribadi lainnya nanti saat Anda perlu Merotasi kunci dengan Google. Variabel dapat berupa string PKCS8 berenkode base64 atau objek ECPrivateKey. Untuk mengetahui informasi selengkapnya tentang cara membuat kunci pribadi PKCS8 berenkode base64, lihat Menyiapkan kunci dan mendaftar ke Google.

  5. Jika Anda tidak dapat memanggil server Google setiap kali mendekripsi kunci, dekripsi dengan kode berikut dan ganti bagian yang dicetak tebal sesuai dengan skenario Anda.

    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);

    Kunci saat ini di lingkungan produksi valid hingga 14/04/2038 dalam keadaan normal, kecuali jika terjadi kompromi kunci. Jika terjadi kebocoran kunci, Google akan memberi tahu semua penjual melalui informasi kontak yang diberikan di portal layanan mandiri untuk meminta pemuatan ulang keys.json yang lebih cepat.

    Cuplikan kode menangani detail keamanan berikut sehingga Anda dapat berfokus pada penggunaan payload:

    • Kunci penandatanganan Google diambil dan di-cache dalam memori
    • Verifikasi tanda tangan
    • Dekripsi