L'API Google Pay restituisce i metodi di pagamento in un payload PaymentMethodToken firmato e criptato. I metodi di pagamento restituiti sono carte
costituite da PAN o carte tokenizzate costituite da PAN del dispositivo e crittogrammi.
Il payload contiene un campo denominato protocolVersion che indica al destinatario del payload quali primitive crittografiche sono in uso e il formato previsto.
Questa guida fornisce informazioni su come generare una chiave pubblica per richiedere un token del metodo di pagamento criptato e firmato da Google e descrive in dettaglio i passaggi da seguire per verificare e decriptare il token.
Questa guida si applica solo a protocolVersion = ECv2.
Poiché ricevi direttamente i dati della carta di pagamento, assicurati che la tua app sia conforme allo standard PCI DSS e che i tuoi server dispongano dell'infrastruttura necessaria per gestire in modo sicuro le credenziali di pagamento dell'utente prima di procedere.
I seguenti passaggi descrivono cosa deve fare un integratore per utilizzare il payload dell'API Google Pay
ECv2 PaymentMethodToken:
- Recupera le chiavi di firma della radice di Google.
- Verifica che la firma della chiave di firma intermedia sia valida per una delle chiavi di firma radice non scadute.
- Verifica che la chiave di firma intermedia del payload non sia scaduta.
- Verifica che la firma del payload sia valida tramite la chiave di firma intermedia.
- Decripta i contenuti del payload dopo aver verificato la firma.
- Verifica che il messaggio non sia scaduto. Ciò richiede di verificare che l'ora corrente sia
inferiore al campo
messageExpirationnei contenuti decriptati. - Utilizza il metodo di pagamento nei contenuti decriptati e addebitalo.
Il codice di esempio nella nostra libreria Tink esegue i passaggi da 1 a 6.
Struttura del token del metodo di pagamento
Il messaggio restituito da Google nella risposta PaymentData è un oggetto JSON serializzato e codificato in UTF-8 con le chiavi specificate nella seguente tabella:
| Nome | Tipo | Descrizione |
|---|---|---|
protocolVersion |
Stringa | Identifica lo schema di crittografia o firma in base al quale viene creato il messaggio. Consente al protocollo di evolversi nel tempo, se necessario. |
signature |
Stringa | Verifica che il messaggio provenga da Google. È codificato in base64 e creato con ECDSA dalla chiave di firma intermedia. |
intermediateSigningKey |
Oggetto | Un oggetto JSON contenente la chiave di firma intermedia di Google. Contiene
signedKey con keyValue, keyExpiration e
signatures. Viene serializzata per semplificare la procedura di verifica della firma della chiave di firma intermedia. |
signedMessage |
Stringa | Un oggetto JSON serializzato come stringa sicura per HTML contenente
encryptedMessage, ephemeralPublicKey e tag. Viene
serializzato per semplificare la procedura di verifica della firma. |
Esempio
Di seguito è riportata una risposta del token del metodo di pagamento in JSON:
{ "protocolVersion":"ECv2", "signature":"MEQCIH6Q4OwQ0jAceFEkGF0JID6sJNXxOEi4r+mA7biRxqBQAiAondqoUpU/bdsrAOpZIsrHQS9nwiiNwOrr24RyPeHA0Q\u003d\u003d", "intermediateSigningKey":{ "signedKey": "{\"keyExpiration\":\"1542323393147\",\"keyValue\":\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/1+3HBVSbdv+j7NaArdgMyoSAM43yRydzqdg1TxodSzA96Dj4Mc1EiKroxxunavVIvdxGnJeFViTzFvzFRxyCw\\u003d\\u003d\"}", "signatures": ["MEYCIQCO2EIi48s8VTH+ilMEpoXLFfkxAwHjfPSCVED/QDSHmQIhALLJmrUlNAY8hDQRV/y1iKZGsWpeNmIP+z+tCQHQxP0v"] }, "signedMessage":"{\"tag\":\"jpGz1F1Bcoi/fCNxI9n7Qrsw7i7KHrGtTf3NrRclt+U\\u003d\",\"ephemeralPublicKey\":\"BJatyFvFPPD21l8/uLP46Ta1hsKHndf8Z+tAgk+DEPQgYTkhHy19cF3h/bXs0tWTmZtnNm+vlVrKbRU9K8+7cZs\\u003d\",\"encryptedMessage\":\"mKOoXwi8OavZ\"}" }
Chiave di firma intermedia
intermediateSigningKey è un oggetto JSON serializzato con codifica UTF-8 che contiene
i seguenti valori:
| Nome | Tipo | Descrizione |
|---|---|---|
signedKey |
Stringa | Un messaggio codificato in base64 che contiene la descrizione del pagamento della chiave. |
signatures |
Stringa | Verifica che la chiave di firma intermedia provenga da Google. È codificata in base64 e creata con ECDSA. |
Chiave firmata
signedKey è un oggetto JSON serializzato con codifica UTF-8 che contiene i seguenti valori:
| Nome | Tipo | Descrizione |
|---|---|---|
keyValue |
Stringa | Una versione base64 della chiave codificata nel tipo ASN.1. SubjectPublicKeyInfo è
definito nello standard X.509. |
keyExpiration |
Stringa | Data e ora di scadenza della chiave intermedia in millisecondi UTC dall'epoca. Gli integratori rifiutano qualsiasi chiave scaduta. |
Messaggio firmato
signedMessage è un oggetto JSON serializzato con codifica UTF-8 che contiene i seguenti valori:
| Nome | Tipo | Descrizione |
|---|---|---|
encryptedMessage |
Stringa | Un messaggio criptato con codifica Base64 che contiene i dati di pagamento e alcuni campi di sicurezza aggiuntivi. |
ephemeralPublicKey |
Stringa | Una chiave pubblica effimera con codifica Base64 associata alla chiave privata per criptare il messaggio in formato punto non compresso. Per saperne di più, vedi Formato della chiave pubblica di crittografia. |
tag |
Stringa | Un MAC con codifica base64 di encryptedMessage. |
Messaggio criptato
encryptedMessage decriptato è un oggetto JSON serializzato e codificato in UTF-8. Il
JSON contiene due livelli. Il livello esterno contiene metadati e campi inclusi per la sicurezza, mentre
il livello interno è un altro oggetto JSON che rappresenta la credenziale di pagamento effettiva.
Per ulteriori dettagli su encryptedMessage, consulta le seguenti tabelle e gli esempi di oggetti JSON:
| Nome | Tipo | Descrizione |
|---|---|---|
messageExpiration |
Stringa | Data e ora di scadenza del messaggio in millisecondi UTC dal periodo. Gli integratori devono rifiutare qualsiasi messaggio scaduto. |
messageId |
Stringa | Un ID univoco che identifica il messaggio nel caso in cui debba essere revocato o individuato in un secondo momento. |
paymentMethod |
Stringa | Il tipo di credenziale di pagamento.
Al momento è supportato solo CARD.
|
paymentMethodDetails |
Oggetto | Le credenziali di pagamento. Il formato di questo oggetto è determinato da
paymentMethod ed è descritto nelle tabelle seguenti. |
Scheda
Le seguenti proprietà costituiscono una credenziale di pagamento per il metodo di pagamento CARD:
| Nome | Tipo | Descrizione |
|---|---|---|
pan |
Stringa | Il numero dell'account personale a cui è stato addebitato l'importo. Questa stringa contiene solo cifre. |
expirationMonth |
Numero | Il mese di scadenza della carta, dove 1 rappresenta gennaio, 2 febbraio e così via. |
expirationYear |
Numero | L'anno di scadenza della carta a quattro cifre, ad esempio 2020. |
authMethod |
Stringa | Il metodo di autenticazione della transazione con carta. |
PAN_ONLY
Il seguente snippet JSON è un esempio del encryptedMessage completo per un
CARD paymentMethod
con un PAN_ONLY authMethod.
{ "paymentMethod": "CARD", "paymentMethodDetails": { "authMethod": "PAN_ONLY", "pan": "1111222233334444", "expirationMonth": 10, "expirationYear": 2025 }, "gatewayMerchantId": "some-merchant-id", "messageId": "some-message-id", "messageExpiration": "1759309000000" }
CRYPTOGRAM_3DS
CARD autenticata con l'utilizzo di un criptogramma 3-D Secure,
CRYPTOGRAM_3DS authMethod. Include i seguenti campi
aggiuntivi:
| Nome | Tipo | Descrizione |
|---|---|---|
cryptogram |
Stringa | Un crittogramma 3-D Secure. |
eciIndicator |
Stringa | Questa stringa non è sempre presente. Viene restituito solo per le transazioni con token dispositivo autenticati su Android (CRYPTOGRAM_3DS). Questo valore deve essere trasmesso nel flusso di elaborazione dei pagamenti. |
Il seguente snippet JSON è un esempio del encryptedMessage completo per un
CARD paymentMethod con un
CRYPTOGRAM_3DS authMethod:
{ "paymentMethod": "CARD", "paymentMethodDetails": { "authMethod": "CRYPTOGRAM_3DS", "pan": "1111222233334444", "expirationMonth": 10, "expirationYear": 2025, "cryptogram": "AAAAAA...", "eciIndicator": "eci indicator" }, "messageId": "some-message-id", "messageExpiration": "1759309000000" }
eciIndicator
Il circuito della carta potrebbe fornire eciIndicator per le transazioni con token dispositivo autenticati (CRYPTOGRAM_3DS).
Devi trasmettere il valore eciIndicator nella transazione di autorizzazione senza che venga modificato o codificato in modo permanente, altrimenti la transazione non va a buon fine. La tabella seguente mostra in dettaglio i valori di eciIndicator.
| valore eciIndicator | Circuito della carta | Parte responsabile | authMethod |
|---|---|---|---|
""(empty) |
Mastercard | Commerciante/Acquirer | CRYPTOGRAM_3DS |
02 |
Mastercard | Emittente della carta | CRYPTOGRAM_3DS |
06 |
Mastercard | Commerciante/Acquirer | CRYPTOGRAM_3DS |
05 |
Visa | Emittente della carta | CRYPTOGRAM_3DS |
07 |
Visa | Commerciante/Acquirer | CRYPTOGRAM_3DS |
""(empty) |
Altre reti | Commerciante/Acquirer | CRYPTOGRAM_3DS |
Eventuali altri valori ECI per VISA e Mastercard non presenti in questa tabella non verranno restituiti.
Verifica della firma
Per verificare le firme, che includono la firma della chiave intermedia e del messaggio, sono necessari i seguenti elementi:
- L'algoritmo utilizzato per creare la firma
- La stringa di byte utilizzata per creare la firma
- La chiave pubblica corrispondente a quella privata utilizzata per creare la firma
- La firma stessa
Algoritmo di firma
Google utilizza l'algoritmo di firma digitale con curva ellittica (ECDSA) per firmare i messaggi con i seguenti parametri: ECDSA su NIST P-256 con SHA-256 come funzione hash, come definito in FIPS 186-4.
La firma
La firma è inclusa nel livello più esterno del messaggio. È codificata con base64 in formato byte ASN.1. Per ulteriori informazioni su ASN.1, consulta l'appendice A di IETF Tools. La firma è costituita dai numeri interi r e s ECDSA. Per maggiori informazioni, consulta la sezione Algoritmo di generazione della firma.
Di seguito è riportato un esempio del formato byte ASN.1 specificato, che è il formato standard prodotto dalle implementazioni ECDSA di Java Cryptography Extension (JCE).
ECDSA-Sig-Value :: = SEQUENCE {
r INTEGER,
s INTEGER
}Come costruire la stringa di byte per la firma della chiave di firma intermedia
Per convalidare la firma della chiave di firma intermedia nel token del metodo di pagamento di esempio, crea
signedStringForIntermediateSigningKeySignature con la seguente formula:
signedStringForIntermediateSigningKeySignature = length_of_sender_id || sender_id || length_of_protocol_version || protocol_version || length_of_signed_key || signed_key
La notazione "||" indica la concatenazione. Ogni componente (sender_id,
protocolVersion, signedKey) deve essere codificato in UTF-8. Il
signedKey deve essere la stringa di intermediateSigningKey.signedKey.
La lunghezza in byte di ogni componente è di 4 byte in formato little-endian.
Esempio
Questo esempio utilizza il seguente token del metodo di pagamento di esempio:
{
"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 è sempre Google e protocol_version è ECv2.
Se sender_id è Google, signedString viene visualizzato come
mostrato nell'esempio seguente:
signedStringForIntermediateSigningKeySignature =
\x06\x00\x00\x00 || Google || | \x04\x00\x00\x00 || ECv2 || \xb5\x00\x00\x00 || {"keyExpiration":"1542323393147","keyValue":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/1+3HBVSbdv+j7NaArdgMyoSAM43yRydzqdg1TxodSzA96Dj4Mc1EiKroxxunavVIvdxGnJeFViTzFvzFRxyCw\u003d\u003d"}Come verificare la firma in signedStringForIntermediateSigningKeySignature
L'algoritmo di verifica ECDSA standard viene utilizzato quando viene assemblata la stringa firmata per la firma della chiave di firma intermedia. Per il protocollo ECv2, devi scorrere tutte le firme
in intermediateSigningKey.signatures e provare a convalidare ciascuna con le
chiavi di firma Google non scadute in keys.json. Se almeno una convalida della firma
funziona, considera la verifica completata. Utilizza
intermediateSigningKey.signedKey.keyValue in un secondo momento per verificare
signedStringForMessageSignature. Google ti consiglia vivamente di utilizzare una libreria
crittografica esistente anziché il tuo codice di verifica.
Come costruire la stringa di byte per la firma del messaggio
Per convalidare la firma nel token del metodo di pagamento di esempio, crea
signedStringForMessageSignature con la seguente formula:
signedStringForMessageSignature = length_of_sender_id || sender_id || length_of_recipient_id || recipient_id || length_of_protocolVersion || protocolVersion || length_of_signedMessage || signedMessage
La notazione "||" indica la concatenazione. Ogni componente (sender_id,
recipient_id, protocolVersion, signedMessage) deve essere codificato in UTF-8. La lunghezza in byte di ogni componente è di 4 byte in formato little-endian. Quando crei la stringa di byte, non analizzare o modificare signedMessage. Ad esempio, non sostituire
\u003d con il carattere =.
Esempio
Il seguente esempio è un token di metodo di pagamento di esempio:
{
"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 è sempre Google e recipient_id è merchant:merchantId. Il valore di merchantId corrisponde a quello trovato nella
console di Google Pay e Wallet per i commercianti con accesso alla produzione.
Se sender_id è Google e recipient_id è merchant:12345, signedString viene visualizzato come nell'esempio seguente:
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"}Come verificare la firma in signedStringForMessageSignature
Quando viene assemblata la stringa firmata, viene utilizzato l'algoritmo di verifica ECDSA standard. Il
intermediateSigningKey.signedKey.keyValue verificato nel passaggio precedente viene utilizzato per
verificare signedMessage. Google consiglia vivamente di utilizzare una libreria
crittografica esistente anziché il tuo codice di verifica.
Specifica dello schema di crittografia
Google utilizza lo schema di crittografia integrata della curva ellittica (ECIES) per proteggere il token del metodo di pagamento restituito nella risposta dell'API Google Pay. Lo schema di crittografia utilizza i seguenti parametri:
| Parametro | Definizione |
|---|---|
| Metodo di incapsulamento chiave | ECIES-KEM, come definito nella norma ISO 18033-2.
|
| Funzione di derivazione della chiave | Basato su HMAC con SHA-256 (
|
| Algoritmo di crittografia simmetrica |
DEM2, come definito nello standard ISO 18033-2 Algoritmo di crittografia: AES-256-CTR con IV pari a zero e senza padding. |
| Algoritmo MAC | HMAC_SHA256 con una chiave a 256 bit derivata dalla funzione di derivazione della chiave. |
Formato della chiave pubblica di crittografia
La chiave pubblica di crittografia e ephemeralPublicKey restituite nei payload di Google sono
formattate con la rappresentazione Base64 della chiave in formato punto non compresso. È composto dai seguenti due elementi:
- Un numero magico che specifica il formato (0x04).
- Due numeri interi grandi di 32 byte che rappresentano le coordinate X e Y nella curva ellittica.
Questo formato è descritto in modo più dettagliato in "Public Key Cryptography For The Financial Services Industry: The Elliptic Curve Digital Signature Algorithm (ECDSA)", ANSI X9.62, 1998.
Utilizzare OpenSSL per generare una chiave pubblica
Passaggio 1: genera una chiave privata
L'esempio seguente genera una chiave privata con curva ellittica adatta all'uso con NIST P-256 e la scrive in key.pem:
openssl ecparam -name prime256v1 -genkey -noout -out key.pem
(Facoltativo) Visualizza le chiavi privata e pubblica
Utilizza il seguente comando per visualizzare sia la chiave privata che quella pubblica:
openssl ec -in key.pem -pubout -text -noout
Il comando produce un output simile al seguente:
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
Passaggio 2: genera una chiave pubblica con codifica Base64
La chiave privata e quella pubblica generate nell'esempio del passaggio facoltativo precedente sono codificate in formato esadecimale. Per ottenere una chiave pubblica con codifica base64 in formato punto non compresso, utilizza questo comando:
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
Il comando produce un file publicKey.txt il cui contenuto, la versione base64 della chiave in formato punto non compresso, è simile al seguente:
BOdoXP+9Aq473SnGwg3JU1aiNpsd9vH2ognq4PtDtlLGa3Kj8TPf+jaQNPyDSkh3JUhiS0KyrrlWhAgNZKHYF2Y=
Il contenuto del file non deve contenere spazi vuoti o ritorni a capo aggiuntivi. Per verificarlo, esegui questo comando in Linux o macOS:
od -bc publicKey.txt
Passaggio 3: genera una chiave privata con codifica base64 in formato PKCS #8
La libreria Tink prevede che la chiave privata sia codificata in base64 nel formato PKCS #8. Utilizza il seguente comando per generare la chiave privata in questo formato dalla chiave privata generata nel primo passaggio:
openssl pkcs8 -topk8 -inform PEM -outform DER -in key.pem -nocrypt | base64 | paste -sd "\0" -
Il comando produce un output simile al seguente:
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgWV4oK8c/MZkCLk4qSCNjW0Zm6H0CBCtSYxkXkC9FBHehRANCAAQPldOnhO2/oXjdJD1dwlFPiNs6fcdoRgFu3/Z0iKj24SjTGyLRGAtYWLGXBZcDdPj3T2bJRHRVhE8Bc2AjkT7n
Come decriptare il token del metodo di pagamento
Per decriptare il token:
- Utilizza la chiave privata e il
ephemeralPublicKeyfornito per derivare una chiave condivisa lunga 512 bit che utilizza ECIES-KEM. Utilizza i seguenti parametri: - Curva ellittica: NIST P-256, nota anche in OpenSSL come prime256v1.
CheckMode,OldCofactorMode,SingleHashModeeCofactorModesono0.- Funzione di codifica: formato punto non compresso.
- Funzione di derivazione della chiave: HKDFwithSHA256, come descritto in RFC 5869, con il seguente parametro:
- Il sale non deve essere fornito. In base alla RFC, questo valore deve essere equivalente a un sale di 32 byte azzerati.
- Dividi la chiave generata in due chiavi lunghe 256 bit:
symmetricEncryptionKeyemacKey. Verifica che il campo
tagsia un MAC valido perencryptedMessage.Per generare il MAC previsto, utilizza HMAC (RFC 5869) con la funzione hash SHA256 e il
macKeyottenuto nel passaggio 2.Decripta
encryptedMessageutilizzando la modalità AES-256-CTR e con i seguenti elementi:- Un IV pari a zero.
- Non imbottito.
- Il
symmetricEncryptionKeyderivato nel passaggio 2.
Gestione delle chiavi
Chiavi di crittografia del commerciante
I commercianti generano una chiave pubblica in base alle specifiche descritte in Specifiche dello schema di crittografia.
Chiavi di firma radice di Google
Google pubblica l'insieme di chiavi pubbliche di firma radice attualmente valide recuperabili da un URL pubblico. Le chiavi sono valide per tutto il tempo indicato dalle intestazioni della cache HTTP restituite dall'URL. Vengono memorizzate nella cache fino alla scadenza, che è determinata dal campo keyExpiration. Ti consigliamo di recuperare nuovamente le chiavi dall'URL pubblico quando una richiesta scade per ricevere l'elenco corrente di chiavi valide.
Eccezione per il protocollo ECv2: se non riesci a recuperare le chiavi da Google in fase di runtime, recupera
keys.json dal nostro URL di produzione, salvalo nel tuo sistema e aggiornalo periodicamente
manualmente. In circostanze normali, Google rilascia una nuova chiave di firma principale per ECv2 cinque anni
prima della scadenza della chiave con la data di scadenza più lontana. In caso di compromissione delle chiavi, Google
invia una notifica a tutti i commercianti tramite i dati di contatto forniti nel portale self-service per
richiedere un ricaricamento più rapido di keys.json. Per non perdere la rotazione regolare, consigliamo ai commercianti che scelgono di salvare le chiavi Google nei contenuti di keys.json di aggiornarle annualmente nell'ambito della propria rotazione annuale delle chiavi.
Le chiavi fornite tramite l'URL pubblico vengono mappate nel seguente formato:
{ "keys": [ { "keyValue": "encoded public key", "protocolVersion": "ECv2" "keyExpiration":"2000000000000" }, { "keyValue": "encoded public key", "protocolVersion": "ECv2" "keyExpiration":"3000000000000" } ] }
keyValue è una versione della chiave con codifica ASN.1 di tipo SubjectPublicKeyInfo definita nello standard X.509, codificata in base64, non sottoposta a wrapping o padding. In Java, la codifica ASN.1 a cui si fa riferimento è rappresentata dalla classe X509EncodedKeySpec.
Può essere ottenuto con ECPublicKey.getEncoded().
Gli URL per gli ambienti di test e di produzione sono forniti dai seguenti link:
- Test:
https://payments.developers.google.com/paymentmethodtoken/test/keys.json - Produzione:
https://payments.developers.google.com/paymentmethodtoken/keys.json
Rotazione chiave
Se decripti un token del metodo di pagamento direttamente sui tuoi server con l'integrazione diretta, devi ruotare le chiavi annualmente.
Completa i seguenti passaggi per ruotare le chiavi di crittografia:
- Utilizza OpenSSL per generare una nuova coppia di chiavi.
- Apri la console Google Pay & Wallet dopo aver eseguito l'accesso con l'Account Google utilizzato in precedenza per gestire la tua app con Google Play.
- Nella scheda API Google Pay, nel riquadro Integrazione diretta, fai clic su Gestisci accanto alla chiave pubblica esistente. Fai clic su Aggiungi un'altra chiave.
- Seleziona il campo di input di testo Chiave di crittografia pubblica e aggiungi la chiave pubblica appena generata con codifica Base64 in formato punto non compresso.
- Fai clic su Salva chiavi di crittografia.
Per garantire una rotazione delle chiavi senza problemi, supporta la decriptografia delle chiavi private nuove e precedenti durante la transizione delle chiavi.
Se utilizzi la libreria Tink per decriptare il token, utilizza il seguente codice Java per supportare più chiavi private:
String decryptedMessage = new PaymentMethodTokenRecipient.Builder() .addRecipientPrivateKey(newPrivateKey) .addRecipientPrivateKey(oldPrivateKey);
Assicurati che il codice per la decriptografia sia implementato in produzione e monitora le decrittografie riuscite.
Modifica la chiave pubblica utilizzata nel codice.
Sostituisci il valore dell'attributo
publicKeynella proprietàPaymentMethodTokenizationSpecificationparameters:/** * @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; }
- Esegui il deployment del codice del passaggio 4 in produzione. Una volta implementato il codice, le transazioni di crittografia e decrittografia utilizzano le nuove coppie di chiavi.
Conferma che la vecchia chiave pubblica non viene più utilizzata per criptare le transazioni.
- Rimuovi la vecchia chiave privata.
- Apri Google Pay & Wallet Console dopo aver eseguito l'accesso con l'Account Google che hai utilizzato in precedenza per registrarti come sviluppatore con Google Pay.
- Nella scheda API Google Pay, nel riquadro Integrazione diretta, fai clic su Gestisci accanto alla chiave pubblica esistente. Fai clic su Elimina accanto alla vecchia chiave pubblica e fai clic su Salva chiavi di crittografia.
Google utilizza la chiave specificata nella proprietà publicKey all'interno
dell'oggetto PaymentMethodTokenizationSpecification parameters, come mostrato
nell'esempio seguente:
{
"protocolVersion": "ECv2",
"publicKey": "BOdoXP+9Aq473SnGwg3JU1..."
}Utilizza la libreria Tink per gestire la risposta criptata
Per eseguire la verifica della firma e la decriptazione del messaggio, utilizza la libreria Tink paymentmethodtoken. Questa libreria è disponibile solo in Java. Per utilizzarlo, completa i seguenti passaggi:
Nel file
pom.xml, aggiungi l'app Tinkpaymentmethodtokencome dipendenza:<dependencies> <!-- other dependencies ... --> <dependency> <groupId>com.google.crypto.tink</groupId> <artifactId>apps-paymentmethodtoken</artifactId> <version>1.9.1</version> <!-- or latest version --> </dependency> </dependencies>All'avvio del server, precarica le chiavi di firma Google per renderle disponibili in memoria. In questo modo, l'utente non visualizza alcuna latenza di rete mentre il processo di decrittografia recupera le chiavi.
GooglePaymentsPublicKeysManager.INSTANCE_PRODUCTION.refreshInBackground();
Decripta il messaggio con il seguente codice, che presuppone che
paymentMethodTokensia memorizzato nella variabileencryptedMessagee sostituisci le sezioni in grassetto in base al tuo scenario.Per i test non di produzione, sostituisci
INSTANCE_PRODUCTIONconINSTANCE_TESTe, se l'integrazione è inattiva o non è configurata una chiave di crittografia, sostituisci [YOUR MERCHANT ID] con.- Attivo
- Ha l'integrazione DIRECT abilitata
- Ha una chiave di crittografia configurata
non sostituire [YOUR MERCHANT ID].
String decryptedMessage = new PaymentMethodTokenRecipient.Builder() .fetchSenderVerifyingKeysWith( GooglePaymentsPublicKeysManager.INSTANCE_PRODUCTION) .recipientId("merchant:[YOUR MERCHANT ID]") // This guide applies only to protocolVersion = ECv2 .protocolVersion("ECv2") // Multiple private keys can be added to support graceful // key rotations. .addRecipientPrivateKey(PrivateKey1) .addRecipientPrivateKey(PrivateKey2) .build() .unseal(encryptedMessage);
Sostituisci
PrivateKey1con il valore della chiave privata appropriato associato al valore della chiave pubblica registrato con Google in Prepara le chiavi e registrati con Google. Puoi aggiungere più valori di altre chiavi private in un secondo momento, quando ti viene richiesto di ruotare le chiavi con Google. Le variabili possono essere una stringa PKCS8 codificata in base64 o un oggettoECPrivateKey. Per saperne di più su come produrre una chiave privata PKCS8 codificata in base64, consulta Preparare le chiavi e registrarsi su Google.Se non riesci a chiamare un server Google ogni volta che decripti le chiavi, decripta con il codice seguente e sostituisci le sezioni in grassetto in base al tuo scenario.
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);
La chiave attuale nell'ambiente di produzione è valida fino al 14/04/2038 in circostanze normali, ad eccezione dei compromessi della chiave. In caso di compromissione delle chiavi, Google invia una notifica a tutti i commercianti tramite i dati di contatto forniti nel portale self-service per richiedere un ricaricamento più rapido di
keys.json.Lo snippet di codice gestisce i seguenti dettagli di sicurezza, in modo che tu possa concentrarti sul consumo del payload:
- Chiavi di firma di Google recuperate e memorizzate nella cache in memoria
- Verifica della firma
- Decriptazione