t2t

package
v0.587.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 6, 2026 License: AGPL-3.0 Imports: 4 Imported by: 0

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

View Source
const CascadeTag = 0x88

CascadeTag is the 0x88 prefix XORed into BCC0 for a double-size (7-byte) UID.

View Source
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.

func Decode

func Decode(hexStr string) (*T2T, error)

Decode parses a hex-encoded Type 2 Tag memory dump. At least the first 4 pages (16 bytes) are required. Separators and a 0x prefix are tolerated.

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

type TLVResult struct {
	Blocks []TLVBlock `json:"blocks"`
	Notes  []string   `json:"notes,omitempty"`
}

TLVResult is the decoded TLV-block sequence.

func DecodeTLV added in v0.467.0

func DecodeTLV(b []byte) (*TLVResult, error)

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

func DecodeTLVHex(s string) (*TLVResult, error)

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL