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 içeren kartlar veya cihaz PAN'ı ve kriptogramlar içeren belirtekleştirilmiş kartlardır.
Yükte, yükün alıcısına hangi şifreleme öğelerinin 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ğı hakkında bilgi verilmekte ve jetonu doğrulayıp şifresini çözmek için yapılması gereken adımlar ayrıntılı olarak 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'ye uygun 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 özetlenmiştir:
- Google kök imzalama anahtarlarını getirin.
- Ara imzalama anahtarının imzasının, geçerlilik 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.
- Ara imzalama anahtarıyla yükün imzasının 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 küçük olduğunu kontrol etmeniz gerekir. - Şifresi çözülmüş içeriklerdeki ödeme yöntemini kullanır ve bu yöntemden ödeme alırız.
Tink kitaplığımızdaki örnek kod, 1-6 arasındaki adımları gerçekleştirir.
Ödeme yöntemi jetonu yapısı
Google'ın PaymentData yanıtında döndürdüğü 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. Bu, protokolün gerekirse zaman içinde gelişmesine olanak tanır. |
signature |
Dize | İletinin Google'dan geldiğini doğrular. Base64 kodlu olan bu sertifika, ara imzalama anahtarı tarafından ECDSA ile 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 değerlerini 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 getirilmiştir. |
Ö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 kodlu ve ECDSA ile oluşturulmuş olmalıdır. |
İ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ımlanmıştır. |
keyExpiration |
Dize | Ara anahtarın geçerliliğinin sona erdiği tarih ve saat (UTC, epoch'tan beri geçen milisaniye cinsinden). Entegrasyon uzmanları, süresi dolmuş 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 ileti. |
ephemeralPublicKey |
Dize | İletiyi sıkıştırılmamış nokta biçiminde şifrelemek için özel anahtarla ilişkilendirilmiş, Base64 kodlu geçici ortak anahtar. 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 kodlu, 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 süresinin dolduğu tarih ve saat (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 tarafından belirlenir ve aşağıdaki tablolarda açıklanı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çerir. |
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şlemi için kullanılan kimlik doğrulama yöntemi. |
PAN_ONLY
Aşağıdaki JSON snippet'i, encryptedMessage için tam bir CARD paymentMethod
örneğidir. 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
3D Secure kriptogramı kullanılarak kimliği doğrulanmış bir CARD,
CRYPTOGRAM_3DS authMethod. Aşağıdaki ek alanları içerir:
| Ad | Tür | Açıklama |
|---|---|---|
cryptogram |
Dize | 3-D 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 aktarılmalıdır. |
Aşağıdaki JSON snippet'i, CRYPTOGRAM_3DS authMethod içeren bir CARD paymentMethod için tam encryptedMessage örneğidir:
{ "paymentMethod": "CARD", "paymentMethodDetails": { "authMethod": "CRYPTOGRAM_3DS", "pan": "1111222233334444", "expirationMonth": 10, "expirationYear": 2025, "cryptogram": "AAAAAA...", "eciIndicator": "eci indicator" }, "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 Hizmeti Sağlayıcı | CRYPTOGRAM_3DS |
02 |
Mastercard | Kartı veren kuruluş | CRYPTOGRAM_3DS |
06 |
Mastercard | Satıcı/Ödeme Hizmeti Sağlayıcı | CRYPTOGRAM_3DS |
05 |
Visa | Kartı veren kuruluş | CRYPTOGRAM_3DS |
07 |
Visa | Satıcı/Ödeme Hizmeti Sağlayıcı | CRYPTOGRAM_3DS |
""(empty) |
Diğer ağlar | Satıcı/Ödeme Hizmeti Sağlayıcı | 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 aşağıdaki parametrelerle birlikte Eliptik Eğri Dijital İmza Algoritması'nı (ECDSA) kullanır: FIPS 186-4'te tanımlandığı gibi karma işlevi olarak SHA-256 ile NIST P-256 üzerinde ECDSA.
İ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'ya bakın. İ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çimine bir örnek 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 aşağıdaki formülle signedStringForIntermediateSigningKeySignature 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 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 imza nasıl doğrulanır?
Ara imzalama anahtarı imzası için imzalı dize oluşturulurken standart ECDSA doğrulama algoritması kullanılır. ECv2 protokolünde, 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ış kabul edilir. intermediateSigningKey.signedKey.keyValue doğrulamak için signedStringForMessageSignature daha sonra kullanın. Google, kendi doğrulama kodunuz yerine mevcut bir şifreleme 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ırmayın veya değiştirmeyin. Ö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ğrulanan intermediateSigningKey.signedKey.keyValue, signedMessage alanını doğrulamak için kullanılır. Google, kendi doğrulama kodunuz yerine mevcut bir şifreleme 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üvenli hale getirmek 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 ile AES-256-CTR ve doldurulmamış. |
| MAC algoritması | HMAC_SHA256 ile anahtar türetme işlevinden türetilen 256 bitlik bir anahtar. |
Şifreleme ortak anahtarı biçimi
Google yüklerinde döndürülen şifreleme ortak anahtarı ve ephemeralPublicKey, sıkıştırılmamış nokta biçimindeki anahtarın 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 iki adet 32 baytlık 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 adlı yayında daha ayrıntılı olarak açıklanmaktadır.
Ortak anahtar oluşturmak için OpenSSL'i kullanma
1. adım: Özel anahtar oluşturun
Aşağıdaki örnekte, NIST P-256 ile kullanıma uygun bir eliptik eğri özel anahtarı oluşturulur ve key.pem konumuna yazılır:
openssl ecparam -name prime256v1 -genkey -noout -out key.pem
İsteğe bağlı: Özel ve ortak anahtarları görüntüleme
Hem özel hem de genel 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 gizli ve ortak 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
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:
- ECIES-KEM kullanan 512 bit uzunluğunda bir paylaşılan anahtar oluşturmak için özel anahtarınızı ve verilen
ephemeralPublicKeydeğerini kullanın. Aşağıdaki parametreleri kullanın: - Eliptik eğri: NIST P-256 (OpenSSL'de prime256v1 olarak da bilinir).
CheckMode,OldCofactorMode,SingleHashModeveCofactorMode0.- 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 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şifresi çözülür:- Sıfır IV.
- Doldurulmamış.
- 2. adımda türetilen
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ı
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 geçerli olduğu sürece geçerlidir. Bu anahtarlar, keyExpiration alanı tarafından belirlenen son kullanma tarihine kadar önbelleğe alınır. Bir 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: Anahtarları çalışma zamanında 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 geçerliliği 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ıştır). Java'da, başvurulan ASN.1
kodlaması X509EncodedKeySpec sınıfı ile gösterilir.
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
Doğrudan entegrasyonla bir ödeme yöntemi jetonunun şifresini doğrudan 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'i kullanı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. 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.
- Ortak şifreleme anahtarı metin giriş alanını seçin ve yeni oluşturduğunuz ortak 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 üretimde 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 publicKey özelliğinde belirtilen anahtarı PaymentMethodTokenizationSpecification parameters nesnesi içinde 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.
- Yapılandırılmış bir şifreleme anahtarı olmalıdır.
[YOUR MERCHANT ID] yerine başka bir mülk oluşturmayı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 kaydetme bölümünde Google'a kaydedilen ortak 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 şifre çözme işlemini yapı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ı self servis portalında sağlanan iletişim bilgilerini kullanarak
keys.json'nın daha hızlı yeniden yüklenmesini istemek için bilgilendirir.Kod snippet'i, aşağıdaki güvenlik ayrıntılarını işler. Böylece, yükün tüketimine odaklanabilirsiniz:
- Google imzalama anahtarları getirilip bellekte önbelleğe alınır.
- İmza doğrulama
- Şifre çözme