Kriptografi data pembayaran untuk penjual

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

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

Panduan ini memberikan informasi tentang cara membuat kunci publik untuk meminta token metode pembayaran yang ditandatangani dan dienkripsi oleh 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 melanjutkan.

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

  1. Ambil kunci penandatanganan root Google.
  2. Pastikan tanda tangan kunci penandatanganan perantara valid oleh salah satu kunci penandatanganan root yang belum habis masa berlakunya.
  3. Pastikan kunci penandatanganan perantara payload belum habis masa berlakunya.
  4. Pastikan tanda tangan payload valid menurut kunci penandatanganan perantara.
  5. Dekripsi konten 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 tagih.

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

Struktur token metode pembayaran

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

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

Kunci bertanda tangan

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

Nama Jenis Deskripsi
keyValue String Versi base64 dari 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 apa pun yang sudah tidak berlaku.

Pesan yang ditandatangani

signedMessage adalah objek JSON yang dienkode UTF-8 dan diserialisasi yang berisi 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 berenkode base64 dari encryptedMessage.

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 mewakili kredensial pembayaran yang 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 yang telah habis masa berlakunya.
messageId String ID unik yang mengidentifikasi pesan jika perlu dicabut 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 dikenai biaya. String ini hanya berisi digit.
expirationMonth Angka Bulan habis masa berlaku kartu, dengan 1 mewakili Januari, 2 mewakili Februari, dan seterusnya.
expirationYear Angka Empat digit tahun habis masa berlaku kartu, misalnya 2020.
authMethod String Metode autentikasi transaksi kartu.
merchantTokenId String

ID token penjual dari transaksi kartu. Kolom opsional ini hanya ditampilkan jika semua kondisi berikut terpenuhi:

  • Penjual menentukan objek *TransactionInfo MIT dalam permintaan.
  • Penjual menyertakan tokenUpdateUrl dalam permintaan.
  • Pengguna memilih instrumen yang ditokenisasi (misalnya, DPAN).

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 yang diautentikasi dengan penggunaan kriptogram 3-D Secure, CRYPTOGRAM_3DS authMethod. Ini mencakup kolom tambahan berikut:

Nama Jenis Deskripsi
cryptogram String Kriptogram 3-D Secure.
eciIndicator String String ini tidak selalu ada. Token ini hanya ditampilkan untuk transaksi token perangkat yang diautentikasi di Android (CRYPTOGRAM_3DS). Nilai ini harus diteruskan ke 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",
    "merchantTokenId": "merchant-token-id",
    
  },
  
  "messageId": "some-message-id",
  "messageExpiration": "1759309000000"
}

eciIndicator

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

Anda harus meneruskan nilai eciIndicator pada transaksi otorisasi tanpa mengubah atau melakukan hardcode; jika tidak, transaksi akan gagal. Tabel berikut menjelaskan nilai eciIndicator.

Nilai eciIndicator Jaringan Kartu Pihak yang Bertanggung Jawab authMethod
""(empty) Mastercard Penjual/Pemroses CRYPTOGRAM_3DS
02 Mastercard Penerbit kartu CRYPTOGRAM_3DS
06 Mastercard Penjual/Pemroses CRYPTOGRAM_3DS
05 Visa Penerbit kartu CRYPTOGRAM_3DS
07 Visa Penjual/Pemroses CRYPTOGRAM_3DS
""(empty) Jaringan lain Penjual/Pemroses 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 kunci perantara dan tanda tangan pesan, item berikut diperlukan:

  • 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 Algoritma Tanda Tangan Digital Kurva Eliptik (ECDSA) untuk menandatangani pesan dengan parameter berikut: ECDSA melalui NIST P-256 dengan SHA-256 sebagai fungsi hash, seperti yang ditentukan dalam FIPS 186-4.

Tanda tangan

Tanda tangan disertakan dalam tingkat terluar pesan. Kunci ini dienkode dengan base64 dalam format byte ASN.1. Untuk informasi selengkapnya tentang ASN.1, lihat Lampiran A Alat IETF. Tanda tangan terdiri dari bilangan bulat r dan s ECDSA. 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 contoh token metode pembayaran, 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 penyambungan. 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 contoh token metode pembayaran 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 yang ditandatangani untuk tanda tangan kunci penandatanganan perantara disusun. 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 ada, bukan kode verifikasi Anda sendiri.

