Satıcılar için ödeme verilerinin şifrelenmesi

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:

  1. Google kök imzalama anahtarlarını getirin.
  2. 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.
  3. Yükün ara imzalama anahtarının süresinin dolmadığını doğrulayın.
  4. Ara imzalama anahtarıyla yükün imzasının geçerli olduğunu doğrulayın.
  5. İmzayı doğruladıktan sonra yükün içeriğinin şifresini çözün.
  6. Mesajın süresinin dolmadığını doğrulayın. Bunun için geçerli saatin, şifresi çözülmüş içeriklerdeki messageExpiration alanından küçük olduğunu kontrol etmeniz gerekir.
  7. Ş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.

  • Eliptik eğri: NIST P-256 (OpenSSL'de prime256v1 olarak da bilinir).
  • CheckMode, OldCofactorMode, SingleHashMode ve CofactorMode 0'dır.
  • Nokta biçimi sıkıştırılmamış.
Anahtar türetme işlevi

SHA-256 ile HMAC tabanlı (HKDFwithSHA256).

  • Tuz sağlanmamalıdır.
  • Bilgiler, protokol sürümü ECv2 için ASCII olarak Google tarafından kodlanmalıdır.
  • AES256 anahtarı için 256 bit, HMAC_SHA256 anahtarı için ise 256 bit daha türetilmelidir.
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:

  1. ECIES-KEM kullanan 512 bit uzunluğunda bir paylaşılan anahtar oluşturmak için özel anahtarınızı ve verilen ephemeralPublicKey değerini kullanın. Aşağıdaki parametreleri kullanın:
    • Eliptik eğri: NIST P-256 (OpenSSL'de prime256v1 olarak da bilinir).
    • CheckMode, OldCofactorMode, SingleHashMode ve CofactorMode 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.
  2. Oluşturulan anahtarı 256 bit uzunluğunda iki anahtara bölün: symmetricEncryptionKey ve macKey.
  3. tag alanının encryptedMessage iç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 macKey değerini kullanın.

  4. 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:

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:

  1. Yeni bir anahtar çifti oluşturmak için OpenSSL'i kullanın.
  2. 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.
  3. 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.
  4. 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.
  5. Şifreleme anahtarlarını kaydet'i tıklayın.
  6. 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.

  7. Kodunuzda kullanılan ortak anahtarı değiştirin.

    PaymentMethodTokenizationSpecification parameters özelliğindeki publicKey ö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;
    }
  8. 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.
  9. Eski ortak anahtarın artık hiçbir işlemi şifrelemek için kullanılmadığını onaylayın.

  10. Eski özel anahtarı kaldırın.
  11. 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.
  12. 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:

  1. pom.xml dosyanıza bağımlılık olarak Tink paymentmethodtoken uygulaması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>
  2. 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();
  3. paymentMethodToken değerinin encryptedMessage değ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_PRODUCTION yerine INSTANCE_TEST, entegrasyonunuz etkin değilse veya şifreleme anahtarı yapılandırılmamışsa [YOUR MERCHANT ID] yerine yazı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);
  4. PrivateKey1 yerine, 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 bir ECPrivateKey nesnesi 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.

  5. 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