All Tools
Tools/ARQC / ARPC Calculator
🧮
Card SecurityBeta

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.

1 / 6
🧾
Transaction Dataamount, ATC, UN…
🗝️
Derive UDK
🔑
Session Key
🧱
Build Block
🔐
ARQC = MAC
↩️
ARPC

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.

</> Code Implementation
# 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}")