> [!WARNING]
> **Important:** The following information is valid for merchants only and not for payment service providers. For questions about your integration as a payment service provider, [contact us](https://support.google.com/faqs/contact/googlepay_api_gateway_payment_processor_interest_form).

The Google Pay API returns payment methods in a signed and encrypted
`PaymentMethodToken` payload. The returned payment methods are either cards that
consist of PAN, or tokenized cards that consist of device PAN and cryptograms.


The payload contains a field called `protocolVersion` that tells the recipient of the
payload which cryptographic primitives are in use and the expected format.

This guide provides information on how to generate a public key to request a Google-signed and
encrypted payment method token, and details the steps to take to verify and decrypt the token.

This guide applies only to `protocolVersion = ECv2`.

> [!NOTE]
> **Note:** If you had implemented support for ECv1, your implementation still works. Contact your Google contact to verify your implementation and enable ECv2 payloads receivable if you wish to upgrade to ECv2 in production.

Because you receive payment card information directly, make sure your app is PCI DSS compliant
and that your servers have the required infrastructure to securely handle the user's payment
credentials before you proceed.

The following steps outline what an integrator must do to consume the Google Pay API
`ECv2` `PaymentMethodToken` payload:

1. Fetch the [Google root signing keys](https://developers.google.com/pay/api/web/guides/resources/payment-data-cryptography#root-signing-keys).
2. Verify that the signature of the intermediate signing key is valid by any of the non-expired root signing keys.
3. Verify that the intermediate signing key of the payload hasn't expired.
4. Verify that the signature of the payload is valid by the intermediate signing key.
5. Decrypt the contents of the payload after you verify the signature.
6. Verify that the message isn't expired. This requires you to check that the current time is less than the `messageExpiration` field in the decrypted contents.
7. Use the payment method in the decrypted contents and charge it.

The sample code in our [Tink library](https://developers.google.com/pay/api/web/guides/resources/payment-data-cryptography#using-tink) performs steps 1--6.

> [!IMPORTANT]
> **Note:** We strongly recommend that you use our [Tink library](https://github.com/google/tink). It handles the decryption process outlined in steps 1--6, so it's unnecessary for you to write your own implementation. This outline is provided mainly for reference. If you only want code to decrypt the token, see the [Use the Tink library to manage the encrypted response](https://developers.google.com/pay/api/web/guides/resources/payment-data-cryptography#using-tink) section instead.

## Payment method token structure

The message returned by Google in the `PaymentData` response is a UTF-8 encoded,
serialized JSON object with the keys specified in the following table:

> [!NOTE]
> **Note:** When base64 encoding is mentioned in this guide, it refers to standard base64 encoding ([RFC 4648](https://tools.ietf.org/html/rfc4648)), padded and not line wrapped.

| Name | Type | Description |
|---|---|---|
| `protocolVersion` | String | Identifies the encryption or signing scheme under which the message is created. It allows the protocol to evolve over time, if needed. |
| `signature` | String | Verifies that the message came from Google. It's base64-encoded, and created with ECDSA by the intermediate signing key. |
| `intermediateSigningKey` | Object | A JSON object that contains the intermediate signing key from Google. It contains the `signedKey` with `keyValue`, `keyExpiration`, and `signatures`. It's serialized to simplify the intermediate signing key signature verification process. |
| `signedMessage` | String | A JSON object serialized as an HTML-safe string that contains the `encryptedMessage`, `ephemeralPublicKey`, and `tag`. It's serialized to simplify the signature verification process. |

### Example

The following is a payment method token response in JSON:

```javascript
{
  "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\"}"
}
```

## Intermediate signing key

The `intermediateSigningKey` is a UTF-8 encoded, serialized JSON object that contains
the following values:

| Name | Type | Description |
|---|---|---|
| `signedKey` | String | A base64-encoded message that contains payment description of the key. |
| `signatures` | String | Verifies that the intermediate signing key came from Google. It's base64-encoded, and created with ECDSA. |

## Signed key

The `signedKey` is a UTF-8 encoded, serialized JSON object that contains the
following values:

| Name | Type | Description |
|---|---|---|
| `keyValue` | String | A base64 version of key encoded in ASN.1 type. `SubjectPublicKeyInfo` is defined in the X.509 standard. |
| `keyExpiration` | String | Date and time when the intermediate key expires as UTC milliseconds since epoch. Integrators reject any key that's expired. |

## Signed message

The `signedMessage` is a UTF-8 encoded, serialized JSON object that contains the
following values:

| Name | Type | Description |
|---|---|---|
| `encryptedMessage` | String | A base64-encoded encrypted message that contains payment information and some additional [security fields](https://developers.google.com/pay/api/web/guides/resources/payment-data-cryptography#encrypted-message). |
| `ephemeralPublicKey` | String | A base64-encoded ephemeral public key associated with the private key to encrypt the message in uncompressed point format. For more information, see [Encryption public key format](https://developers.google.com/pay/api/web/guides/resources/payment-data-cryptography#public-key-format). |
| `tag` | String | A base64-encoded MAC of `encryptedMessage`. |

## Encrypted message

The decrypted `encryptedMessage` is a UTF-8 encoded, serialized JSON object. The
JSON contains two levels. The outer level contains metadata and fields included for security, while
the inner level is another JSON object that represents the actual payment credential.

For more details about `encryptedMessage`, see the following tables and
JSON object examples:

| Name | Type | Description |
|---|---|---|
| `messageExpiration` | String | Date and time at which the message expires as UTC milliseconds since epoch. Integrators should reject any message that's expired. |
| `messageId` | String | A unique ID that identifies the message in case it needs to be revoked or located at a later time. |
| `paymentMethod` | String | The type of the payment credential. Currently, only `CARD` is supported. |
| `paymentMethodDetails` | Object | The payment credential itself. The format of this object is determined by the `paymentMethod` and is described in the following tables. |

### Card

The following properties make up a payment credential for the `CARD` payment method:

| Name | Type | Description |
|---|---|---|
| `pan` | String | The personal account number charged. This string contains only digits. |
| `expirationMonth` | Number | The expiration month of the card, where 1 represents January, 2 represents February, and so on. |
| `expirationYear` | Number | The four-digit expiration year of the card, such as 2020. |
| `authMethod` | String | The authentication method of the card transaction. |
| `merchantTokenId` | String | The merchant token ID of the card transaction. This optional field is only returned if all of the following conditions are met: - Merchant specifies a MIT `*TransactionInfo` object in the request. - Merchant includes a `tokenUpdateUrl` in the request. - The user selects a tokenized instrument (e.g., DPAN). |

#### `PAN_ONLY`

The following JSON snippet is an example of the full `encryptedMessage` for a
`CARD` `paymentMethod`

with a `PAN_ONLY` `authMethod`.

```javascript
{
  "paymentMethod": "CARD",
  "paymentMethodDetails": {
    "authMethod": "PAN_ONLY",
    "pan": "1111222233334444",
    "expirationMonth": 10,
    "expirationYear": 2025
  },
  "gatewayMerchantId": "some-merchant-id",
  "messageId": "some-message-id",
  "messageExpiration": "1759309000000"
}
```

#### `CRYPTOGRAM_3DS`

A `CARD` authenticated with the use of a 3-D Secure cryptogram,
`CRYPTOGRAM_3DS` `authMethod`. It includes the following additional
fields:

| Name | Type | Description |
|---|---|---|
| `cryptogram` | String | A 3-D Secure cryptogram. |
| `eciIndicator` | String | This string isn't always present. It returns only for authenticated device tokens transactions on Android (CRYPTOGRAM_3DS). This value must be passed down the payment processing flow. |

The following JSON snippet is an example of the full `encryptedMessage` for a
`CARD` `paymentMethod` with a
`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

The card network might provide the `eciIndicator` for authenticated device tokens transactions (CRYPTOGRAM_3DS).

You must pass the `eciIndicator` value on the authorization transaction without it being altered or hardcoded; otherwise, the transaction fails. The following table details the values of the `eciIndicator`.

| eciIndicator value | Card Network | Liable Party | authMethod |
|---|---|---|---|
| `""(empty)` | Mastercard | Merchant/Acquirer | CRYPTOGRAM_3DS |
| `02` | Mastercard | Card issuer | CRYPTOGRAM_3DS |
| `06` | Mastercard | Merchant/Acquirer | CRYPTOGRAM_3DS |
| `05` | Visa | Card issuer | CRYPTOGRAM_3DS |
| `07` | Visa | Merchant/Acquirer | CRYPTOGRAM_3DS |
| `""(empty)` | Other networks | Merchant/Acquirer | CRYPTOGRAM_3DS |

Any other ECI values for VISA and Mastercard that aren't present in this table won't be returned.

## Signature verification

To verify the signatures, which include the intermediate key and message signatures, the
following items are required:

- The algorithm used to create the signature
- The byte-string used to create the signature
- The public key that corresponds to the private one used to create the signature
- The signature itself

### The signature algorithm

Google uses the Elliptic Curve Digital Signature Algorithm ([ECDSA](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm))
to sign the messages with the following parameters: ECDSA over NIST P-256 with SHA-256 as the hash
function, as defined in FIPS 186-4.

### The signature

The signature is included in the outermost level of the message. It's encoded with base64 in
ASN.1 byte format. For more information on ASN.1, see
[IETF Tools Appendix A](https://tools.ietf.org/html/rfc5480#appendix-A).
The signature consists of the ECDSA [integers r and s](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm#Signature_generation_algorithm). For more information, see
[Signature generation algorithm](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm#Signature_generation_algorithm).

The following is an example of the specified ASN.1 byte format, which is the standard format
produced by Java Cryptography Extension (JCE) ECDSA implementations.

```
ECDSA-Sig-Value :: = SEQUENCE {
 r INTEGER,
 s INTEGER
}
```

### How to construct the byte-string for intermediate signing key signature

To validate the intermediate signing key signature in the sample payment method token, construct
the `signedStringForIntermediateSigningKeySignature` with the following formula:

```
signedStringForIntermediateSigningKeySignature =
length_of_sender_id || sender_id || length_of_protocol_version || protocol_version || length_of_signed_key || signed_key
```

The "\|\|" notation means concatenate. Each component---`sender_id`,
`protocolVersion`, `signedKey`---must be UTF-8 encoded. The
`signedKey` must be the string of `intermediateSigningKey.signedKey`.
The byte length of each component is 4 bytes in little-endian format.

#### Example

This example uses the following sample payment method token:

```
{
  "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\"}"
}
```

The `sender_id` is always `Google` and the `protocol_version` is
`ECv2`.

If the `sender_id` is `Google`, the `signedString` appears as
shown in the following example:

```
signedStringForIntermediateSigningKeySignature =
\x06\x00\x00\x00 || Google || | \x04\x00\x00\x00 || ECv2 || \xb5\x00\x00\x00 || {"keyExpiration":"1542323393147","keyValue":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/1+3HBVSbdv+j7NaArdgMyoSAM43yRydzqdg1TxodSzA96Dj4Mc1EiKroxxunavVIvdxGnJeFViTzFvzFRxyCw\u003d\u003d"}
```

### How to verify the signature on signedStringForIntermediateSigningKeySignature

The standard ECDSA verification algorithm is used when the signed string for the intermediate
signing key signature is assembled. For ECv2 protocol, you need to iterate over all the signatures
in `intermediateSigningKey.signatures` and try to validate each one with the
non-expired Google signing keys in `keys.json`. If at least one signature validation
works, consider the verification complete. Use the
`intermediateSigningKey.signedKey.keyValue` later to verify the
`signedStringForMessageSignature`. Google strongly recommends you use a cryptographic
library that exists rather than your own verification code.

### How to construct the byte-string for message signature

To validate the signature in the sample payment method token, construct the
`signedStringForMessageSignature` with the following formula:

```
signedStringForMessageSignature =
length_of_sender_id || sender_id || length_of_recipient_id || recipient_id || length_of_protocolVersion || protocolVersion || length_of_signedMessage || signedMessage
```

The "\|\|" notation means concatenate. Each component---`sender_id`,
`recipient_id`, `protocolVersion`, `signedMessage`---must be UTF-8
encoded. The byte length of each component is 4 bytes in little-endian format. When you construct
the byte string, don't parse or modify `signedMessage`. For example, don't replace
`\u003d` with the `=` character.

#### Example

The following example is a sample payment method token:

```
{
  "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\"}"
}
```

The `sender_id` is always `Google` and the `recipient_id` is
`merchant:merchantId`. The `merchantId` matches the value found in
the [Google Pay \& Wallet Console](https://pay.google.com/business/console?utm_source=devsite&utm_medium=devsite&utm_campaign=devsite) for merchants with production access.

If the `sender_id` is `Google` and the `recipient_id`
is `merchant:12345`, the `signedString` appears as it is in the following
example:

```
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"}
```

### How to verify the signature on signedStringForMessageSignature

The standard ECDSA verification algorithm is used when the signed string is assembled. The
`intermediateSigningKey.signedKey.keyValue` verified in the previous step is used to
verify the `signedMessage`. Google strongly recommends you use a cryptographic
library that exists rather than your own verification code.

## Encryption scheme specification

Google uses the Elliptic Curve Integrated Encryption Scheme ([ECIES](https://en.wikipedia.org/wiki/Integrated_Encryption_Scheme)) to secure
the payment method token returned in the Google Pay API response. The encryption scheme uses the
following parameters:

| Parameter | Definition |
|---|---|
| Key encapsulation method | ECIES-KEM, as defined in [ISO 18033-2](https://www.iso.org/standard/37971.html). - Elliptic curve: NIST P-256 (also known in OpenSSL as prime256v1). - `CheckMode`, `OldCofactorMode`, `SingleHashMode`, and `CofactorMode` are 0. - Point format is uncompressed. |
| Key derivation function | HMAC-based with SHA-256 (`HKDFwithSHA256`). - Salt must not be provided. - Information must be `"Google"`, encoded in ASCII for protocol version `ECv2`. - 256 bits must be derived for the `AES256` key and another 256 bits must be derived for the `HMAC_SHA256` key. |
| Symmetric encryption algorithm | DEM2, as defined in [ISO 18033-2](https://www.iso.org/standard/37971.html) Encryption algorithm: AES-256-CTR with zero IV and not padded. |
| MAC algorithm | `HMAC_SHA256` with a 256-bit key as derived from the key derivation function. |

### Encryption public key format

The encryption public key and the `ephemeralPublicKey` returned in Google payloads are
formatted with the base64 representation of the key in uncompressed point format. It consists of
the following two elements:

- One magic number that specifies the format (0x04).
- Two 32-byte large integers that represent the X and Y coordinates in the Elliptic Curve.

This format is described in more detail in "Public Key Cryptography For The Financial Services
Industry: The Elliptic Curve Digital Signature Algorithm (ECDSA)," ANSI X9.62, 1998.

## Use OpenSSL to generate a public key

### Step 1: Generate a private key

The following example generates an Elliptic Curve private key suitable for use with NIST P-256
and writes it to `key.pem`:

```
openssl ecparam -name prime256v1 -genkey -noout -out key.pem
```

### Optional: View the private and public keys

Use the following command to view both the private and public key:

```
openssl ec -in key.pem -pubout -text -noout
```

The command produces an output similar to the following:

```
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
```

### Step 2: Generate a base64-encoded public key

The private and public key that's generated in the previous [optional step](https://developers.google.com/pay/api/processors/guides/implementation/generate-keys#optional)
example is hexadecimal-encoded. To get a base64-encoded public key in uncompressed point format,
use the following command:

```
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
```

The command produces a `publicKey.txt` file whose content, the base64 version of the
key in uncompressed point format, resembles the following:

```
BOdoXP+9Aq473SnGwg3JU1aiNpsd9vH2ognq4PtDtlLGa3Kj8TPf+jaQNPyDSkh3JUhiS0KyrrlWhAgNZKHYF2Y=
```

The file content must not have extra empty spaces or carriage returns. To verify this, run the
following command in Linux or MacOS:

```
od -bc publicKey.txt
```

### Step 3: Generate a base64-encoded private key in PKCS #8 format

The Tink library expects your private key to be base64-encoded in PKCS #8 format. Use the
following command to generate the private key in this format from the private key generated in
the first step:

```
openssl pkcs8 -topk8 -inform PEM -outform DER -in key.pem -nocrypt | base64 | paste -sd "\0" -
```

The command produces an output similar to the following:

```
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgWV4oK8c/MZkCLk4qSCNjW0Zm6H0CBCtSYxkXkC9FBHehRANCAAQPldOnhO2/oXjdJD1dwlFPiNs6fcdoRgFu3/Z0iKj24SjTGyLRGAtYWLGXBZcDdPj3T2bJRHRVhE8Bc2AjkT7n
```

> [!CAUTION]
> **Important:** Always protect your private keys against unauthorized disclosure. Ensure your private keys are always protected and stored securely. Never hard-code or embed keys in your production code.

## How to decrypt the payment method token

Follow these steps to decrypt the token:

1. Use your private key and the given `ephemeralPublicKey` to derive a 512-bit long shared key that uses [ECIES-KEM](https://www.iso.org/standard/37971.html). Use the following parameters:
   - Elliptic curve: NIST P-256, also known in OpenSSL as prime256v1.
   - `CheckMode`, `OldCofactorMode`, `SingleHashMode`, and `CofactorMode` are `0`.
   - Encoding function: Uncompressed point format.
   - Key derivation function: HKDFwithSHA256, as described in [RFC 5869](https://tools.ietf.org/html/rfc5869), with the following parameter:
     - Salt must not be provided. Per the RFC, this must be equivalent to a salt of 32 zeroed bytes.
2. Split the generated key into two 256-bit-long keys: `symmetricEncryptionKey` and `macKey`.
3. Verify that the `tag` field is a valid MAC for `encryptedMessage`.

   To generate the expected MAC, use HMAC ([RFC 5869](https://tools.ietf.org/html/rfc5869)) with hash function SHA256 and
   the `macKey` obtained in Step 2.

   > [!NOTE]
   > **Note:** Remember to use a constant time array comparison to avoid timing attacks.

4. Decrypt `encryptedMessage` with the use of AES-256-CTR mode, and with the
   following:

   - A zero IV.
   - Not padded.
   - The `symmetricEncryptionKey` derived in Step 2.

## Key management

### Merchant encryption keys

Merchants generate a public key as per the specifications outlined in
[Encryption scheme specification](https://developers.google.com/pay/api/web/guides/resources/payment-data-cryptography#encrypt-spec).

> [!NOTE]
> **Note:** Merchants are expected to submit updated PCI documentation and rotate encryption keys once a year in the [Google Pay \& Wallet Console](https://pay.google.com/business/console?utm_source=devsite&utm_medium=devsite&utm_campaign=devsite). If the merchant doesn't rotate their keys, Google might stop fulfillment requests made to the Google Pay API for that merchant.

### Google root signing keys

> [!NOTE]
> **Note:** Details on how to fetch, parse, and manage Google signing keys are implemented in the [Tink paymentmethodtoken library](https://github.com/tink-crypto/tink-java-apps). This library is only available in Java. For more information, see [Use the Tink paymentmethodtoken library](https://developers.google.com/pay/api/processors/guides/implementation/using-tink).


Google publishes the set of currently valid root signing public keys that are fetchable from a
public URL. The keys are valid for as long as the HTTP cache headers that are returned by the URL
indicate. They're cached until they expire, which is determined by the *keyExpiration*
field. We recommend that when a fetch expires, fetch the keys from the public URL again to
receive the current list of valid keys.

Exception for ECv2 protocol: If you can't fetch the keys from Google at runtime, fetch the
`keys.json` from our production URL, save it into your system, and periodically refresh
manually. Under normal circumstances, Google issues a new root signing key for ECv2 five years
before the key with the longest expiration date expires. In case of key compromises, Google
notifies all merchants through the contact information provided in the self-service portal in
order to request a quicker reload of `keys.json`. To make sure you don't miss the
regular rotation, we recommend that merchants who choose to save Google keys in the contents of
`keys.json` refresh annually as part of their own annual key rotation.

The keys provided through the public URL are mapped in the following format:

```javascript
{
  "keys": [
    {
      "keyValue": "encoded public key",
      "protocolVersion": "ECv2"
      "keyExpiration":"2000000000000"
    },
    {
      "keyValue": "encoded public key",
      "protocolVersion": "ECv2"
      "keyExpiration":"3000000000000"
    }
  ]
}
```

The `keyValue` is a base64, not wrapped or padded, version of the key encoded in ASN.1
type `SubjectPublicKeyInfo` defined in the X.509 standard. In Java, the referred ASN.1
encoding is represented by the
[X509EncodedKeySpec class](https://docs.oracle.com/javase/7/docs/api/java/security/spec/X509EncodedKeySpec.html).
It can be obtained with `ECPublicKey.getEncoded()`.

URLs for both test and production environments are provided by the following links:

- Test: [`https://payments.developers.google.com/paymentmethodtoken/test/keys.json`](https://payments.developers.google.com/paymentmethodtoken/test/keys.json)
- Production: [`https://payments.developers.google.com/paymentmethodtoken/keys.json`](https://payments.developers.google.com/paymentmethodtoken/keys.json)

> [!CAUTION]
> **Caution:** For development purposes, use the test URL.

### Key rotation

If you decrypt a payment method token directly on your servers with direct integration, then you
must rotate the keys annually.

Complete the following steps to rotate encryption keys:

1. [Use OpenSSL to generate a new key pair](https://developers.google.com/pay/api/web/guides/resources/payment-data-cryptography#using-openssl).
2. Open the [Google Pay \& Wallet Console](https://pay.google.com/business/console?utm_source=devsite&utm_medium=devsite&utm_campaign=devsite) while signed in with the Google Account that you previously used to sign up as a developer for Google Pay.
3. In the **Google Pay API** tab, under the **Direct integration** pane, click **Manage** next to your existing public key. Click **Add another key**.
4. Select the **Public encryption key** text input field and add your newly generated public key base64-encoded in uncompressed point format.
5. Click **Save encryption keys**.
6. To ensure a seamless key rotation, support both the new and old private keys
   decryption while you transition the keys.

   If you use the [Tink library](https://github.com/google/tink)
   to decrypt the token, use the following Java code to support multiple private keys:

   ```java
   String decryptedMessage =
       new PaymentMethodTokenRecipient.Builder()
           .addRecipientPrivateKey(newPrivateKey)
           .addRecipientPrivateKey(oldPrivateKey);
   ```

   Make sure that the code for decryption is deployed to production and that you monitor
   successful decryptions.

   > [!NOTE]
   > **Note:** For performance reasons, make the new private key the first key added to the builder.

7. Change the public key used in your code.

   Replace the value of the `publicKey` attribute in the
   `PaymentMethodTokenizationSpecification` `parameters` property:

   ```javascript
   const tokenizationSpecification = {
     "type": "DIRECT",
     "parameters": {
       "protocolVersion": "ECv2",
       "publicKey": "BOdoXP1aiNp.....kh3JUhiSZKHYF2Y="
     }
   }
   ```

   > [!NOTE]
   > **Note:** Test the decryption with the new private key to make sure it works as expected.

8. Deploy the code from step 4 to production. Once the code is deployed, encryption and decryption transactions use the new key pairs.
9. Confirm that the old public key is no longer used to encrypt any transactions.

   > [!CAUTION]
   > **Caution:** You must support the old private key for decryption of payment methods for eight days after you remove the old public key.

10. Remove the old private key.
11. Open the [Google Pay \& Wallet Console](https://pay.google.com/business/console?utm_source=devsite&utm_medium=devsite&utm_campaign=devsite) while signed in with the Google Account that you previously used to sign up as a developer with Google Pay.
12. In the **Google Pay API** tab, under the **Direct integration** pane, click **Manage** next to your existing public key. Click **Delete** next to your old public key and click **Save encryption keys**.

> [!NOTE]
> **Note** : Updated PCI documentation is also required during key rotation. PCI documentation can be uploaded in the same **Direct integration** pane in the [Google Pay \& Wallet Console](https://pay.google.com/business/console?utm_source=devsite&utm_medium=devsite&utm_campaign=devsite) for review.

Google uses the key specified in the `publicKey` property within
`PaymentMethodTokenizationSpecification` `parameters` object, as shown
in the following example:

```
{
  "protocolVersion": "ECv2",
  "publicKey": "BOdoXP+9Aq473SnGwg3JU1..."
}
```

## Use the
[Tink library](https://github.com/google/tink) to manage the encrypted
response

> [!NOTE]
> **Note:** We recommend that you use the [Tink paymentmethodtoken library](https://github.com/tink-crypto/tink-java-apps/blob/main/paymentmethodtoken/) to decrypt Google Pay tokens, as in [the paymentmethodtoken example library](https://github.com/tink-crypto/tink-java-apps/blob/main/paymentmethodtoken/src/test/java/com/google/crypto/tink/apps/paymentmethodtoken/ExampleTest.java).

To perform signature verification and message decryption, use the
[Tink paymentmethodtoken library](https://github.com/tink-crypto/tink-java-apps).
This library is only available in Java. To use it, complete the following steps:

1. In your `pom.xml`, add the Tink `paymentmethodtoken` app
   as a dependency:

   ```
   <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. At server startup, prefetch the Google signing keys to make the key available in memory.
   This prevents a user view of any network latency while the
   decryption process fetches the keys.

   ```
   GooglePaymentsPublicKeysManager.INSTANCE_PRODUCTION.refreshInBackground();
   ```

   > [!NOTE]
   > **Note:** This step is optional, but is a highly recommended performance optimization.

3. Decrypt the message with the following code, which assumes `paymentMethodToken` is
   stored in the `encryptedMessage` variable, and replace the sections in bold in
   accordance with your scenario.

   For non-production tests, replace `INSTANCE_PRODUCTION` with
   `INSTANCE_TEST`, and if your integration is inactive or does not have an encryption
   key configured, replace <var translate="no">\[YOUR MERCHANT ID\]</var> with
   `12345678901234567890`.
   - Active
   - Has DIRECT integration enabled
   - Has an encryption key configured

   don't replace <var translate="no">\[YOUR MERCHANT ID\]</var>.

   ```
   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. Replace `PrivateKey1` with the appropriate private key value that associates with
   the registered public key value with Google from [Prepare your keys and register with Google](https://developers.google.com/pay/api/processors/guides/implementation/prepare-your-key). You can add multiple other private key values later on when it
   requires you to [Rotate keys with Google](https://developers.google.com/pay/api/processors/guides/implementation/rotate-keys-with). The variables can be either a
   base64-encoded PKCS8 string or an `ECPrivateKey` object. For more information on how to produce a
   base64-encoded PKCS8 private key, see [Prepare your keys and register with Google](https://developers.google.com/pay/api/processors/guides/implementation/prepare-your-key).

5. If you aren't able to call a Google server every time you decrypt keys, decrypt with the
   following code and replace the sections in bold in accordance with your 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);
   ```

   The current key in the production environment is valid until 04/14/2038 under normal
   circumstances except key compromises. In case of key compromises, Google notifies all merchants
   through the contact information provided in the self-service portal in order to request a quicker
   reload of `keys.json`.

   The code snippet handles the following security details so you can focus on the consumption
   of the payload:
   - Google signing keys fetched and cached in memory
   - Signature verification
   - Decryption