ARQC / ARPC Calculator
Compute EMV Application Request Cryptograms (ARQC) and Application Response Cryptograms (ARPC) — supports CVN10 (no key derivation) and CVN18 (ATC-derived session key).
Use test data only. All calculations run locally in your browser — PayProbe never sees, transmits, or stores your PAN, CVV, keys, PINs, or cryptographic inputs. How we handle data →
How the cryptogram is computed
How an EMV Application Cryptogram is built. The card derives keys from an issuer master key and MACs the transaction data; the issuer validates it and returns an ARPC the card can verify in return.
1Transaction Data
CDOL1 elements
The inputs come from CDOL1: amount, terminal country, TVR, currency, date, transaction type, unpredictable number (UN), AIP, and the Application Transaction Counter (ATC).
Algorithm overview
ARQC = ISO 9797-1 Retail MAC (Alg 3) over transaction data using the session key.
CVN10: Session key = UDK directly.
CVN18: Session key derived using ATC as diversification data.
ARPC Method 1: TDES(ARQC ⊕ AuthRC, SK) where AuthRC is the 8-byte authorisation response code.
# EMV ARQC Calculator — CBC-MAC with 3DES (ISO 9797-1 Alg 3)
# Requires: pip install pycryptodome
from Crypto.Cipher import DES, DES3
def des3_encrypt(key: bytes, data: bytes) -> bytes:
key24 = key[:16] + key[:8]
return DES3.new(key24, DES3.MODE_ECB).encrypt(data)
def retail_mac(data: bytes, key: bytes) -> bytes:
"""ISO 9797-1 Alg 3 MAC: single-DES CBC then final 2TDEA."""
k1, k2 = key[:8], key[8:16]
pad_len = 8 - (len(data) % 8)
padded = data + bytes([0x80] + [0x00] * (pad_len - 1))
state = bytes(8)
for i in range(0, len(padded) - 8, 8):
block = padded[i:i+8]
state = DES.new(k1, DES.MODE_ECB).encrypt(
bytes(a ^ b for a, b in zip(state, block))
)
last = bytes(a ^ b for a, b in zip(state, padded[-8:]))
dec = DES.new(k2, DES.MODE_ECB).decrypt(last)
return DES.new(k1, DES.MODE_ECB).encrypt(dec)
def compute_arqc(udk_hex: str, tx_data_hex: str) -> str:
udk = bytes.fromhex(udk_hex)
data = bytes.fromhex(tx_data_hex)
return retail_mac(data, udk).hex().upper()
# Example (CVN10: UDK used directly as session key)
udk = "0123456789ABCDEF0123456789ABCDEF"
tx_data = "000000002500000000000000260101019F3704AABBCCDD"
arqc = compute_arqc(udk, tx_data)
print(f"ARQC: {arqc}")