Documentation
¶
Overview ¶
Package emv decodes EMV BER-TLV structures from contactless and contact payment card APDU responses. Pure offline parser — no hardware, no network — so the same code paths run in unit tests and in any host-side tooling that consumes captured EMV data (saved NFC reads, debugger transcripts, EMV Co specification examples).
Wrap-vs-native judgement: EMV BER-TLV is a well-documented public format (EMV Book 3 §B Annex B). The walker is ~100 lines of bit-twiddling over a byte slice. Wrapping a FAP for this would add an SD-card install step + a firmware-fork dependency for what is, ultimately, a recursive descent parser. We implement natively here so operators can decode an EMV transcript they pasted from a forum post without a Flipper attached.
What this package covers:
- BER-TLV walker with multi-byte tag + length support
- Constructed vs primitive recognition (per the BER class+P/C bit)
- Curated tag-name table for the ~80 most-common EMV tags
What this package does NOT cover (deliberately out of scope):
- Cryptogram verification (Application Cryptogram derivation, CDA, DDA — these need issuer public keys we don't have)
- Online authorisation flow (issuer scripting, ARPC)
- TLV write / re-encode (round-tripping a tree back to bytes — happy to add if a caller materialises)
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type TLV ¶
type TLV struct {
// Tag is the BER tag as a uint32 — the encoded big-endian bytes
// of the tag identifier. Single-byte tags use the low byte;
// multi-byte tags pack into successively higher bytes (so 0x9F02
// is the most common Amount Authorised tag, 0x5F2A is the
// Transaction Currency Code, etc.). Stored as uint32 so the
// tag-name lookup map can key on it without a string conversion.
Tag uint32 `json:"tag"`
// TagHex is the operator-facing rendering of Tag — always
// uppercase, no 0x prefix, no leading zeros. Matches the format
// every EMV book / forum post uses ("9F02", "5F2A").
TagHex string `json:"tag_hex"`
// Name is the canonical EMV name for the tag, or "" when the
// tag isn't in the curated lookup table.
Name string `json:"name,omitempty"`
// Constructed reports whether the value bytes contain nested
// TLVs (per BER class+P/C bit). When true, Children holds the
// parsed sub-tree and Value is the raw bytes (kept for callers
// that want to re-emit the original structure).
Constructed bool `json:"constructed"`
Value []byte `json:"value,omitempty"`
// ValueHex is the operator-facing hex rendering of Value.
// Convenient for JSON output without forcing every caller to
// re-encode.
ValueHex string `json:"value_hex,omitempty"`
// Children is non-nil iff Constructed is true. May be empty
// when a constructed tag's body is zero-length (legal per the
// spec, occasionally seen in templated responses).
Children []TLV `json:"children,omitempty"`
}
TLV is one decoded BER-TLV entry. Constructed entries carry their child TLVs in Children; primitive entries carry the raw value bytes in Value (Children is nil).
func Parse ¶
Parse decodes a hex-encoded EMV BER-TLV blob (the common form operator-supplied EMV captures take) into a flat list of top-level TLVs. Constructed tags are walked recursively into each TLV's Children. Returns an error on malformed input (truncated tag/length, length-exceeds-buffer, length-encoding reserved value).
func ParseBytes ¶
ParseBytes is the byte-slice variant of Parse for callers that already have raw EMV bytes (e.g. from a PC/SC reader). Same recursive walker; same error contract.