L'API Google Pay renvoie les modes de paiement dans une charge utile PaymentMethodToken signée et chiffrée. Les modes de paiement renvoyés sont soit des cartes composées d'un PAN, soit des cartes tokenisées composées d'un PAN d'appareil et de cryptogrammes.
La charge utile contient un champ appelé protocolVersion qui indique au destinataire de la charge utile les primitives cryptographiques utilisées et le format attendu.
Ce guide explique comment générer une clé publique pour demander un jeton de mode de paiement chiffré et signé par Google, et décrit les étapes à suivre pour vérifier et déchiffrer le jeton.
Ce guide ne s'applique qu'à protocolVersion = ECv2.
Étant donné que vous recevez directement les informations de carte de paiement, assurez-vous que votre application est conforme à la norme PCI DSS et que vos serveurs disposent de l'infrastructure requise pour gérer de manière sécurisée les identifiants de paiement de l'utilisateur avant de continuer.
Les étapes suivantes décrivent ce qu'un intégrateur doit faire pour utiliser la charge utile ECv2 PaymentMethodToken de l'API Google Pay :
- Récupérez les clés de signature racine Google.
- Vérifiez que la signature de la clé de signature intermédiaire est valide avec l'une des clés de signature racine non expirées.
- Vérifiez que la clé de signature intermédiaire de la charge utile n'a pas expiré.
- Vérifiez que la signature de la charge utile est valide grâce à la clé de signature intermédiaire.
- Déchiffrez le contenu de la charge utile après avoir vérifié la signature.
- Vérifiez que le message n'a pas expiré. Pour cela, vous devez vérifier que l'heure actuelle est inférieure au champ
messageExpirationdans le contenu déchiffré. - Utilisez le mode de paiement indiqué dans le contenu décrypté et débitez-le.
L'exemple de code de notre bibliothèque Tink effectue les étapes 1 à 6.
Structure du jeton de mode de paiement
Le message renvoyé par Google dans la réponse PaymentData est un objet JSON sérialisé et encodé en UTF-8, avec les clés spécifiées dans le tableau suivant :
| Nom | Type | Description |
|---|---|---|
protocolVersion |
Chaîne | Identifie le schéma de chiffrement ou de signature sous lequel le message est créé. Il permet au protocole d'évoluer au fil du temps, si nécessaire. |
signature |
Chaîne | Vérifie que le message provient de Google. Elle est encodée en base64 et créée avec ECDSA par la clé de signature intermédiaire. |
intermediateSigningKey |
Objet | Objet JSON contenant la clé de signature intermédiaire de Google. Il contient signedKey avec keyValue, keyExpiration et signatures. Elle est sérialisée pour simplifier le processus de validation de la signature de la clé de signature intermédiaire. |
signedMessage |
Chaîne | Objet JSON sérialisé sous forme de chaîne HTML sécurisée contenant encryptedMessage, ephemeralPublicKey et tag. Il est sérialisé pour simplifier le processus de validation de la signature. |
Exemple
Voici une réponse de jeton de mode de paiement au format 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\"}" }
Clé de signature intermédiaire
intermediateSigningKey est un objet JSON sérialisé et encodé en UTF-8 qui contient les valeurs suivantes :
| Nom | Type | Description |
|---|---|---|
signedKey |
Chaîne | Message encodé en base64 contenant la description du paiement de la clé. |
signatures |
Chaîne | Vérifie que la clé de signature intermédiaire provient de Google. Elle est encodée en base64 et créée avec ECDSA. |
Clé signée
signedKey est un objet JSON sérialisé et encodé en UTF-8 qui contient les valeurs suivantes :
| Nom | Type | Description |
|---|---|---|
keyValue |
Chaîne | Version base64 de la clé encodée au format ASN.1. SubjectPublicKeyInfo est défini dans la norme X.509. |
keyExpiration |
Chaîne | Date et heure d'expiration de la clé intermédiaire en millisecondes UTC depuis l'époque. Les intégrateurs rejettent toute clé expirée. |
Message signé
signedMessage est un objet JSON sérialisé et encodé en UTF-8 qui contient les valeurs suivantes :
| Nom | Type | Description |
|---|---|---|
encryptedMessage |
Chaîne | Message chiffré encodé en base64 contenant des informations de paiement et des champs de sécurité supplémentaires. |
ephemeralPublicKey |
Chaîne | Clé publique éphémère encodée en base64 associée à la clé privée pour chiffrer le message au format de point non compressé. Pour en savoir plus, consultez Format de la clé publique de chiffrement. |
tag |
Chaîne | MAC de encryptedMessage encodé en base64. |
Message chiffré
Le encryptedMessage décrypté est un objet JSON sérialisé et encodé au format UTF-8. Le fichier JSON contient deux niveaux. Le niveau extérieur contient des métadonnées et des champs inclus pour la sécurité, tandis que le niveau intérieur est un autre objet JSON qui représente l'identifiant de paiement réel.
Pour en savoir plus sur encryptedMessage, consultez les tableaux et les exemples d'objets JSON suivants :
| Nom | Type | Description |
|---|---|---|
messageExpiration |
Chaîne | Date et heure d'expiration du message en millisecondes UTC depuis l'epoch. Les intégrateurs doivent rejeter tout message expiré. |
messageId |
Chaîne | ID unique qui identifie le message au cas où il devrait être révoqué ou localisé ultérieurement. |
paymentMethod |
Chaîne | Type d'identifiant de paiement.
Pour le moment, seul CARD est pris en charge.
|
paymentMethodDetails |
Objet | Le justificatif de paiement lui-même. Le format de cet objet est déterminé par paymentMethod et est décrit dans les tableaux suivants. |
Cartes
Les propriétés suivantes constituent un identifiant de paiement pour le mode de paiement CARD :
| Nom | Type | Description |
|---|---|---|
pan |
Chaîne | Numéro du compte personnel débité. Cette chaîne ne contient que des chiffres. |
expirationMonth |
Nombre | Mois d'expiration de la carte, où 1 représente janvier, 2 représente février, etc. |
expirationYear |
Nombre | Année d'expiration de la carte (à quatre chiffres, par exemple 2020). |
authMethod |
Chaîne | Méthode d'authentification de la transaction par carte. |
PAN_ONLY
L'extrait JSON suivant est un exemple de encryptedMessage complet pour un CARD paymentMethod
avec 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
Une CARD authentifiée à l'aide d'un cryptogramme 3-D Secure, CRYPTOGRAM_3DS authMethod. Il inclut les champs supplémentaires suivants :
| Nom | Type | Description |
|---|---|---|
cryptogram |
Chaîne | Cryptogramme 3-D Secure. |
eciIndicator |
Chaîne | Cette chaîne n'est pas toujours présente. Elle n'est renvoyée que pour les transactions de jetons d'appareil authentifiés sur Android (CRYPTOGRAM_3DS). Cette valeur doit être transmise tout au long du processus de paiement. |
L'extrait de code JSON suivant est un exemple de encryptedMessage complet pour un CARD paymentMethod avec 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
Le réseau de cartes peut fournir le eciIndicator pour les transactions avec jetons d'appareil authentifiés (CRYPTOGRAM_3DS).
Vous devez transmettre la valeur eciIndicator lors de la transaction d'autorisation sans la modifier ni la coder en dur. Sinon, la transaction échouera. Le tableau suivant détaille les valeurs de eciIndicator.
| Valeur eciIndicator | Réseau de cartes | Partie responsable | authMethod |
|---|---|---|---|
""(empty) |
MasterCard | Marchand/Acquéreur | CRYPTOGRAM_3DS |
02 |
MasterCard | Émetteur de la carte | CRYPTOGRAM_3DS |
06 |
MasterCard | Marchand/Acquéreur | CRYPTOGRAM_3DS |
05 |
Visa | Émetteur de la carte | CRYPTOGRAM_3DS |
07 |
Visa | Marchand/Acquéreur | CRYPTOGRAM_3DS |
""(empty) |
Autres réseaux | Marchand/Acquéreur | CRYPTOGRAM_3DS |
Toutes les autres valeurs ECI pour VISA et Mastercard qui ne figurent pas dans ce tableau ne seront pas renvoyées.
Validation de la signature
Pour valider les signatures, y compris les signatures de clé intermédiaire et de message, les éléments suivants sont requis :
- Algorithme utilisé pour créer la signature
- Chaîne d'octets utilisée pour créer la signature
- Clé publique correspondant à la clé privée utilisée pour créer la signature
- La signature elle-même
Algorithme de signature
Google utilise l'algorithme de signature numérique à courbe elliptique (ECDSA) pour signer les messages avec les paramètres suivants : ECDSA sur NIST P-256 avec SHA-256 comme fonction de hachage, tel que défini dans FIPS 186-4.
Signature
La signature est incluse au niveau le plus externe du message. Il est encodé en base64 au format d'octet ASN.1. Pour en savoir plus sur ASN.1, consultez l'annexe A des outils IETF. La signature se compose des entiers r et s de l'algorithme ECDSA. Pour en savoir plus, consultez Algorithme de génération de signature.
Voici un exemple du format d'octet ASN.1 spécifié, qui est le format standard produit par les implémentations ECDSA de l'extension de chiffrement Java (JCE).
ECDSA-Sig-Value :: = SEQUENCE {
r INTEGER,
s INTEGER
}Construire la chaîne d'octets pour la signature de la clé de signature intermédiaire
Pour valider la signature de la clé de signature intermédiaire dans l'exemple de jeton de mode de paiement, construisez signedStringForIntermediateSigningKeySignature avec la formule suivante :
signedStringForIntermediateSigningKeySignature = length_of_sender_id || sender_id || length_of_protocol_version || protocol_version || length_of_signed_key || signed_key
La notation "||" signifie concaténer. Chaque composant (sender_id, protocolVersion, signedKey) doit être encodé en UTF-8. signedKey doit être la chaîne de intermediateSigningKey.signedKey.
La longueur en octets de chaque composant est de quatre octets au format little-endian.
Exemple
Cet exemple utilise le jeton de mode de paiement suivant :
{
"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 est toujours Google et protocol_version est ECv2.
Si sender_id est défini sur Google, signedString s'affiche comme dans l'exemple suivant :
signedStringForIntermediateSigningKeySignature =
\x06\x00\x00\x00 || Google || | \x04\x00\x00\x00 || ECv2 || \xb5\x00\x00\x00 || {"keyExpiration":"1542323393147","keyValue":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/1+3HBVSbdv+j7NaArdgMyoSAM43yRydzqdg1TxodSzA96Dj4Mc1EiKroxxunavVIvdxGnJeFViTzFvzFRxyCw\u003d\u003d"}Vérifier la signature sur signedStringForIntermediateSigningKeySignature
L'algorithme de validation ECDSA standard est utilisé lorsque la chaîne signée pour la signature de la clé de signature intermédiaire est assemblée. Pour le protocole ECv2, vous devez parcourir toutes les signatures dans intermediateSigningKey.signatures et essayer de valider chacune d'elles avec les clés de signature Google non expirées dans keys.json. Si au moins une validation de signature fonctionne, la vérification est considérée comme terminée. Utilisez intermediateSigningKey.signedKey.keyValue ultérieurement pour valider signedStringForMessageSignature. Google vous recommande vivement d'utiliser une bibliothèque cryptographique existante plutôt que votre propre code de validation.
Construire la chaîne d'octets pour la signature du message
Pour valider la signature dans l'exemple de jeton de mode de paiement, construisez le signedStringForMessageSignature avec la formule suivante :
signedStringForMessageSignature = length_of_sender_id || sender_id || length_of_recipient_id || recipient_id || length_of_protocolVersion || protocolVersion || length_of_signedMessage || signedMessage
La notation "||" signifie concaténer. Chaque composant (sender_id, recipient_id, protocolVersion, signedMessage) doit être encodé en UTF-8. La longueur en octets de chaque composant est de quatre octets au format little-endian. Lorsque vous construisez la chaîne d'octets, n'analysez ni ne modifiez signedMessage. Par exemple, ne remplacez pas \u003d par le caractère =.
Exemple
Voici un exemple de jeton de mode de paiement :
{
"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 est toujours Google et recipient_id est merchant:merchantId. La valeur merchantId correspond à celle indiquée dans la Google Pay & Wallet Console pour les marchands ayant accès à la production.
Si sender_id est défini sur Google et que recipient_id est défini sur merchant:12345, signedString s'affiche tel quel, comme dans l'exemple suivant :
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"}Vérifier la signature sur signedStringForMessageSignature
L'algorithme de validation ECDSA standard est utilisé lorsque la chaîne signée est assemblée. Le intermediateSigningKey.signedKey.keyValue validé à l'étape précédente est utilisé pour valider le signedMessage. Google vous recommande vivement d'utiliser une bibliothèque cryptographique existante plutôt que votre propre code de validation.
Spécification du schéma de chiffrement
Google utilise le schéma de chiffrement intégré à courbe elliptique (ECIES) pour sécuriser le jeton du mode de paiement renvoyé dans la réponse de l'API Google Pay. Le schéma de chiffrement utilise les paramètres suivants :
| Paramètre | Définition |
|---|---|
| Méthode d'encapsulation de clé | ECIES-KEM, tel que défini dans la norme ISO 18033-2.
|
| Fonction de dérivation de clé | Basé sur HMAC avec SHA-256 (
|
| Algorithme de chiffrement symétrique |
DEM2, tel que défini dans la norme ISO 18033-2 Algorithme de chiffrement : AES-256-CTR avec IV nul et sans remplissage. |
| Algorithme MAC | HMAC_SHA256 avec une clé de 256 bits dérivée de la fonction de dérivation de clé. |
Format de la clé publique de chiffrement
La clé publique de chiffrement et le ephemeralPublicKey renvoyés dans les charges utiles Google sont mis en forme avec la représentation base64 de la clé au format de point non compressé. Il se compose des deux éléments suivants :
- Nombre magique qui spécifie le format (0x04).
- Deux grands entiers de 32 octets qui représentent les coordonnées X et Y dans la courbe elliptique.
Ce format est décrit plus en détail dans "Public Key Cryptography For The Financial Services Industry: The Elliptic Curve Digital Signature Algorithm (ECDSA)", ANSI X9.62, 1998.
Utiliser OpenSSL pour générer une clé publique
Étape 1 : Générer une clé privée
L'exemple suivant génère une clé privée à courbe elliptique pouvant être utilisée avec NIST P-256 et l'écrit dans key.pem :
openssl ecparam -name prime256v1 -genkey -noout -out key.pem
Facultatif : afficher les clés privée et publique
Utilisez la commande suivante pour afficher la clé privée et la clé publique :
openssl ec -in key.pem -pubout -text -noout
La commande produit un résultat semblable à celui-ci :
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
Étape 2 : Générer une clé publique encodée en base64
La clé privée et la clé publique générées dans l'exemple de l'étape facultative précédente sont encodées au format hexadécimal. Pour obtenir une clé publique encodée en base64 au format de point non compressé, utilisez la commande suivante :
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
La commande génère un fichier publicKey.txt dont le contenu, la version base64 de la clé au format de point non compressé, ressemble à ce qui suit :
BOdoXP+9Aq473SnGwg3JU1aiNpsd9vH2ognq4PtDtlLGa3Kj8TPf+jaQNPyDSkh3JUhiS0KyrrlWhAgNZKHYF2Y=
Le contenu du fichier ne doit pas comporter d'espaces vides ni de retours chariot supplémentaires. Pour le vérifier, exécutez la commande suivante sous Linux ou macOS :
od -bc publicKey.txt
Étape 3 : Générer une clé privée encodée en base64 au format PKCS #8
La bibliothèque Tink s'attend à ce que votre clé privée soit encodée en base64 au format PKCS #8. Utilisez la commande suivante pour générer la clé privée dans ce format à partir de la clé privée générée lors de la première étape :
openssl pkcs8 -topk8 -inform PEM -outform DER -in key.pem -nocrypt | base64 | paste -sd "\0" -
La commande produit un résultat semblable à celui-ci :
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgWV4oK8c/MZkCLk4qSCNjW0Zm6H0CBCtSYxkXkC9FBHehRANCAAQPldOnhO2/oXjdJD1dwlFPiNs6fcdoRgFu3/Z0iKj24SjTGyLRGAtYWLGXBZcDdPj3T2bJRHRVhE8Bc2AjkT7n
Décrypter le jeton du mode de paiement
Pour décrypter le jeton, procédez comme suit :
- Utilisez votre clé privée et le
ephemeralPublicKeyfourni pour dériver une clé partagée de 512 bits de long qui utilise ECIES-KEM. Utilisez les paramètres suivants : - Courbe elliptique : NIST P-256, également appelée prime256v1 dans OpenSSL.
CheckMode,OldCofactorMode,SingleHashModeetCofactorModesont0.- Fonction d'encodage : format de point non compressé.
- Fonction de dérivation de clé : HKDFwithSHA256, comme décrit dans la RFC 5869, avec le paramètre suivant :
- Le sel ne doit pas être fourni. Conformément à la RFC, cela doit équivaloir à un sel de 32 octets nuls.
- Divisez la clé générée en deux clés de 256 bits :
symmetricEncryptionKeyetmacKey. Vérifiez que le champ
tagest un MAC valide pourencryptedMessage.Pour générer le MAC attendu, utilisez HMAC (RFC 5869) avec la fonction de hachage SHA256 et le
macKeyobtenu à l'étape 2.Déchiffrez
encryptedMessageà l'aide du mode AES-256-CTR et des éléments suivants :- Un IV de zéro.
- Non rembourré.
- Le
symmetricEncryptionKeyobtenu à l'étape 2.
Gestion des clés
Clés de chiffrement du marchand
Les marchands génèrent une clé publique conformément aux spécifications décrites dans la spécification du schéma de chiffrement.
Clés de signature racine Google
Google publie l'ensemble des clés publiques de signature racine actuellement valides, qui peuvent être récupérées à partir d'une URL publique. Les clés sont valides aussi longtemps que les en-têtes de cache HTTP renvoyés par l'URL l'indiquent. Elles sont mises en cache jusqu'à leur expiration, qui est déterminée par le champ keyExpiration. Nous vous recommandons, lorsqu'une récupération expire, de récupérer à nouveau les clés à partir de l'URL publique pour obtenir la liste actuelle des clés valides.
Exception pour le protocole ECv2 : si vous ne parvenez pas à récupérer les clés de Google au moment de l'exécution, récupérez le keys.json à partir de notre URL de production, enregistrez-le dans votre système et actualisez-le régulièrement manuellement. Dans des circonstances normales, Google émet une nouvelle clé de signature racine pour ECv2 cinq ans avant l'expiration de la clé ayant la date d'expiration la plus éloignée. En cas de clés compromises, Google avertit tous les marchands via les coordonnées fournies dans le portail en libre-service afin de demander un rechargement plus rapide de keys.json. Pour ne pas manquer la rotation régulière, nous recommandons aux marchands qui choisissent d'enregistrer les clés Google dans le contenu de keys.json de les actualiser chaque année dans le cadre de leur propre rotation annuelle des clés.
Les clés fournies via l'URL publique sont mappées au format suivant :
{ "keys": [ { "keyValue": "encoded public key", "protocolVersion": "ECv2" "keyExpiration":"2000000000000" }, { "keyValue": "encoded public key", "protocolVersion": "ECv2" "keyExpiration":"3000000000000" } ] }
keyValue est une version base64, non encapsulée ni complétée, de la clé encodée dans le type ASN.1 SubjectPublicKeyInfo défini dans la norme X.509. En Java, l'encodage ASN.1 référencé est représenté par la classe X509EncodedKeySpec.
Vous pouvez l'obtenir avec ECPublicKey.getEncoded().
Les URL des environnements de test et de production sont disponibles via les liens suivants :
- Test :
https://payments.developers.google.com/paymentmethodtoken/test/keys.json - Production :
https://payments.developers.google.com/paymentmethodtoken/keys.json
Rotation des clés
Si vous déchiffrez un jeton de mode de paiement directement sur vos serveurs avec une intégration directe, vous devez alterner les clés tous les ans.
Pour effectuer une rotation des clés de chiffrement :
- Utilisez OpenSSL pour générer une paire de clés.
- Ouvrez la Google Pay & Wallet Console en étant connecté au compte Google que vous avez utilisé précédemment pour vous inscrire en tant que développeur Google Pay.
- Dans l'onglet API Google Pay, dans le volet Intégration directe, cliquez sur Gérer à côté de votre clé publique existante. Cliquez sur Ajouter une autre clé.
- Sélectionnez le champ de saisie de texte Clé de chiffrement publique et ajoutez votre nouvelle clé publique encodée en base64 au format de point non compressé.
- Cliquez sur Enregistrer les clés de chiffrement.
Pour garantir une rotation des clés fluide, acceptez le déchiffrement avec les anciennes et les nouvelles clés privées pendant la transition.
Si vous utilisez la bibliothèque Tink pour déchiffrer le jeton, utilisez le code Java suivant pour prendre en charge plusieurs clés privées :
String decryptedMessage = new PaymentMethodTokenRecipient.Builder() .addRecipientPrivateKey(newPrivateKey) .addRecipientPrivateKey(oldPrivateKey);
Assurez-vous que le code de déchiffrement est déployé en production et que vous surveillez les déchiffrements réussis.
Modifiez la clé publique utilisée dans votre code.
Remplacez la valeur de l'attribut
publicKeydans la propriétéparametersdePaymentMethodTokenizationSpecification:const tokenizationSpecification = { "type": "DIRECT", "parameters": { "protocolVersion": "ECv2", "publicKey": "BOdoXP1aiNp.....kh3JUhiSZKHYF2Y=" } }
- Déployez le code de l'étape 4 en production. Une fois le code déployé, les transactions de chiffrement et de déchiffrement utilisent les nouvelles paires de clés.
Vérifiez que l'ancienne clé publique n'est plus utilisée pour chiffrer les transactions.
- Supprimez l'ancienne clé privée.
- Ouvrez la Google Pay & Wallet Console en étant connecté au compte Google que vous avez utilisé précédemment pour vous inscrire en tant que développeur auprès de Google Pay.
- Dans l'onglet API Google Pay, sous le volet Intégration directe, cliquez sur Gérer à côté de votre clé publique existante. Cliquez sur Supprimer à côté de votre ancienne clé publique, puis sur Enregistrer les clés de chiffrement.
Google utilise la clé spécifiée dans la propriété publicKey de l'objet PaymentMethodTokenizationSpecification parameters, comme indiqué dans l'exemple suivant :
{
"protocolVersion": "ECv2",
"publicKey": "BOdoXP+9Aq473SnGwg3JU1..."
}Utilisez la bibliothèque Tink pour gérer la réponse chiffrée.
Pour valider la signature et déchiffrer le message, utilisez la bibliothèque Tink paymentmethodtoken. Cette bibliothèque n'est disponible qu'en Java. Pour l'utiliser, procédez comme suit :
Dans votre fichier
pom.xml, ajoutez l'applicationpaymentmethodtokenTink en tant que dépendance :<dependencies> <!-- other dependencies ... --> <dependency> <groupId>com.google.crypto.tink</groupId> <artifactId>apps-paymentmethodtoken</artifactId> <version>1.9.1</version> <!-- or latest version --> </dependency> </dependencies>Au démarrage du serveur, préchargez les clés de signature Google pour les rendre disponibles en mémoire. Cela empêche l'utilisateur de voir la latence du réseau pendant que le processus de déchiffrement récupère les clés.
GooglePaymentsPublicKeysManager.INSTANCE_PRODUCTION.refreshInBackground();
Déchiffrez le message avec le code suivant, qui suppose que
paymentMethodTokenest stocké dans la variableencryptedMessage, et remplacez les sections en gras en fonction de votre scénario.Pour les tests non liés à la production, remplacez
INSTANCE_PRODUCTIONparINSTANCE_TEST. Si votre intégration est inactive ou n'a pas de clé de chiffrement configurée, remplacez [YOUR MERCHANT ID] par12345678901234567890.- Actif
- L'intégration DIRECT est activée
- Une clé de chiffrement est configurée.
Ne remplacez pas [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);
Remplacez
PrivateKey1par la valeur de clé privée appropriée associée à la valeur de clé publique enregistrée auprès de Google dans Préparer vos clés et les enregistrer auprès de Google. Vous pourrez ajouter d'autres valeurs de clé privée ultérieurement lorsque vous devrez faire tourner les clés avec Google. Les variables peuvent être une chaîne PKCS8 encodée en base64 ou un objetECPrivateKey. Pour savoir comment générer une clé privée PKCS8 encodée en base64, consultez Préparer vos clés et vous enregistrer auprès de Google.Si vous ne pouvez pas appeler un serveur Google chaque fois que vous déchiffrez des clés, déchiffrez-les avec le code suivant et remplacez les sections en gras en fonction de votre scénario.
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 clé actuelle dans l'environnement de production est valide jusqu'au 14/04/2038 dans des circonstances normales, sauf en cas de compromission de la clé. En cas de clé compromise, Google avertit tous les marchands via les coordonnées fournies dans le portail en libre-service afin de demander un rechargement plus rapide de
keys.json.L'extrait de code gère les détails de sécurité suivants afin que vous puissiez vous concentrer sur la consommation de la charge utile :
- Clés de signature Google récupérées et mises en cache en mémoire
- Validation de la signature
- Déchiffrement