Apple's own reference page for decrypting an Apple Pay token currently gets the key derivation wrong. The KDF table lists the hash function where the shared secret should be, and it has dropped the id-aes256-GCM algorithm ID bytes altogether; the archived version of the same page has the correct values. If you are building a decryptor from the live docs, you will get a key that never opens the ciphertext, and nothing in the error will tell you why.
That is the level most "decrypt Apple Pay token" guides stop above. They show you a library call, or a PSP's CSR upload screen, and move on. This guide covers the actual formats for Apple Pay (EC_v1 and RSA_v1) and Google Pay (ECv2), the signature checks people skip, the certificate rotation rules that cause outages, and the more important question: whether you should be decrypting at all.
What Is Inside an Apple Pay Payment Token?
When the payment sheet completes, PKPayment.token.paymentData (or the ApplePayPaymentToken on the web) hands you a JSON object with four keys:
{
"version": "EC_v1",
"data": "<base64 ciphertext>",
"signature": "<base64 detached PKCS #7>",
"header": {
"ephemeralPublicKey": "<base64 X.509 key>",
"publicKeyHash": "<base64 SHA-256 of your cert's public key>",
"transactionId": "<hex, generated on device>",
"applicationData": "<hex SHA-256, optional>"
}
}
version is EC_v1 almost everywhere. Apple says other regions use RSA_v1 "if ECC encryption is unavailable due to regulatory concerns", and its March 2026 certificate technote (TN3206) makes the mapping clear without quite saying it: the Payment Processing CSR is a 256-bit ECC key globally and a 2048-bit RSA key for China mainland. An RSA_v1 header carries wrappedKey instead of ephemeralPublicKey.
publicKeyHash matters more than it looks. It is the only field that tells you which of your private keys the token was encrypted to, and you will need it during every certificate rotation.
How to Decrypt an Apple Pay Token (EC_v1)
The flow for EC_v1 is ECDH, then a single-pass NIST SP 800-56A concatenation KDF, then AES-GCM:
-
Select the key. Match
header.publicKeyHashagainst the SHA-256 of each Payment Processing certificate's public key you hold. -
Agree a secret. ECDH between your private key and
ephemeralPublicKey. Apple only says "256-bit ECC key pair"; every open-source decryptor treats it as P-256. -
Derive the key. SHA-256 over
counter (0x00000001) || Z || AlgorithmID || PartyUInfo || PartyVInfo, where:-
Zis the ECDH shared secret -
AlgorithmIDis the byte0x0Dfollowed by the ASCII stringid-aes256-GCM(the0x0Dis a length prefix: 13 characters) -
PartyUInfois the ASCII stringApple -
PartyVInfois the SHA-256 of your merchant identifier, either hashed from the UID in the certificate subject or hex-decoded from the extension at OID1.2.840.113635.100.6.32
-
-
Decrypt. AES-256-GCM over
data, IV of 16 zero bytes, no associated data. The last 16 bytes ofdataare the GCM tag.
Read the full article on tomcn.uk →
About the Author
I'm Tom Wang, an AI Developer & Fintech Developer — building AI agents, crypto payment infrastructure, and cross-border payout systems with Rust, Go, and TypeScript. Based in London, UK.
Currently open to new opportunities in fintech, crypto payments, and AI agent engineering.
Top comments (0)