Documentation
¶
Overview ¶
Package t2t decodes the NFC Forum Type 2 Tag structure — the page layout shared by NXP NTAG21x and MIFARE Ultralight, by far the most common NFC tags (transit, access fobs, amiibo, marketing tags). It interprets a page-aligned memory dump's header: the 7-byte UID with its BCC check bytes, the static lock bytes, and the Capability Container.
Wrap-vs-native judgement ¶
Native. The Type 2 Tag layout is a public NFC Forum standard (Type 2 Tag Operation Specification) reproduced in every NTAG/Ultralight datasheet and in libnfc / the Flipper NFC stack: pages are 4 bytes, page 0-2 hold the 7-byte UID + BCC0/BCC1 + internal + static lock bytes, and page 3 is the Capability Container. Decoding is a fixed-offset read with a hand-computable XOR checksum (the BCC bytes) — no crypto, no hardware, no card present at decode time (the operator pastes a dump from nfc_mfu_rdbl / a Flipper .nfc / libnfc). It is distinct from the mifare package (MIFARE Classic) and from ndef (the NDEF message inside the user pages): this is the tag-structure layer.
Verifiable ¶
The UID carries two XOR check bytes that gate correctness without a card:
BCC0 = 0x88 (cascade tag) XOR UID0 XOR UID1 XOR UID2 (page 0, byte 3) BCC1 = UID3 XOR UID4 XOR UID5 XOR UID6 (page 2, byte 0)
Both are validated and surfaced; a mismatch is flagged (a misread, or a non-7-byte-UID tag) rather than silently trusted.
Configuration pages (NTAG21x) ¶
When the dump size exactly matches an NTAG213/215/216 (45/135/231 pages), the configuration pages (CFG0 / CFG1 / PWD / PACK) are decoded into the password-protection posture: AUTH0 (first page requiring authentication), PROT (read+write vs write-only protection), AUTHLIM (failed-auth lockout), and CFGLCK (config permanently locked). Their location is derived STRUCTURALLY — the config pages are always the last four pages on every NTAG21x — so no per-variant page table is guessed, and decoding only runs when the size uniquely identifies an NTAG21x. The Ultralight EV1 variants (different config layout) and the NDEF message in the user pages (decoded by ndef_decode) are deliberately not covered here.
Index ¶
Constants ¶
const CascadeTag = 0x88
CascadeTag is the 0x88 prefix XORed into BCC0 for a double-size (7-byte) UID.
const DefaultInternal = 0x48
DefaultInternal is the page-2 "internal" byte NXP Ultralight/NTAG tags ship with (0x48); it has no functional meaning to a reader.
Variables ¶
This section is empty.
Functions ¶
func EncodeHeader ¶ added in v0.410.0
func EncodeHeader(r EncodeRequest) ([]byte, error)
EncodeHeader builds the first four pages (16 bytes) of an NFC Forum Type 2 Tag — the inverse of Decode's header parse. It computes the two UID BCC check bytes (BCC0 = 0x88 XOR UID0..2, BCC1 = UID3..6), lays out the UID, internal byte, static lock bytes, and Capability Container, and returns the 16-byte header. This is the clone-prep step for writing a chosen UID to a UID-rewritable ("magic") NTAG / Ultralight: the BCCs are filled in so the tag passes a reader's UID-integrity check. Generation only — it touches no card.
Wrap-vs-native judgement ¶
Native, and the exact inverse of Decode: it reuses the same BCC formula, so the two are guaranteed consistent. Pure byte assembly over the public NFC Forum Type 2 layout, no crypto, no hardware. Correctness is verifiable two ways: round-trip against Decode (BCCs validate) and the hand-computed BCC vector (UID 04 11 22 33 44 55 66 -> BCC0 0xBF, BCC1 0x44).
Types ¶
type CapabilityContainer ¶
type CapabilityContainer struct {
Hex string `json:"hex"`
MagicValid bool `json:"magic_valid"` // CC0 == 0xE1 (NDEF-formatted)
Version string `json:"version"` // e.g. "1.0"
SizeBytes int `json:"size_bytes"` // CC2 * 8
ReadAccess string `json:"read_access"`
WriteAccess string `json:"write_access"`
}
CapabilityContainer is the decoded view of page 3.
type EncodeRequest ¶ added in v0.410.0
type EncodeRequest struct {
// UID is the 7-byte device UID as hex (required). The two BCC check
// bytes are computed from it.
UID string
// Internal is the page-2 internal byte (defaults to 0x48).
Internal byte
// Lock0, Lock1 are the page-2 static lock bytes (default 0x00 = unlocked).
Lock0, Lock1 byte
// CC is the 4-byte Capability Container (page 3) as hex. Defaults to
// "E1101200" (NDEF-formatted, v1.0, 144-byte, free access) — override to
// replicate a specific tag's CC.
CC string
}
EncodeRequest describes the Type 2 Tag header pages to build.
type NTAGConfig ¶ added in v0.405.0
type NTAGConfig struct {
CFG0Hex string `json:"cfg0_hex"`
CFG1Hex string `json:"cfg1_hex"`
PWDHex string `json:"pwd_hex"`
PACKHex string `json:"pack_hex"`
AUTH0 int `json:"auth0"` // first page requiring password auth
ProtectedFrom string `json:"protected_from"` // human summary of the protected range
ProtectMode string `json:"protect_mode"` // "write only" | "read and write"
AuthLimit int `json:"auth_limit"` // failed-auth attempts before lockout (0 = unlimited)
ConfigLocked bool `json:"config_locked"` // CFGLCK: config pages permanently locked
}
NTAGConfig is the decoded NTAG21x configuration (the last four pages: CFG0, CFG1, PWD, PACK) — the password-protection security posture.
type T2T ¶
type T2T struct {
Pages int `json:"pages"`
UID string `json:"uid"` // 7-byte UID, hex
BCC0 string `json:"bcc0"` // captured page0[3]
BCC0Valid bool `json:"bcc0_valid"`
BCC1 string `json:"bcc1"` // captured page2[0]
BCC1Valid bool `json:"bcc1_valid"`
Internal string `json:"internal"` // page2[1]
LockBytes string `json:"lock_bytes"` // page2[2..3]
LockedPages []int `json:"locked_pages"`
BlockLocks []string `json:"block_locking,omitempty"`
CC CapabilityContainer `json:"capability_container"`
Model string `json:"model,omitempty"` // NTAG213/215/216 when the dump size matches
Config *NTAGConfig `json:"config,omitempty"` // NTAG21x password-protection config
Notes []string `json:"notes,omitempty"`
}
T2T is the decoded Type 2 Tag structure.
type TLVBlock ¶ added in v0.467.0
type TLVBlock struct {
Type string `json:"type"`
TypeRaw int `json:"type_raw"`
Offset int `json:"offset"`
Length int `json:"length"`
ValueHex string `json:"value_hex,omitempty"`
NDEF *ndef.Message `json:"ndef,omitempty"`
}
TLVBlock is one decoded TLV block from the Type 2 Tag data area.
type TLVResult ¶ added in v0.467.0
TLVResult is the decoded TLV-block sequence.
func DecodeTLV ¶ added in v0.467.0
DecodeTLV walks the TLV blocks of a Type 2 Tag data area. A length that runs past the buffer ends the walk with a note (partial blocks are still reported); the NDEF Message TLV's value is decoded via internal/ndef.
func DecodeTLVHex ¶ added in v0.467.0
DecodeTLVHex decodes a hex-encoded Type 2 Tag data area (the user memory from page 4 onward — use DecodeDump / nfc_t2t for the page 0-3 header). ':' / '-' / '_' / whitespace separators are ignored.