Google Pay API, ödeme yöntemlerini imzalı ve şifrelenmiş bir PaymentMethodToken yükü içinde döndürür. Döndürülen ödeme yöntemleri, PAN'den oluşan kartlar veya cihaz PAN'si ve kriptogramlardan oluşan token'laştırılmış kartlardır.
Yük, yükün alıcısına hangi kriptografik temel öğelerin kullanıldığını ve beklenen biçimi bildiren protocolVersion adlı bir alan içerir.
Bu kılavuzda, Google tarafından imzalanmış ve şifrelenmiş bir ödeme yöntemi jetonu istemek için ortak anahtarın nasıl oluşturulacağı hakkında bilgi verilmekte ve jetonu doğrulamak ve ş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 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, bir entegratörün Google Pay API ECv2 PaymentMethodToken yükünü kullanmak için yapması gerekenler açıklanmaktadır:
- Google kök imzalama anahtarlarını alın.
- Ara imzalama anahtarının imzasının, süresi dolmamış kök imzalama anahtarlarından herhangi biri tarafından 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ı tarafından 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. Bu, geçerli zamanın şifresi çözülmüş içeriklerdeki
messageExpirationalanından daha az olduğunu kontrol etmenizi gerektirir. - Şifresi çözülen içeriklerdeki ödeme yöntemini kullanın ve ödemeyi alın.
Tink kitaplığımızdaki örnek kod, 1-6 arasındaki adımları uygular.
Ödeme yöntemi jeton yapısı
Google tarafından PaymentData yanıtında döndürülen mesaj, aşağıdaki tabloda belirtilen anahtarları içeren, UTF-8 kodlu, 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 zaman içinde gelişmesine olanak tanır. |
signature |
Dize | İletinin Google'dan geldiğini doğrular. Base64 olarak kodlanmıştır ve ara imzalama anahtarı tarafından ECDSA ile oluşturulmuştur. |
intermediateSigningKey |
Nesne | Google'dan gelen ara imzalama anahtarını içeren bir JSON nesnesi. keyValue, keyExpiration ve signatures ile signedKey içerir. Ara imzalama anahtarı imza doğrulama sürecini basitleştirmek için serileştirilir. |
signedMessage |
Dize | encryptedMessage, ephemeralPublicKey ve tag içeren, HTML için güvenli bir dize olarak serileştirilmiş JSON nesnesi. İmza doğrulama sürecini basitleştirmek için serileştirilir. |
Ö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ıştır 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ımlanmıştır. |
keyExpiration |
Dize | Ara anahtarın süresinin dolduğu tarih ve saat (epoch'tan bu yana geçen UTC milisaniye cinsinden). Entegratörler, süresi dolmuş anahtarları reddeder. |
İmzalı mesaj
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ış şifreli mesaj. |
ephemeralPublicKey |
Dize | Mesajı sıkıştırılmamış nokta biçiminde şifrelemek için özel anahtarla ilişkili, base64 kodlu geçici bir ortak anahtar. Daha fazla bilgi için Şifreleme ortak anahtar biçimi başlıklı makaleyi inceleyin. |
tag |
Dize | encryptedMessage değerinin base64 kodlu MAC'i. |
Şifrelenmiş mesaj
Şifresi çözülen encryptedMessage, UTF-8 olarak kodlanmış, serileştirilmiş bir JSON nesnesidir. JSON iki düzey içerir. Dış düzey, güvenlik için eklenen meta verileri ve alanları içerirken iç düzey, gerçek ödeme kimlik bilgilerini 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 | Mesajın süresinin dolduğu tarih ve saat (sıfır zamandan itibaren UTC milisaniye cinsinden). Entegratörler, süresi dolmuş tüm mesajları reddetmelidir. |
messageId |
Dize | İptal edilmesi veya daha sonra bulunması gerektiğinde mesajı 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
Aşağıdaki özellikler, CARD ödeme yönteminin ödeme kimlik bilgilerini oluşturur:
| 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 ayı. 1 Ocak'ı, 2 Şubat'ı 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ı jeton 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, PAN_ONLY authMethod içeren bir CARD paymentMethod için tam encryptedMessage ö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
3-D 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'deki kimliği doğrulanmış cihaz jetonu işlemleri (CRYPTOGRAM_3DS) için döndürülür. Bu değer, ödeme işleme akışına iletilmelidir. |
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",
"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ştirmeden veya sabit kodlamadan iletmeniz gerekir. Aksi takdirde işlem başarısız olur. Aşağıdaki tabloda eciIndicator değerleri ayrıntılı olarak açıklanmıştır.
| eciIndicator değeri | Kart ağı | Sorumlu Taraf | authMethod |
|---|---|---|---|
""(empty) |
Mastercard | Satıcı/Ödeme Alıcı | CRYPTOGRAM_3DS |
02 |
Mastercard | Kartı veren kuruluş | CRYPTOGRAM_3DS |
06 |
Mastercard | Satıcı/Ödeme Alıcı | CRYPTOGRAM_3DS |
05 |
Visa | Kartı veren kuruluş | CRYPTOGRAM_3DS |
07 |
Visa | Satıcı/Ödeme Alıcı | CRYPTOGRAM_3DS |
""(empty) |
Diğer ağlar | Satıcı/Ödeme Alıcı | CRYPTOGRAM_3DS |
VISA ve Mastercard için bu tabloda yer almayan diğer ECI değerleri döndürülmez.
İmza doğrulama
Ara anahtar ve mesaj imzalarını içeren 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, mesajları imzalamak için Eliptik Eğri Dijital İmza Algoritması'nı (ECDSA) kullanır. Bu algoritma, FIPS 186-4'te tanımlandığı şekilde karma işlevi olarak SHA-256 ile NIST P-256 üzerinden ECDSA parametrelerini kullanır.
İmza
İmza, iletinin en dış düzeyine eklenir. ASN.1 bayt biçiminde base64 ile kodlanır. ASN.1 hakkında daha fazla bilgi için IETF Araçları Ek A bölümüne bakın. İmza, ECDSA r ve s tam sayılarından 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
Örnek ödeme yöntemi jetonundaki ara imzalama anahtarı imzasını 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 imzayı doğrulama
Ara imzalama anahtarı imzası için imzalanmış dize birleştirilirken 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ğrulamayı denemeniz gerekir. En az bir imza doğrulaması başarılı olursa doğrulama tamamlanmış sayılır. signedStringForMessageSignature doğrulamak için daha sonra intermediateSigningKey.signedKey.keyValue kullanın. Google, kendi doğrulama kodunuz yerine mevcut bir kriptografik kitaplığı kullanmanızı önemle tavsiye eder.
Mesaj imzası için bayt dizesi 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 değerini ayrıştırmayın veya değiştirmeyin. Örneğin, \u003d ifadesini = karakteriyle değiştirmeyin.
Örnek
Aşağıdaki örnek, bir ödeme yöntemi jetonu örneğidir:
{
"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 olduğu 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'daki imza nasıl doğrulanır?
İmzalı dize oluşturulurken standart ECDSA doğrulama algoritması kullanılır. Önceki adımda doğrulanan intermediateSigningKey.signedKey.keyValue, signedMessage 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 jetonunun güvenliğini sağlamak 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 (
|
| Simetrik şifreleme algoritması |
ISO 18033-2'de tanımlandığı şekilde DEM2 Şifreleme algoritması: Sıfır IV'lü ve dolgusuz AES-256-CTR. |
| MAC algoritması | Anahtar türetme işlevinden türetilen 256 bit anahtarla HMAC_SHA256. |
Şifreleme ortak anahtarı biçimi
Şifreleme ortak anahtarı ve Google yüklerinde döndürülen ephemeralPublicKey, sıkıştırılmamış nokta biçiminde anahtarın base64 temsiliyle biçimlendirilir. Aşağıdaki iki unsurdan 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'de daha ayrıntılı olarak açıklanmıştır.
Ortak anahtar oluşturmak için OpenSSL'yi 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 dosyasına 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 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 çıkış ü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 ortak anahtar, onaltılık olarak kodlanmıştır. Sıkıştırılmamış nokta biçiminde Base64 olarak kodlanmış 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ğıdakine benzeyen bir publicKey.txt dosyası oluşturur:
BOdoXP+9Aq473SnGwg3JU1aiNpsd9vH2ognq4PtDtlLGa3Kj8TPf+jaQNPyDSkh3JUhiS0KyrrlWhAgNZKHYF2Y=
Dosya içeriğinde fazladan boşluk veya satır başı karakteri 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 ile kodlanmış bir özel anahtar oluşturun
Tink kitaplığı, özel anahtarınızın PKCS #8 biçiminde base64 kodlu olmasını bekler. İlk adımda oluşturulan özel anahtardan bu biçimde özel anahtar oluşturmak için 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 çıkış ü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 türetmek 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ığı şekilde, aşağıdaki parametreyle HKDFwithSHA256:
- Salt sağlanmamalıdır. RFC uyarınca, bu değer 32 sıfırlanmış baytlık bir salt değerine 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'i oluşturmak için SHA256 karma işleviyle HMAC'yi (RFC 5869) ve 2. adımda elde edilen
macKeydeğerini kullanın.AES-256-CTR modunu ve aşağıdakileri kullanarak
encryptedMessageşifresini çözün:- Sıfır IV.
- Dolgulu değil.
- 2. adımda elde edilen
symmetricEncryptionKey.
Anahtar yönetimi
Satıcı şifreleme anahtarları
Satıcılar, Şifreleme şeması spesifikasyonu bölümünde belirtilen spesifikasyonlara göre bir ortak anahtar oluşturur.
Google kök imzalama anahtarları
Google, herkese açık bir URL'den alınabilen, geçerli kök imzalama ortak anahtarlarını yayınlar. Anahtarlar, URL tarafından döndürülen HTTP önbellek üst bilgilerinde belirtilen süre boyunca geçerlidir. keyExpiration alanı tarafından belirlenen süre dolana kadar önbelleğe alınırlar. Bir getirme işleminin süresi dolduğunda, 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 Google'dan anahtarları getiremiyorsanız üretim URL'mizden keys.json anahtarını getirin, sisteminize kaydedin ve manuel olarak düzenli aralıklarla yenileyin. Normal koşullarda Google, en uzun geçerlilik bitiş tarihine sahip anahtarın süresi dolmadan beş yıl önce ECv2 için yeni bir kök imzalama anahtarı yayınlar. Anahtarların güvenliğinin ihlal edilmesi durumunda Google, keys.json anahtarının daha hızlı bir şekilde yeniden yüklenmesini talep etmek için self servis portalda sağlanan iletişim bilgileri aracılığıyla tüm satıcıları bilgilendirir. Düzenli rotasyonu kaçırmamanız için, Google anahtarlarını keys.json içeriğine kaydetmeyi seçen satıcıların, kendi yıllık anahtar rotasyonlarının bir parçası olarak her yıl yenileme yapmalarını öneririz.
Herkese açık URL aracılığıyla 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ü SubjectPublicKeyInfo ile kodlanmış anahtarın base64, sarmalanmamış veya doldurulmamış bir sürümüdür. Java'da, bahsedilen 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
Doğrudan entegrasyonla sunucularınızda bir ödeme yöntemi jetonunun şifresini doğrudan çözerseniz anahtarları her yıl değiştirmeniz gerekir.
Şifreleme anahtarlarını rotasyona tabi tutmak için aşağıdaki adımları tamamlayın:
- Yeni bir anahtar çifti oluşturmak için OpenSSL'yi kullanın.
- Daha önce Google Pay'e geliştirici olarak kaydolmak için kullandığınız Google Hesabı ( ) ile oturum açarak Google Pay ve Cüzdan Konsolu'nu açın.
- Google Pay API sekmesindeki Doğrudan entegrasyon bölmesinde, mevcut ortak 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.
Anahtar rotasyonunun sorunsuz bir şekilde gerçekleşmesi 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:const tokenizationSpecification = { "type": "DIRECT", "parameters": { "protocolVersion": "ECv2", "publicKey": "BOdoXP1aiNp.....kh3JUhiSZKHYF2Y=" } }
- 4. adımdaki kodu üretime dağıtın. Kod dağıtıldıktan sonra şifreleme ve şifre çözme işlemleri yeni anahtar çiftlerini kullanır.
Eski ortak anahtarın artık herhangi bir işlemi şifrelemek için kullanılmadığını doğrulayı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 ortak anahtarınızın yanındaki Yönet'i tıklayın. Eski ortak anahtarınızın yanındaki Sil'i ve ardından Ş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ğrulaması ve mesaj ş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ızda Tinkpaymentmethodtokenuygulamasını bağımlılık olarak 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 Google imzalama anahtarlarını önceden getirerek anahtarın bellekte kullanılabilir olmasını sağlayın. Bu sayede, şifre çözme işlemi anahtarları getirirken kullanıcının ağ gecikmesini görmesi engellenir.
GooglePaymentsPublicKeysManager.INSTANCE_PRODUCTION.refreshInBackground();
paymentMethodTokendeğerininencryptedMessagedeğişkeninde depolandığını varsayan aşağıdaki kodla mesajın şifresini çözün ve kalın harflerle yazılmış bölümleri senaryonuza göre değiştirin.Üretim dışı testler için
INSTANCE_PRODUCTIONyerineINSTANCE_TESTkullanın. Entegrasyonunuz etkin değilse veya yapılandırılmış bir şifreleme anahtarı yoksa [YOUR MERCHANT ID] yerine12345678901234567890kullanın.- Etkin
- DOĞRUDAN entegrasyon etkinleştirilmişse
- Şifreleme anahtarı yapılandırılmış
[YOUR MERCHANT ID] mülkünüzü değiştirmeyin.
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);
PrivateKey1değerini, Anahtarlarınızı hazırlama ve Google'a kaydolma bölümünde Google'a kayıtlı ortak anahtar değeriyle ilişkilendirilen uygun özel anahtar değeriyle değiştirin. Google ile anahtarları rotasyona tabi tutmanız gerektiğinde daha sonra birden fazla özel anahtar değeri ekleyebilirsiniz. Değişkenler, base64 kodlu bir PKCS8 dizesi veyaECPrivateKeynesnesi olabilir. Base64 ile kodlanmış bir PKCS8 özel anahtarının nasıl oluşturulacağı 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 Google sunucusunu arayamıyorsanız aşağıdaki kodla şifreyi çözün ve kalın harflerle yazılmış 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 tarihine kadar geçerlidir. Anahtarların güvenliğinin ihlal edilmesi durumunda Google,
keys.jsonanahtarının daha hızlı bir şekilde yeniden yüklenmesini talep etmek için self servis portalda sağlanan iletişim bilgileri aracılığıyla tüm satıcıları bilgilendirir.Kod snippet'i, yükün kullanımına odaklanabilmeniz için aşağıdaki güvenlik ayrıntılarını işler:
- Google imzalama anahtarları getirilir ve bellekte önbelleğe alınır.
- İmza doğrulama
- Şifre çözme