La API Google Pay devuelve los métodos de pago en un payload PaymentMethodToken firmado y cifrado. Los métodos de pago devueltos son tarjetas que constan de un PAN o tarjetas tokenizadas que constan de un PAN de dispositivo y criptogramas.
La carga útil contiene un campo llamado protocolVersion que indica al destinatario de la carga útil qué primitivas criptográficas se están usando y el formato esperado.
En esta guía se explica cómo generar una clave pública para solicitar un token de método de pago cifrado y firmado por Google, y se detallan los pasos que se deben seguir para verificar y descifrar el token.
Esta guía solo se aplica a protocolVersion = ECv2.
Como recibes la información de la tarjeta de pago directamente, asegúrate de que tu aplicación cumpla el estándar PCI DSS y de que tus servidores tengan la infraestructura necesaria para gestionar de forma segura las credenciales de pago del usuario antes de continuar.
A continuación, se describen los pasos que debe seguir un integrador para consumir la carga útil de la API de Google Pay
ECv2 PaymentMethodToken:
- Obtén las claves de firma raíz de Google.
- Verifica que la firma de la clave de firma intermedia sea válida con cualquiera de las claves de firma raíz que no hayan caducado.
- Verifica que la clave de firma intermedia de la carga útil no haya caducado.
- Verifica que la firma de la carga útil sea válida con la clave de firma intermedia.
- Descifra el contenido de la carga útil después de verificar la firma.
- Comprueba que el mensaje no haya caducado. Para ello, debes comprobar que la hora actual sea anterior a la del campo
messageExpirationdel contenido descifrado. - Usa el método de pago del contenido descifrado y haz el cargo.
El código de muestra de nuestra biblioteca Tink realiza los pasos del 1 al 6.
Estructura de token de método de pago
El mensaje que devuelve Google en la respuesta PaymentData es un objeto JSON serializado y codificado en UTF-8 con las claves especificadas en la siguiente tabla:
| Nombre | Tipo | Descripción |
|---|---|---|
protocolVersion |
Cadena | Identifica el esquema de cifrado o de firma con el que se ha creado el mensaje. Permite que el protocolo evolucione con el tiempo, si es necesario. |
signature |
Cadena | Verifica que el mensaje procede de Google. Está codificada en base64 y se ha creado con ECDSA mediante la clave de firma intermedia. |
intermediateSigningKey |
Objeto | Un objeto JSON que contiene la clave de firma intermedia de Google. Contiene el signedKey con keyValue, keyExpiration y signatures. Se serializa para simplificar el proceso de verificación de la firma de la clave de firma intermedia. |
signedMessage |
Cadena | Un objeto JSON serializado como una cadena segura para HTML que contiene encryptedMessage, ephemeralPublicKey y tag. Se serializa para simplificar el proceso de verificación de firmas. |
Ejemplo
A continuación se muestra una respuesta de token de método de pago en 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\"}" }
Clave de firma intermedia
intermediateSigningKey es un objeto JSON serializado con codificación UTF-8 que contiene los siguientes valores:
| Nombre | Tipo | Descripción |
|---|---|---|
signedKey |
Cadena | Un mensaje codificado en base64 que contiene la descripción del pago de la clave. |
signatures |
Cadena | Verifica que la clave de firma intermedia procede de Google. Está codificada en base64 y se ha creado con ECDSA. |
Clave firmada
signedKey es un objeto JSON serializado y codificado en UTF-8 que contiene los siguientes valores:
| Nombre | Tipo | Descripción |
|---|---|---|
keyValue |
Cadena | Una versión en base64 de la clave codificada en el tipo ASN.1. SubjectPublicKeyInfo se define en el estándar X.509. |
keyExpiration |
Cadena | Fecha y hora en que caduca la clave intermedia, expresadas en milisegundos UTC desde el inicio del registro de tiempo. Los integradores rechazan las claves que han caducado. |
Mensaje firmado
signedMessage es un objeto JSON serializado y codificado en UTF-8 que contiene los siguientes valores:
| Nombre | Tipo | Descripción |
|---|---|---|
encryptedMessage |
Cadena | Un mensaje cifrado codificado en base64 que contiene información para pagos y algunos campos de seguridad adicionales. |
ephemeralPublicKey |
Cadena | Una clave pública efímera codificada en base64 asociada a la clave privada para cifrar el mensaje en formato de punto sin comprimir. Para obtener más información, consulta el artículo Formato de clave pública de cifrado. |
tag |
Cadena | Un MAC codificado en base64 de encryptedMessage. |
Mensaje cifrado
El encryptedMessage descifrado es un objeto JSON serializado y codificado en UTF-8. El JSON contiene dos niveles. El nivel exterior contiene metadatos y campos incluidos por motivos de seguridad, mientras que el nivel interior es otro objeto JSON que representa la credencial de pago real.
Para obtener más información sobre encryptedMessage, consulta las siguientes tablas y ejemplos de objetos JSON:
| Nombre | Tipo | Descripción |
|---|---|---|
messageExpiration |
Cadena | Fecha y hora en que caduca el mensaje, expresadas en milisegundos UTC desde el inicio del registro de tiempo. Los integradores deben rechazar cualquier mensaje que haya caducado. |
messageId |
Cadena | Un ID único que identifica el mensaje por si es necesario revocarlo o localizarlo más adelante. |
paymentMethod |
Cadena | El tipo de credencial de pago.
Por el momento, solo se admite CARD.
|
paymentMethodDetails |
Objeto | La credencial de pago en sí. El formato de este objeto lo determina el paymentMethod y se describe en las siguientes tablas. |
Tarjeta
Las siguientes propiedades componen una credencial de pago del método de pago CARD:
| Nombre | Tipo | Descripción |
|---|---|---|
pan |
Cadena | El número de cuenta personal al que se ha aplicado el cargo. Esta cadena solo contiene dígitos. |
expirationMonth |
Número | Mes de vencimiento de la tarjeta, donde 1 representa enero, 2 representa febrero, etc. |
expirationYear |
Número | El año de vencimiento de la tarjeta, con cuatro dígitos (por ejemplo, 2020). |
authMethod |
Cadena | El método de autenticación de la transacción con tarjeta. |
merchantTokenId |
Cadena | El ID de token de comercio de la transacción con tarjeta. Este campo opcional solo se devuelve si se cumplen todas las condiciones siguientes:
|
PAN_ONLY
El siguiente fragmento de JSON es un ejemplo de la encryptedMessage completa de 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
Un CARD autenticado mediante un criptograma de 3-D Secure,
CRYPTOGRAM_3DS authMethod. Incluye los siguientes campos adicionales:
| Nombre | Tipo | Descripción |
|---|---|---|
cryptogram |
Cadena | Un criptograma de 3-D Secure. |
eciIndicator |
Cadena | Esta cadena no siempre está presente. Solo se devuelve para las transacciones de tokens de dispositivos autenticados en Android (CRYPTOGRAM_3DS). Este valor debe transmitirse a lo largo del flujo de procesamiento de pagos. |
El siguiente fragmento de JSON es un ejemplo del encryptedMessage completo de 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",
"merchantTokenId": "merchant-token-id",
},
"messageId": "some-message-id",
"messageExpiration": "1759309000000"
}eciIndicator
La red de tarjetas puede proporcionar el eciIndicator para las transacciones de tokens de dispositivos autenticados (CRYPTOGRAM_3DS).
Debes transferir el valor eciIndicator en la transacción de autorización sin que se altere ni se codifique de forma rígida. De lo contrario, la transacción fallará. En la siguiente tabla se detallan los valores de eciIndicator.
| Valor de eciIndicator | Red de tarjetas | Parte responsable | authMethod |
|---|---|---|---|
""(empty) |
Mastercard | Comercio o entidad adquirente | CRYPTOGRAM_3DS |
02 |
Mastercard | Entidad emisora de la tarjeta | CRYPTOGRAM_3DS |
06 |
Mastercard | Comercio o entidad adquirente | CRYPTOGRAM_3DS |
05 |
Visa | Entidad emisora de la tarjeta | CRYPTOGRAM_3DS |
07 |
Visa | Comercio o entidad adquirente | CRYPTOGRAM_3DS |
""(empty) |
Otras redes | Comercio o entidad adquirente | CRYPTOGRAM_3DS |
No se devolverán otros valores de ECI para VISA y Mastercard que no estén presentes en esta tabla.
Verificación de firma
Para verificar las firmas, que incluyen la clave intermedia y las firmas de los mensajes, se necesitan los siguientes elementos:
- El algoritmo usado para crear la firma
- La cadena de bytes usada para crear la firma
- La clave pública que corresponde a la clave privada que se ha usado para crear la firma
- La propia firma
El algoritmo de firma
Google utiliza el algoritmo de firma digital de curva elíptica (ECDSA) para firmar los mensajes con los siguientes parámetros: ECDSA sobre NIST P-256 con SHA-256 como función hash, tal como se define en FIPS 186-4.
La firma
La firma se incluye en el nivel más externo del mensaje. Está codificada con base64 en formato de byte ASN.1. Para obtener más información sobre ASN.1, consulta el apéndice A de las herramientas de IETF. La firma consta de los enteros r y s de ECDSA. Para obtener más información, consulta el algoritmo de generación de firmas.
A continuación, se muestra un ejemplo del formato de byte ASN.1 especificado, que es el formato estándar que producen las implementaciones de ECDSA de la extensión de criptografía de Java (JCE).
ECDSA-Sig-Value :: = SEQUENCE {
r INTEGER,
s INTEGER
}Cómo crear la cadena de bytes para la firma de la clave de firma intermedia
Para validar la firma de la clave de firma intermedia en el token de método de pago de ejemplo, crea el signedStringForIntermediateSigningKeySignature con la siguiente fórmula:
signedStringForIntermediateSigningKeySignature = length_of_sender_id || sender_id || length_of_protocol_version || protocol_version || length_of_signed_key || signed_key
La notación "||" significa concatenar. Cada componente (sender_id, protocolVersion y signedKey) debe estar codificado en UTF-8. signedKey debe ser la cadena de intermediateSigningKey.signedKey.
La longitud de bytes de cada componente es de 4 bytes en formato little-endian.
Ejemplo
En este ejemplo se usa el siguiente token de método de pago de ejemplo:
{
"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 siempre es Google y protocol_version es ECv2.
Si el sender_id es Google, el signedString se muestra como en el siguiente ejemplo:
signedStringForIntermediateSigningKeySignature =
\x06\x00\x00\x00 || Google || | \x04\x00\x00\x00 || ECv2 || \xb5\x00\x00\x00 || {"keyExpiration":"1542323393147","keyValue":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/1+3HBVSbdv+j7NaArdgMyoSAM43yRydzqdg1TxodSzA96Dj4Mc1EiKroxxunavVIvdxGnJeFViTzFvzFRxyCw\u003d\u003d"}Cómo verificar la firma en signedStringForIntermediateSigningKeySignature
El algoritmo de verificación ECDSA estándar se usa cuando se ensambla la cadena firmada de la firma de la clave de firma intermedia. En el caso del protocolo ECv2, debes iterar todas las firmas de intermediateSigningKey.signatures e intentar validar cada una de ellas con las claves de firma de Google que no hayan caducado en keys.json. Si al menos una validación de firma funciona, se considera que la verificación se ha completado. Usa el intermediateSigningKey.signedKey.keyValue más adelante para verificar el signedStringForMessageSignature. Google recomienda encarecidamente que uses una biblioteca criptográfica que ya exista en lugar de tu propio código de verificación.
Cómo crear la cadena de bytes para la firma de mensajes
Para validar la firma en el token de método de pago de ejemplo, crea la signedStringForMessageSignature con la siguiente fórmula:
signedStringForMessageSignature = length_of_sender_id || sender_id || length_of_recipient_id || recipient_id || length_of_protocolVersion || protocolVersion || length_of_signedMessage || signedMessage
La notación "||" significa concatenar. Cada componente (sender_id, recipient_id, protocolVersion y signedMessage) debe estar codificado en UTF-8. La longitud de bytes de cada componente es de 4 bytes en formato little-endian. Cuando construyas la cadena de bytes, no analices ni modifiques signedMessage. Por ejemplo, no sustituyas \u003d por el carácter =.
Ejemplo
A continuación se muestra un ejemplo de token de método de pago:
{
"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 siempre es Google y recipient_id es merchant:merchantId. El merchantId coincide con el valor que se encuentra en la consola de Google Pay y Wallet para los comercios con acceso a producción.
Si el sender_id es Google y el recipient_id es merchant:12345, el signedString se muestra como en el siguiente ejemplo:
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"}Cómo verificar la firma en signedStringForMessageSignature
El algoritmo de verificación ECDSA estándar se usa cuando se ensambla la cadena firmada. El intermediateSigningKey.signedKey.keyValue verificado en el paso anterior se usa para verificar el signedMessage. Google recomienda encarecidamente que uses una biblioteca criptográfica que ya exista en lugar de tu propio código de verificación.
Especificación del esquema de cifrado
Google utiliza el esquema de cifrado integrado de curva elíptica (ECIES) para proteger el token del método de pago que se devuelve en la respuesta de la API de Google Pay. El esquema de cifrado usa los siguientes parámetros:
| Parámetro | Definición |
|---|---|
| Método de encapsulación de claves | ECIES-KEM, tal como se define en ISO 18033-2.
|
| Función de derivación de claves | Basado en HMAC con SHA-256 (
|
| Algoritmo de cifrado simétrico |
DEM2, tal como se define en la norma ISO 18033-2 Algoritmo de cifrado: AES-256-CTR con vector de inicialización cero y sin relleno. |
| Algoritmo MAC | HMAC_SHA256 con una clave de 256 bits derivada de la función de derivación de claves. |
Formato de clave pública de cifrado
La clave pública de cifrado y el ephemeralPublicKey que se devuelven en las cargas útiles de Google tienen el formato de la representación en base64 de la clave en formato de punto sin comprimir. Consta de los dos elementos siguientes:
- Un número mágico que especifica el formato (0x04).
- Dos enteros grandes de 32 bytes que representan las coordenadas X e Y de la curva elíptica.
Este formato se describe con más detalle en "Public Key Cryptography For The Financial Services Industry: The Elliptic Curve Digital Signature Algorithm (ECDSA)", ANSI X9.62, 1998.
Usar OpenSSL para generar una clave pública
Paso 1: Genera una clave privada
En el siguiente ejemplo se genera una clave privada de curva elíptica adecuada para usarla con NIST P-256 y se escribe en key.pem:
openssl ecparam -name prime256v1 -genkey -noout -out key.pem
Opcional: Ver las claves privadas y públicas
Usa el siguiente comando para ver las claves privada y pública:
openssl ec -in key.pem -pubout -text -noout
El comando genera un resultado similar al siguiente:
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
Paso 2: Generar una clave pública codificada en base64
La clave privada y la clave pública que se generan en el ejemplo del paso opcional anterior están codificadas en formato hexadecimal. Para obtener una clave pública codificada en base64 en formato de punto sin comprimir, usa el siguiente 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
El comando genera un archivo publicKey.txt cuyo contenido, la versión en base64 de la clave en formato de punto sin comprimir, se parece al siguiente:
BOdoXP+9Aq473SnGwg3JU1aiNpsd9vH2ognq4PtDtlLGa3Kj8TPf+jaQNPyDSkh3JUhiS0KyrrlWhAgNZKHYF2Y=
El contenido del archivo no debe tener espacios vacíos ni retornos de carro adicionales. Para comprobarlo, ejecuta el siguiente comando en Linux o macOS:
od -bc publicKey.txt
Paso 3: Genera una clave privada codificada en base64 con el formato PKCS #8
La biblioteca Tink espera que tu clave privada esté codificada en Base64 en formato PKCS #8. Usa el siguiente comando para generar la clave privada en este formato a partir de la clave privada generada en el primer paso:
openssl pkcs8 -topk8 -inform PEM -outform DER -in key.pem -nocrypt | base64 | paste -sd "\0" -
El comando genera un resultado similar al siguiente:
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgWV4oK8c/MZkCLk4qSCNjW0Zm6H0CBCtSYxkXkC9FBHehRANCAAQPldOnhO2/oXjdJD1dwlFPiNs6fcdoRgFu3/Z0iKj24SjTGyLRGAtYWLGXBZcDdPj3T2bJRHRVhE8Bc2AjkT7n
Cómo descifrar el token del método de pago
Sigue estos pasos para descifrar el token:
- Usa tu clave privada y el
ephemeralPublicKeyproporcionado para derivar una clave compartida de 512 bits que use ECIES-KEM. Usa los siguientes parámetros: - Curva elíptica: NIST P-256, también conocida en OpenSSL como prime256v1.
CheckMode,OldCofactorMode,SingleHashModeyCofactorModeson0.- Función de codificación: formato de punto sin comprimir.
- Función de derivación de claves: HKDFwithSHA256, tal como se describe en RFC 5869, con el siguiente parámetro:
- No se debe proporcionar el valor de sal. Según el RFC, debe ser equivalente a un salt de 32 bytes con valor cero.
- Divide la clave generada en dos claves de 256 bits:
symmetricEncryptionKeyymacKey. Comprueba que el campo
tagsea una MAC válida paraencryptedMessage.Para generar el MAC esperado, usa HMAC (RFC 5869) con la función hash SHA256 y el
macKeyobtenido en el paso 2.Descifra
encryptedMessagecon el modo AES-256-CTR y lo siguiente:- Un VI de cero.
- No acolchado.
- La
symmetricEncryptionKeyderivada en el paso 2.
Gestión de claves
Claves de cifrado del comerciante
Los comercios generan una clave pública según las especificaciones descritas en la especificación del esquema de cifrado.
Claves de firma raíz de Google
Google publica el conjunto de claves públicas de firma raíz válidas que se pueden obtener de una URL pública. Las claves son válidas durante el tiempo que indiquen los encabezados de caché HTTP que devuelve la URL. Se almacenan en caché hasta que caducan, lo que se determina mediante el campo keyExpiration. Te recomendamos que, cuando caduque una obtención, vuelvas a obtener las claves de la URL pública para recibir la lista de claves válidas.
Excepción para el protocolo ECv2: si no puedes obtener las claves de Google en el momento de la ejecución, obtén el keys.json de nuestra URL de producción, guárdalo en tu sistema y actualízalo manualmente de forma periódica. En circunstancias normales, Google emite una nueva clave de firma raíz para ECv2 cinco años antes de que caduque la clave con la fecha de vencimiento más larga. En caso de que se vulneren las claves, Google notificará a todos los comercios a través de la información de contacto proporcionada en el portal de autoservicio para solicitar una recarga más rápida de keys.json. Para asegurarte de que no te pierdes la rotación periódica, recomendamos que los comerciantes que decidan guardar las claves de Google en el contenido de keys.json las actualicen anualmente como parte de su propia rotación de claves anual.
Las claves proporcionadas a través de la URL pública se asignan con el siguiente formato:
{ "keys": [ { "keyValue": "encoded public key", "protocolVersion": "ECv2" "keyExpiration":"2000000000000" }, { "keyValue": "encoded public key", "protocolVersion": "ECv2" "keyExpiration":"3000000000000" } ] }
La keyValue es una versión en base64, no empaquetada ni rellenada, de la clave codificada en el tipo ASN.1 SubjectPublicKeyInfo definido en el estándar X.509. En Java, la codificación ASN.1 a la que se hace referencia se representa mediante la clase X509EncodedKeySpec.
Se puede obtener con ECPublicKey.getEncoded().
Las URLs de los entornos de prueba y de producción se proporcionan en los siguientes enlaces:
- Prueba:
https://payments.developers.google.com/paymentmethodtoken/test/keys.json - Producción:
https://payments.developers.google.com/paymentmethodtoken/keys.json
Rotación de claves
Si descifras un token de método de pago directamente en tus servidores con la integración directa, debes rotar las claves anualmente.
Sigue estos pasos para rotar las claves de cifrado:
- Usa OpenSSL para generar un nuevo par de claves.
- Abre la consola de Google Pay y Wallet con la cuenta de Google que usaste anteriormente para registrarte como desarrollador de Google Pay.
- En la pestaña API de Google Pay, en el panel Integración directa, haz clic en Gestionar junto a tu clave pública. Haz clic en Añadir otra clave.
- Selecciona el campo de entrada de texto Clave de cifrado pública y añade la clave pública que acabas de generar codificada en base64 en formato de punto sin comprimir.
- Haz clic en Guardar claves de cifrado.
Para que la rotación de claves se realice sin problemas, admite el descifrado de las claves privadas nuevas y antiguas mientras se cambian las claves.
Si usas la biblioteca Tink para descifrar el token, utiliza el siguiente código Java para admitir varias claves privadas:
String decryptedMessage = new PaymentMethodTokenRecipient.Builder() .addRecipientPrivateKey(newPrivateKey) .addRecipientPrivateKey(oldPrivateKey);
Asegúrate de que el código de descifrado se haya desplegado en producción y de que monitorizas los descifrados correctos.
Cambia la clave pública que se usa en tu código.
Sustituye el valor del atributo
publicKeyen la propiedadPaymentMethodTokenizationSpecificationparameters:const tokenizationSpecification = { "type": "DIRECT", "parameters": { "protocolVersion": "ECv2", "publicKey": "BOdoXP1aiNp.....kh3JUhiSZKHYF2Y=" } }
- Despliega el código del paso 4 en producción. Una vez que se haya implementado el código, las transacciones de cifrado y descifrado usarán los nuevos pares de claves.
Confirma que la clave pública antigua ya no se usa para cifrar ninguna transacción.
- Quita la clave privada antigua.
- Abre la consola de Google Pay y Wallet con la cuenta de Google que hayas usado anteriormente para registrarte como desarrollador en Google Pay.
- En la pestaña API de Google Pay, en el panel Integración directa, haz clic en Gestionar junto a tu clave pública. Haz clic en Eliminar junto a tu clave pública antigua y, a continuación, en Guardar claves de cifrado.
Google utiliza la clave especificada en la propiedad publicKey del objeto PaymentMethodTokenizationSpecification parameters, tal como se muestra en el siguiente ejemplo:
{
"protocolVersion": "ECv2",
"publicKey": "BOdoXP+9Aq473SnGwg3JU1..."
}Usa la biblioteca Tink para gestionar la respuesta cifrada.
English:Para verificar la firma y descifrar el mensaje, usa la biblioteca paymentmethodtoken de Tink. Esta biblioteca solo está disponible en Java. Para usarla, sigue estos pasos:
En tu
pom.xml, añade la aplicación Tinkpaymentmethodtokencomo dependencia:<dependencies> <!-- other dependencies ... --> <dependency> <groupId>com.google.crypto.tink</groupId> <artifactId>apps-paymentmethodtoken</artifactId> <version>1.9.1</version> <!-- or latest version --> </dependency> </dependencies>Al iniciar el servidor, precarga las claves de firma de Google para que estén disponibles en la memoria. De esta forma, se evita que el usuario vea la latencia de red mientras el proceso de descifrado obtiene las claves.
GooglePaymentsPublicKeysManager.INSTANCE_PRODUCTION.refreshInBackground();
Descifra el mensaje con el siguiente código, que asume que
paymentMethodTokense almacena en la variableencryptedMessage, y sustituye las secciones en negrita según tu situación.En las pruebas que no sean de producción, sustituye
INSTANCE_PRODUCTIONporINSTANCE_TEST. Si tu integración está inactiva o no tiene configurada una clave de cifrado, sustituye [YOUR MERCHANT ID] por12345678901234567890.- Activa
- Tiene habilitada la integración DIRECTA
- Tiene una clave de cifrado configurada
no sustituyas [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);
Sustituye
PrivateKey1por el valor de clave privada adecuado que se asocie al valor de clave pública registrado en Google de la sección Preparar las claves y registrarlas en Google. Puedes añadir más valores de clave privada más adelante cuando se te pida que cambies las claves con Google. Las variables pueden ser una cadena PKCS8 codificada en Base64 o un objetoECPrivateKey. Para obtener más información sobre cómo generar una clave privada PKCS8 codificada en Base64, consulta el artículo Preparar las claves y registrarse en Google.Si no puedes llamar a un servidor de Google cada vez que descifres claves, descífralas con el siguiente código y sustituye las secciones en negrita según tu situación.
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 clave actual del entorno de producción es válida hasta el 14/04/2038 en circunstancias normales, excepto si se vulnera la clave. En caso de que se vulneren las claves, Google notificará a todos los comercios a través de la información de contacto proporcionada en el portal de autoservicio para solicitar una recarga más rápida de
keys.json.El fragmento de código gestiona los siguientes detalles de seguridad para que puedas centrarte en el consumo de la carga útil:
- Claves de firma de Google obtenidas y almacenadas en la memoria caché
- Verificación de firma
- Desencriptado