All Tools
Tools/EMV TLV Decoder
🔓
EMV & ChipAvailable

EMV TLV Decoder

Decode TLV-encoded hex bytes (e.g. from DE55 / tag 77 response) into a structured, annotated list of EMV tag/length/value records with descriptions.

Follows EMV Book 34.4·verified Oct 2026· double-checked Oct 2026— Annex B BER-TLV (lengths 81/82/83, 00 padding; FF skips reported); values per Annex A1, Book 4 and ISO 4217 / 3166-1; 10,000 trees match an independent decoder and proxmark3

Try it as a puzzle: route a chip payment to the card’s bank →

Examples:
</> Code Implementation
# BER-TLV Parser — decode EMV tag-length-value structures
# No external dependencies required

def parse_tlv(hex_str: str) -> list:
    data = bytes.fromhex(hex_str.replace(" ", ""))
    results, i = [], 0
    while i < len(data):
        # Padding: 00 (EMV Book 3 Annex B) or FF (ISO/IEC 7816-4), but not the FF of a
        # Kernel 2 FF81xx tag
        if data[i] == 0x00 or (data[i] == 0xFF and data[i + 1:i + 2] != b"\x81"):
            i += 1; continue
        # Tag: more bytes follow while b8 is set (first byte: if b5-b1 = 11111)
        start = i
        i += 1
        if (data[start] & 0x1F) == 0x1F:
            while data[i] & 0x80: i += 1
            i += 1
        tag_hex = data[start:i].hex().upper()
        # Length
        l = data[i]; i += 1
        if l & 0x80:                        # long form
            n = l & 0x7F
            length = int.from_bytes(data[i:i+n], "big"); i += n
        else:
            length = l
        value = data[i:i+length]; i += length
        results.append({"tag": tag_hex, "length": length, "value": value.hex().upper()})
    return results

# Example
tlv = "9F02060000000025009A03260101"
for t in parse_tlv(tlv):
    print(f"Tag: {t['tag']}  Len: {t['length']:02d}  Value: {t['value']}")
# Tag: 9F02  Len: 06  Value: 000000002500
# Tag: 9A    Len: 03  Value: 260101
Something wrong or missing? Report a problem— we check reports against the specs and fix them.