Cara membuat string byte untuk tanda tangan pesan

Untuk memvalidasi tanda tangan dalam contoh token metode pembayaran, 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 penyambungan. Setiap komponen—sender_id, recipient_id, protocolVersion, signedMessage—harus dienkode UTF-8. Panjang byte setiap komponen adalah 4 byte dalam format little-endian. Saat Anda membuat string byte, jangan mengurai atau mengubah signedMessage. Misalnya, jangan ganti \u003d dengan karakter =.

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 disusun. intermediateSigningKey.signedKey.keyValue yang diverifikasi pada langkah sebelumnya digunakan untuk memverifikasi signedMessage. Google sangat menyarankan Anda menggunakan library kriptografi yang 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 API Google Pay. Skema enkripsi menggunakan parameter berikut:

Parameter Definisi
Metode enkapsulasi kunci

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

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

Berbasis HMAC dengan SHA-256 (HKDFwithSHA256).

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

DEM2, sebagaimana ditentukan dalam ISO 18033-2

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

Algoritma MAC HMAC_SHA256 dengan kunci 256-bit seperti yang diperoleh dari fungsi derivasi 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 nomor ajaib yang menentukan format (0x04).
  • Dua bilangan bulat besar 32 byte yang mewakili koordinat X dan Y dalam Kurva Eliptis.

Format ini dijelaskan secara lebih mendetail dalam "Kriptografi Kunci Publik Untuk Industri Jasa Keuangan: Algoritma Tanda Tangan Digital Kurva Eliptik (ECDSA)," ANSI X9.62, 1998.

Menggunakan OpenSSL untuk membuat kunci publik

Langkah 1: Buat kunci pribadi

Contoh berikut menghasilkan kunci pribadi Kurva Eliptik yang cocok untuk digunakan dengan NIST P-256 dan menulisnya 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 dihasilkan 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, yaitu versi base64 dari kunci dalam format titik yang tidak dikompresi, menyerupai berikut ini:

BOdoXP+9Aq473SnGwg3JU1aiNpsd9vH2ognq4PtDtlLGa3Kj8TPf+jaQNPyDSkh3JUhiS0KyrrlWhAgNZKHYF2Y=

Konten file tidak boleh memiliki spasi kosong atau enter 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 pada 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 eliptis: NIST P-256, juga dikenal di OpenSSL sebagai prime256v1.
    • CheckMode, OldCofactorMode, SingleHashMode, dan CofactorMode adalah 0.
    • Fungsi encoding: Format titik yang tidak dikompresi.
    • Fungsi derivasi 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 di-nol-kan.
  2. Pisahkan kunci yang dihasilkan 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 di Langkah 2.

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

    • IV nol.
    • Tidak diisi.
    • symmetricEncryptionKey yang diperoleh di 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 tersebut valid selama header cache HTTP yang ditampilkan oleh URL menunjukkannya. Kunci tersebut di-cache hingga masa berlakunya habis, yang ditentukan oleh kolom keyExpiration. Sebaiknya saat pengambilan 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 muat ulang secara berkala secara manual. Dalam keadaan normal, Google menerbitkan kunci penandatanganan root baru untuk ECv2 lima tahun sebelum kunci dengan tanggal habis masa berlaku terlama berakhir. Jika terjadi penyusupan 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 melakukan pembaruan 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 base64, tidak digabungkan atau diisi, dari kunci yang dienkode dalam jenis SubjectPublicKeyInfo ASN.1 yang ditentukan dalam standar X.509. 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 melalui link berikut:

Rotasi kunci

Jika Anda mendekripsi token metode pembayaran langsung di server Anda dengan integrasi langsung, 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 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 mentransisikan 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 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..."
}

Menggunakan 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 Tink paymentmethodtoken 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 dari 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
    • Mengaktifkan integrasi DIRECT
    • Memiliki kunci enkripsi yang dikonfigurasi

    jangan ganti [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 di Google dari Menyiapkan kunci dan mendaftar ke Google. Anda dapat menambahkan beberapa nilai kunci pribadi lainnya nanti saat diminta untuk 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 berlaku hingga 14/04/2038 dalam keadaan normal, kecuali jika kunci tersebut disusupi. Jika terjadi penyusupan 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