Google Pay API, ödeme yöntemlerini imzalı ve şifrelenmiş bir PaymentMethodToken yükte döndürür. Döndürülen ödeme yöntemleri, PAN'dan oluşan kartlar veya cihaz PAN'ı ve kriptogramlardan oluşan jetonlaştırılmış kartlardır.
Yükte, alıcıya hangi kriptografik öğelerin kullanıldığını ve beklenen biçimi bildiren protocolVersion adlı bir alan bulunur.
Bu kılavuzda, Google tarafından imzalanmış ve şifrelenmiş bir ödeme yöntemi jetonu istemek için nasıl genel anahtar oluşturulacağı ve jetonu doğrulayıp şifresini çözmek için hangi adımların izleneceği açıklanmaktadır.
Bu kılavuz yalnızca protocolVersion = ECv2 için geçerlidir.
Ödeme kartı bilgilerini doğrudan aldığınız için devam etmeden önce uygulamanızın PCI DSS uyumlu olduğundan ve sunucularınızın, kullanıcının ödeme kimlik bilgilerini güvenli bir şekilde işlemek için gerekli altyapıya sahip olduğundan emin olun.
Aşağıdaki adımlarda, entegrasyon uzmanının Google Pay API
ECv2 PaymentMethodToken yükünü kullanmak için yapması gerekenler özetlenmektedir:
- Google kök imzalama anahtarlarını getirin.
- Ara imzalama anahtarının imzasının, süresi dolmamış kök imzalama anahtarlarından biriyle geçerli olduğunu doğrulayın.
- Yükün ara imzalama anahtarının süresinin dolmadığını doğrulayın.
- Yükün imzasının, ara imzalama anahtarıyla geçerli olduğunu doğrulayın.
- İmzayı doğruladıktan sonra yükün içeriğinin şifresini çözün.
- Mesajın süresinin dolmadığını doğrulayın. Bunun için geçerli saatin, şifresi çözülmüş içeriklerdeki
messageExpirationalanından daha küçük olduğunu kontrol etmeniz gerekir. - Şifresi çözülmüş içeriklerdeki ödeme yöntemini kullanır ve bu yöntemden ödeme alır.
Tink kitaplığımızdaki örnek kod, 1-6 arasındaki adımları gerçekleştirir.
Ödeme yöntemi jetonu yapısı
Google tarafından PaymentData yanıtında döndürülen mesaj, aşağıdaki tabloda belirtilen anahtarlara sahip, UTF-8 kodlu ve serileştirilmiş bir JSON nesnesidir:
| Ad | Tür | Açıklama |
|---|---|---|
protocolVersion |
Dize | İletinin oluşturulduğu şifreleme veya imzalama şemasını tanımlar. Gerekirse protokolün zaman içinde gelişmesine olanak tanır. |
signature |
Dize | İletinin Google'dan geldiğini doğrular. Base64 olarak kodlanmıştır ve ECDSA ile ara imzalama anahtarı tarafından oluşturulur. |
intermediateSigningKey |
Nesne | Google'ın ara imzalama anahtarını içeren bir JSON nesnesi. keyValue, keyExpiration ve signatures ile signedKey içerir. Ara imzalama anahtarı imzası doğrulama sürecini basitleştirmek için seri hale getirilir. |
signedMessage |
Dize | encryptedMessage, ephemeralPublicKey ve tag öğelerini içeren, HTML'de güvenli bir dize olarak serileştirilmiş bir JSON nesnesi. İmza doğrulama sürecini basitleştirmek için seri hale getirilir. |
Örnek
Aşağıda, JSON biçiminde bir ödeme yöntemi jetonu yanıtı verilmiştir:
{ "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\"}" }
Ara imzalama anahtarı
intermediateSigningKey, aşağıdaki değerleri içeren UTF-8 kodlu, serileştirilmiş bir JSON nesnesidir:
| Ad | Tür | Açıklama |
|---|---|---|
signedKey |
Dize | Anahtarın ödeme açıklamasını içeren, Base64 kodlu bir mesaj. |
signatures |
Dize | Ara imzalama anahtarının Google'dan geldiğini doğrular. Base64 olarak kodlanmış ve ECDSA ile oluşturulmuştur. |
İmzalı anahtar
signedKey, aşağıdaki değerleri içeren UTF-8 kodlu, serileştirilmiş bir JSON nesnesidir:
| Ad | Tür | Açıklama |
|---|---|---|
keyValue |
Dize | ASN.1 türünde kodlanmış anahtarın Base64 sürümü. SubjectPublicKeyInfo, X.509 standardında tanımlanır. |
keyExpiration |
Dize | Ara anahtarın geçerliliğinin sona erdiği tarih ve saat (epoch'tan bu yana geçen UTC milisaniye cinsinden). Entegrasyon uzmanları, süresi dolmuş tüm anahtarları reddeder. |
İmzalı ileti
signedMessage, aşağıdaki değerleri içeren UTF-8 kodlu, serileştirilmiş bir JSON nesnesidir:
| Ad | Tür | Açıklama |
|---|---|---|
encryptedMessage |
Dize | Ödeme bilgilerini ve bazı ek güvenlik alanlarını içeren, base64 ile kodlanmış şifrelenmiş bir mesaj. |
ephemeralPublicKey |
Dize | Base64 kodlu, geçici bir ortak anahtar. Bu anahtar, mesajı sıkıştırılmamış nokta biçiminde şifrelemek için özel anahtarla ilişkilendirilir. Daha fazla bilgi için Şifreleme genel anahtar biçimi başlıklı makaleye bakın. |
tag |
Dize | encryptedMessage öğesinin Base64 kodlu MAC'si. |
Şifrelenmiş mesaj
Şifresi çözülen encryptedMessage, UTF-8 olarak kodlanmış ve serileştirilmiş bir JSON nesnesidir. JSON iki düzey içeriyor. Dış katman, meta verileri ve güvenlik için eklenen alanları içerirken iç katman, gerçek ödeme kimlik bilgisini temsil eden başka bir JSON nesnesidir.
encryptedMessage hakkında daha fazla bilgi için aşağıdaki tablolara ve JSON nesnesi örneklerine bakın:
| Ad | Tür | Açıklama |
|---|---|---|
messageExpiration |
Dize | İletinin geçerliliğinin sona erdiği tarih ve saat (epoch'tan bu yana geçen UTC milisaniye cinsinden). Entegrasyon uzmanları, süresi dolmuş tüm mesajları reddetmelidir. |
messageId |
Dize | İletinin daha sonra iptal edilmesi veya bulunması gerektiğinde iletiyi tanımlayan benzersiz bir kimlik. |
paymentMethod |
Dize | Ödeme kimlik bilgisinin türü.
Şu anda yalnızca CARD desteklenmektedir.
|
paymentMethodDetails |
Nesne | Ödeme kimlik bilgisinin kendisi. Bu nesnenin biçimi paymentMethod ile belirlenir ve aşağıdaki tablolarda açıklanmıştır. |
Kart
CARD ödeme yönteminin ödeme kimlik bilgileri aşağıdaki özelliklerden oluşur:
| Ad | Tür | Açıklama |
|---|---|---|
pan |
Dize | Ücretlendirilen kişisel hesap numarası. Bu dize yalnızca rakam içeriyor. |
expirationMonth |
Sayı | Kartın son kullanma tarihi ayı. 1 değeri Ocak ayını, 2 değeri Şubat ayını vb. temsil eder. |
expirationYear |
Sayı | Kartın dört haneli son kullanma yılı (ör. 2020). |
authMethod |
Dize | Kart işleminin kimlik doğrulama yöntemi. |
merchantTokenId |
Dize | Kart işleminin satıcı jetonu kimliği. Bu isteğe bağlı alan yalnızca aşağıdaki koşulların tümü karşılandığında döndürülür:
|
PAN_ONLY
Aşağıdaki JSON snippet'i, encryptedMessage için tam CARD paymentMethod
PAN_ONLY authMethod örneğidir.
{ "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 3D Secure kriptogramı kullanılarak kimliği doğrulanmış,
CRYPTOGRAM_3DS authMethod. Aşağıdaki ek alanları içerir:
| Ad | Tür | Açıklama |
|---|---|---|
cryptogram |
Dize | 3D Secure kriptogramı. |
eciIndicator |
Dize | Bu dize her zaman mevcut değildir. Yalnızca Android'de kimliği doğrulanmış cihaz jetonu işlemleri (CRYPTOGRAM_3DS) için döndürülür. Bu değer, ödeme işleme akışında iletilmelidir. |
Aşağıdaki JSON snippet'i,
CARD paymentMethod için
CRYPTOGRAM_3DS authMethod içeren tam bir encryptedMessage örneğidir:
{
"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
Kart ağı, kimliği doğrulanmış cihaz jetonu işlemleri (CRYPTOGRAM_3DS) için eciIndicator sağlayabilir.
Yetkilendirme işleminde eciIndicator değerini değiştirilmeden veya sabit kodlanmadan iletmeniz gerekir. Aksi takdirde işlem başarısız olur. Aşağıdaki tabloda eciIndicator değerleri ayrıntılı olarak açıklanmaktadır.
| eciIndicator değeri | Kart Ağı | Sorumlu Taraf | authMethod |
|---|---|---|---|
""(empty) |
Mastercard | Satıcı/Ödeme İşlemcisi | CRYPTOGRAM_3DS |
02 |
Mastercard | Kartı veren kuruluş | CRYPTOGRAM_3DS |
06 |
Mastercard | Satıcı/Ödeme İşlemcisi | CRYPTOGRAM_3DS |
05 |
Visa | Kartı veren kuruluş | CRYPTOGRAM_3DS |
07 |
Visa | Satıcı/Ödeme İşlemcisi | CRYPTOGRAM_3DS |
""(empty) |
Diğer ağlar | Satıcı/Ödeme İşlemcisi | CRYPTOGRAM_3DS |
VISA ve Mastercard için bu tabloda bulunmayan diğer ECI değerleri döndürülmez.
İmza doğrulama
Ara anahtar ve ileti imzaları dahil olmak üzere imzaları doğrulamak için aşağıdaki öğeler gereklidir:
- İmzayı oluşturmak için kullanılan algoritma
- İmzayı oluşturmak için kullanılan bayt dizesi
- İmzayı oluşturmak için kullanılan özel anahtara karşılık gelen ortak anahtar
- İmzanın kendisi
İmza algoritması
Google, iletileri imzalamak için Elliptic Curve Digital Signature Algorithm (ECDSA) kullanır. FIPS 186-4'te tanımlandığı gibi, karma işlevi olarak SHA-256 ile NIST P-256 üzerinden ECDSA parametrelerini kullanır.
İmza
İmza, mesajın en dıştaki düzeyine eklenir. ASN.1 bayt biçiminde base64 ile kodlanır. ASN.1 hakkında daha fazla bilgi için IETF Tools Appendix A başlıklı makaleyi inceleyin. İmza, ECDSA tamsayıları r ve s'den oluşur. Daha fazla bilgi için İmza oluşturma algoritması başlıklı makaleyi inceleyin.
Aşağıda, Java Cryptography Extension (JCE) ECDSA uygulamaları tarafından üretilen standart biçim olan belirtilen ASN.1 bayt biçimi örneği verilmiştir.
ECDSA-Sig-Value :: = SEQUENCE {
r INTEGER,
s INTEGER
}Ara imzalama anahtarı imzası için bayt dizesi oluşturma
Ara imzalama anahtarı imzasını örnek ödeme yöntemi jetonunda doğrulamak için signedStringForIntermediateSigningKeySignature öğesini aşağıdaki formülle oluşturun:
signedStringForIntermediateSigningKeySignature = length_of_sender_id || sender_id || length_of_protocol_version || protocol_version || length_of_signed_key || signed_key
"||" gösterimi, birleştirme anlamına gelir. Her bileşen (sender_id, protocolVersion, signedKey) UTF-8 kodlamalı olmalıdır. signedKey, intermediateSigningKey.signedKey dizesi olmalıdır.
Her bileşenin bayt uzunluğu, little-endian biçiminde 4 bayttır.
Örnek
Bu örnekte aşağıdaki örnek ödeme yöntemi jetonu kullanılmaktadır:
{
"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 her zaman Google, protocol_version ise ECv2 olur.
sender_id değeri Google ise signedString, aşağıdaki örnekte gösterildiği gibi görünür:
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 üzerindeki imzayı doğrulama
Ara imzalama anahtarı imzası için imzalı dize oluşturulurken standart ECDSA doğrulama algoritması kullanılır. ECv2 protokolü için intermediateSigningKey.signatures içindeki tüm imzaları yinelemeniz ve her birini keys.json içindeki süresi dolmamış Google imzalama anahtarlarıyla doğrulamaya çalışmanız gerekir. En az bir imza doğrulaması çalışıyorsa doğrulama tamamlanmış sayılır. intermediateSigningKey.signedKey.keyValue daha sonra signedStringForMessageSignature doğrulamak için kullanın. Google, kendi doğrulama kodunuz yerine mevcut bir kriptografik kitaplığı kullanmanızı önemle tavsiye eder.
İleti imzası için bayt dizesini oluşturma
Örnek ödeme yöntemi jetonundaki imzayı doğrulamak için aşağıdaki formülle signedStringForMessageSignature oluşturun:
signedStringForMessageSignature = length_of_sender_id || sender_id || length_of_recipient_id || recipient_id || length_of_protocolVersion || protocolVersion || length_of_signedMessage || signedMessage
"||" gösterimi, birleştirme anlamına gelir. Her bileşen (sender_id,
recipient_id, protocolVersion, signedMessage) UTF-8 kodlamalı olmalıdır. Her bileşenin bayt uzunluğu, little-endian biçiminde 4 bayttır. Bayt dizesini oluştururken signedMessage ayrıştırılmamalı veya değiştirilmemelidir. Örneğin, \u003d karakterini = karakteriyle değiştirmeyin.
Örnek
Aşağıdaki örnek, örnek bir ödeme yöntemi jetonudur:
{
"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 her zaman Google, recipient_id ise merchant:merchantId olur. merchantId, üretim erişimi olan satıcılar için Google Pay ve Cüzdan Konsolu'nda bulunan değerle eşleşir.
sender_id Google ve recipient_id merchant:12345 ise signedString aşağıdaki örnekte gösterildiği gibi görünür:
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 üzerindeki imzayı doğrulama
İmzalı dize oluşturulurken standart ECDSA doğrulama algoritması kullanılır. Önceki adımda doğrulanmış olan intermediateSigningKey.signedKey.keyValue, signedMessage öğesini doğrulamak için kullanılır. Google, kendi doğrulama kodunuz yerine mevcut bir kriptografik kitaplığı kullanmanızı önemle tavsiye eder.
Şifreleme şeması spesifikasyonu
Google, Google Pay API yanıtında döndürülen ödeme yöntemi jetonunu güvence altına almak için Elips Biçimli Eğri Entegre Şifreleme Şeması'nı (ECIES) kullanır. Şifreleme şeması aşağıdaki parametreleri kullanır:
| Parametre | Tanım |
|---|---|
| Anahtar kapsülleme yöntemi | ISO 18033-2'de tanımlandığı şekilde ECIES-KEM.
|
| Anahtar türetme işlevi | SHA-256 ile HMAC tabanlı (
|
| Simetrik şifreleme algoritması |
ISO 18033-2'de tanımlandığı şekilde DEM2 Şifreleme algoritması: Sıfır IV'li ve doldurulmamış AES-256-CTR. |
| MAC algoritması | Anahtar türetme işlevinden türetilen 256 bit anahtarlı HMAC_SHA256. |
Şifreleme ortak anahtarı biçimi
Google yüklerinde döndürülen şifreleme genel anahtarı ve ephemeralPublicKey, anahtarın sıkıştırılmamış nokta biçimindeki base64 gösterimiyle biçimlendirilir. Aşağıdaki iki öğeden oluşur:
- Biçimi belirten bir sihirli sayı (0x04).
- Eliptik eğrideki X ve Y koordinatlarını temsil eden 32 baytlık iki büyük tam sayı.
Bu biçim, "Public Key Cryptography For The Financial Services Industry: The Elliptic Curve Digital Signature Algorithm (ECDSA)," ANSI X9.62, 1998'de daha ayrıntılı olarak açıklanmaktadır.
Ortak anahtar oluşturmak için OpenSSL'yi kullanma
1. adım: Özel anahtar oluşturun
Aşağıdaki örnek, NIST P-256 ile kullanıma uygun bir eliptik eğri özel anahtarı oluşturur ve bunu key.pem konumuna yazar:
openssl ecparam -name prime256v1 -genkey -noout -out key.pem
İsteğe bağlı: Özel ve ortak anahtarları görüntüleyin.
Hem özel hem de ortak anahtarı görüntülemek için aşağıdaki komutu kullanın:
openssl ec -in key.pem -pubout -text -noout
Komut, aşağıdakine benzer bir çıktı üretir:
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. adım: Base64 kodlu bir ortak anahtar oluşturun
Önceki isteğe bağlı adım örneğinde oluşturulan özel ve herkese açık anahtar, onaltılık olarak kodlanmıştır. Sıkıştırılmamış nokta biçiminde Base64 kodlu bir ortak anahtar almak için aşağıdaki komutu kullanın:
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
Bu komut, içeriği sıkıştırılmamış nokta biçimindeki anahtarın base64 sürümü olan ve aşağıdaki gibi görünen bir publicKey.txt dosyası oluşturur:
BOdoXP+9Aq473SnGwg3JU1aiNpsd9vH2ognq4PtDtlLGa3Kj8TPf+jaQNPyDSkh3JUhiS0KyrrlWhAgNZKHYF2Y=
Dosya içeriğinde fazladan boşluk veya satır başı olmamalıdır. Bunu doğrulamak için Linux veya macOS'te aşağıdaki komutu çalıştırın:
od -bc publicKey.txt
3. adım: PKCS #8 biçiminde base64 kodlu bir özel anahtar oluşturun
Tink kitaplığı, özel anahtarınızın PKCS #8 biçiminde base64 kodlu olmasını bekler. Bu biçimde özel anahtar oluşturmak için ilk adımda oluşturulan özel anahtardan aşağıdaki komutu kullanın:
openssl pkcs8 -topk8 -inform PEM -outform DER -in key.pem -nocrypt | base64 | paste -sd "\0" -
Komut, aşağıdakine benzer bir çıktı üretir:
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgWV4oK8c/MZkCLk4qSCNjW0Zm6H0CBCtSYxkXkC9FBHehRANCAAQPldOnhO2/oXjdJD1dwlFPiNs6fcdoRgFu3/Z0iKj24SjTGyLRGAtYWLGXBZcDdPj3T2bJRHRVhE8Bc2AjkT7n
Ödeme yöntemi jetonunun şifresini çözme
Jetonun şifresini çözmek için aşağıdaki adımları uygulayın:
ephemeralPublicKeydeğerini ve özel anahtarınızı kullanarak ECIES-KEM'i kullanan 512 bit uzunluğunda bir paylaşılan anahtar oluşturun. Aşağıdaki parametreleri kullanın:- Eliptik eğri: NIST P-256 (OpenSSL'de prime256v1 olarak da bilinir).
CheckMode,OldCofactorMode,SingleHashModeveCofactorMode,0.- Kodlama işlevi: Sıkıştırılmamış nokta biçimi.
- Anahtar türetme işlevi: RFC 5869'da açıklandığı gibi HKDFwithSHA256, ve aşağıdaki parametre:
- Tuz sağlanmamalıdır. RFC'ye göre bu, 32 sıfırlanmış baytlık bir tuzla eşdeğer olmalıdır.
- Oluşturulan anahtarı 256 bit uzunluğunda iki anahtara bölün:
symmetricEncryptionKeyvemacKey. tagalanınınencryptedMessageiçin geçerli bir MAC adresi olduğunu doğrulayın.Beklenen MAC'yi oluşturmak için karma işlevi SHA256 ile HMAC'yi (RFC 5869) ve 2. adımda elde edilen
macKeydeğerini kullanın.AES-256-CTR modu ve aşağıdakiler kullanılarak
encryptedMessageöğesinin şifresini çözün:- Sıfır IV.
- Doldurulmamış.
- 2. adımda elde edilen
symmetricEncryptionKey.
Anahtar yönetimi
Satıcı şifreleme anahtarları
Satıcılar, Şifreleme şeması spesifikasyonu'nda belirtilen özelliklere göre ortak anahtar oluşturur.
Google kök imzalama anahtarları
başlıklı makaleyi inceleyin.Google, herkese açık bir URL'den getirilebilen, şu anda geçerli olan kök imzalama ortak anahtarlarının kümesini yayınlar. Anahtarlar, URL tarafından döndürülen HTTP önbellek üst bilgileri süresince geçerlidir. keyExpiration alanı tarafından belirlenen geçerlilik süresi dolana kadar önbelleğe alınır. Getirme işlemi sona erdiğinde geçerli anahtarların güncel listesini almak için anahtarları herkese açık URL'den tekrar getirmenizi öneririz.
ECv2 protokolü için istisna: Çalışma zamanında anahtarları Google'dan getiremiyorsanız keys.json öğesini üretim URL'mizden getirin, sisteminize kaydedin ve düzenli olarak manuel olarak yenileyin. Normal şartlar altında Google, en uzun geçerlilik tarihine sahip anahtarın süresi dolmadan beş yıl önce ECv2 için yeni bir kök imzalama anahtarı yayınlar. Anahtar güvenliğinin ihlal edilmesi durumunda Google, keys.json'nın daha hızlı yeniden yüklenmesini istemek için self servis portalında sağlanan iletişim bilgilerini kullanarak tüm satıcıları bilgilendirir. Düzenli rotasyonu kaçırmamak için Google anahtarlarını keys.json içeriklerine kaydetmeyi tercih eden satıcıların, kendi yıllık anahtar rotasyonlarının bir parçası olarak yıllık yenileme yapmalarını öneririz.
Herkese açık URL üzerinden sağlanan anahtarlar aşağıdaki biçimde eşlenir:
{ "keys": [ { "keyValue": "encoded public key", "protocolVersion": "ECv2" "keyExpiration":"2000000000000" }, { "keyValue": "encoded public key", "protocolVersion": "ECv2" "keyExpiration":"3000000000000" } ] }
keyValue, X.509 standardında tanımlanan ASN.1 türünde SubjectPublicKeyInfo kodlanmış anahtarın base64 sürümüdür (sarmalanmamış veya doldurulmamış). Java'da, başvurulan ASN.1
kodlaması X509EncodedKeySpec sınıfı ile temsil edilir.
ECPublicKey.getEncoded() ile elde edilebilir.
Hem test hem de üretim ortamlarının URL'leri aşağıdaki bağlantılarda verilmiştir:
- Test:
https://payments.developers.google.com/paymentmethodtoken/test/keys.json - Üretim:
https://payments.developers.google.com/paymentmethodtoken/keys.json
Anahtar rotasyonu
Ödeme yöntemi jetonunun şifresini doğrudan entegrasyonla sunucularınızda çözerseniz anahtarları yılda bir kez döndürmeniz gerekir.
Şifreleme anahtarlarını döndürmek için aşağıdaki adımları tamamlayın:
- Yeni bir anahtar çifti oluşturmak için OpenSSL'yi kullanın.
- Google Pay'e geliştirici olarak kaydolmak için daha önce kullandığınız Google Hesabı ile oturum açmışken Google Pay ve Cüzdan Konsolu'nu açın. daha önce uygulamanızı Google Play ile yönetmek için kullanılmış olmalıdır.
- Google Pay API sekmesindeki Doğrudan entegrasyon bölmesinde, mevcut genel anahtarınızın yanındaki Yönet'i tıklayın. Başka bir anahtar ekle'yi tıklayın.
- Genel şifreleme anahtarı metin giriş alanını seçin ve yeni oluşturduğunuz genel anahtarı sıkıştırılmamış nokta biçiminde base64 kodlu olarak ekleyin.
- Şifreleme anahtarlarını kaydet'i tıklayın.
Sorunsuz bir anahtar rotasyonu sağlamak için anahtarları taşırken hem yeni hem de eski özel anahtarların şifre çözme işlemini destekleyin.
Jetonun şifresini çözmek için Tink kitaplığını kullanıyorsanız birden fazla özel anahtarı desteklemek için aşağıdaki Java kodunu kullanın:
String decryptedMessage = new PaymentMethodTokenRecipient.Builder() .addRecipientPrivateKey(newPrivateKey) .addRecipientPrivateKey(oldPrivateKey);
Şifre çözme kodunun üretime dağıtıldığından ve başarılı şifre çözme işlemlerini izlediğinizden emin olun.
Kodunuzda kullanılan ortak anahtarı değiştirin.
PaymentMethodTokenizationSpecificationparametersözelliğindekipublicKeyözelliğinin değerini değiştirin:/** * @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. adımdaki kodu üretime dağıtın. Kod dağıtıldıktan sonra şifreleme ve şifre çözme işlemleri yeni anahtar çiftleri kullanılarak yapılır.
Eski ortak anahtarın artık hiçbir işlemi şifrelemek için kullanılmadığını onaylayın.
- Eski özel anahtarı kaldırın.
- Daha önce Google Pay'e geliştirici olarak kaydolmak için kullandığınız Google Hesabı ile oturum açmışken Google Pay ve Cüzdan Konsolu'nu açın.
- Google Pay API sekmesindeki Doğrudan entegrasyon bölmesinde, mevcut genel anahtarınızın yanındaki Yönet'i tıklayın. Eski ortak anahtarınızın yanındaki Sil'i ve Şifreleme anahtarlarını kaydet'i tıklayın.
Google, aşağıdaki örnekte gösterildiği gibi PaymentMethodTokenizationSpecification parameters nesnesindeki publicKey özelliğinde belirtilen anahtarı kullanır:
{
"protocolVersion": "ECv2",
"publicKey": "BOdoXP+9Aq473SnGwg3JU1..."
}Şifrelenmiş yanıtı yönetmek için Tink kitaplığını kullanın.
İmza doğrulama ve ileti şifre çözme işlemlerini gerçekleştirmek için Tink paymentmethodtoken kitaplığını kullanın. Bu kitaplık yalnızca Java'da kullanılabilir. Bu özelliği kullanmak için aşağıdaki adımları uygulayın:
pom.xmldosyanıza bağımlılık olarak Tinkpaymentmethodtokenuygulamasını ekleyin:<dependencies> <!-- other dependencies ... --> <dependency> <groupId>com.google.crypto.tink</groupId> <artifactId>apps-paymentmethodtoken</artifactId> <version>1.9.1</version> <!-- or latest version --> </dependency> </dependencies>Sunucu başlatılırken, anahtarı bellekte kullanılabilir hale getirmek için Google imzalama anahtarlarını önceden getirin. Bu, şifre çözme işlemi anahtarları getirirken ağ gecikmesinin kullanıcı tarafından görülmesini engeller.
GooglePaymentsPublicKeysManager.INSTANCE_PRODUCTION.refreshInBackground();
paymentMethodTokendeğerininencryptedMessagedeğişkeninde depolandığını varsayan aşağıdaki kodla mesajın şifresini çözün ve kalın harflerle belirtilen bölümleri senaryonuza göre değiştirin.Üretim dışı testler için
INSTANCE_PRODUCTIONyerineINSTANCE_TEST, entegrasyonunuz etkin değilse veya şifreleme anahtarı yapılandırılmamışsa [YOUR MERCHANT ID] yerineyazın.- Etkin
- DIRECT entegrasyonu etkinleştirilmiş olmalıdır.
- Şifreleme anahtarı yapılandırılmış olmalıdır.
[YOUR MERCHANT ID] yerine başka bir öğe koymayın.
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);
PrivateKey1yerine, Anahtarlarınızı hazırlama ve Google'a kaydolma bölümünde Google'a kaydedilen herkese açık anahtar değeriyle ilişkilendirilen uygun özel anahtar değerini girin. Daha sonra, Google ile anahtarları döndürmeniz gerektiğinde başka özel anahtar değerleri ekleyebilirsiniz. Değişkenler, base64 kodlu bir PKCS8 dizesi veya birECPrivateKeynesnesi olabilir. Base64 kodlu PKCS8 özel anahtarı oluşturma hakkında daha fazla bilgi için Anahtarlarınızı hazırlama ve Google'a kaydolma başlıklı makaleyi inceleyin.Anahtarların şifresini her çözdüğünüzde bir Google sunucusunu arayamıyorsanız aşağıdaki kodla şifreyi çözün ve kalın harflerle belirtilen bölümleri senaryonuza göre değiştirin.
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);
Üretim ortamındaki mevcut anahtar, anahtarın güvenliğinin ihlal edilmesi dışında normal koşullarda 14.04.2038'e kadar geçerlidir. Anahtar güvenliğinin ihlal edilmesi durumunda Google, tüm satıcıları
keys.json'nın daha hızlı yeniden yüklenmesini istemek için self servis portalında sağlanan iletişim bilgileri aracılığıyla bilgilendirir.Kod snippet'i, aşağıdaki güvenlik ayrıntılarını işler. Böylece siz de yükün tüketimine odaklanabilirsiniz:
- Google imzalama anahtarları getirilip bellekte önbelleğe alınır.
- İmza doğrulama
- Şifre çözme