mifare

package
v0.447.0 Latest Latest
Warning

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

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

Documentation

Overview

Package mifare decodes Mifare Classic 1K / 4K data dumps — manufacturer block (sector 0 block 0), sector trailer (last block of each sector), value blocks (recognized by their value+complement structure), and plain data blocks. Pure offline parser; no transport, no hardware.

Wrap-vs-native judgement: Mifare Classic's block layouts are public — NXP application notes AN10833 (sector trailer and access conditions), AN10834 (value blocks), AN10927 (UID formats), and ISO/IEC 14443-3 (ATQA / SAK). Wrapping a FAP for this would require an SD-card install + a firmware-fork dependency for a pure parser. We implement natively so operators can paste a 16-byte block (or a 64-block 1K dump / 256-block 4K dump) and decode it offline.

What this package covers:

  • Block-kind classification (manufacturer, trailer, value, data) based on block index + structural heuristics
  • Sector-trailer decode: Key A, access bits, GPB, Key B, plus the per-block permission expansion (read / write / increment / decrement / transfer / restore allowed for Key A only, Key B only, both, or neither)
  • Value-block decode: value + complement + duplicate value integrity check, signed 32-bit value, address byte + complement check
  • Manufacturer-block decode: NUID (4-byte UID), BCC, SAK, ATQA, and the 8 trailing manufacturer-data bytes
  • Dump walker that classifies every block of a 1K / 4K dump in one pass

What this package does NOT cover (deliberately out of scope):

  • Reading the actual card (operators bring dumps from Flipper / Proxmark3 / etc.)
  • Cryptogram derivation or key recovery (covered by the internal/crypto1 package's mfoc / mfcuk / mfkey32 paths)
  • Mifare Plus / DESFire — separate specs with separate layouts
  • Re-encode (round-tripping a decoded view back to 16 bytes — happy to add if a caller materialises)

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AccessBits

type AccessBits struct {
	// Blocks holds the per-block access view. For a 1K sector
	// the slice has 4 entries (blocks 0-3); for 4K large
	// sectors the slice has 4 entries representing the four
	// block groups (5-block chunks); we render the layout in
	// the small-sector form since 1K is the common case and
	// the bit-packing matches.
	Blocks [4]BlockAccess `json:"blocks"`
}

AccessBits is the structured view of a sector's access conditions — three bits per block (C1, C2, C3), expanded into the documented permission catalog per NXP AN10833 Table 6 (data blocks) and Table 7 (sector trailer).

type Block

type Block struct {
	// Index is the block's absolute position in the dump (0..63
	// for 1K, 0..255 for 4K). -1 when decoding a single block
	// with no dump context.
	Index int `json:"index"`
	// Sector is the sector number containing this block. -1 when
	// Index is -1.
	Sector int `json:"sector"`
	// Kind is the recognised block role.
	Kind BlockKind `json:"kind"`
	// Hex is the operator-facing hex rendering of the raw 16
	// bytes, uppercase, no separators.
	Hex string `json:"hex"`
	// ASCII is the printable-ASCII rendering of the raw bytes
	// with '.' for non-printable. Useful for spotting strings in
	// data blocks.
	ASCII string `json:"ascii"`
	// Trailer is populated when Kind == KindTrailer.
	Trailer *Trailer `json:"trailer,omitempty"`
	// Value is populated when Kind == KindValue.
	Value *Value `json:"value,omitempty"`
	// Manufacturer is populated when Kind == KindManufacturer.
	Manufacturer *Manufacturer `json:"manufacturer,omitempty"`
}

Block is the structured decoded view of a 16-byte Mifare Classic block.

func DecodeBlock

func DecodeBlock(hexBlob string, index int) (Block, error)

DecodeBlock decodes a single hex-encoded 16-byte Mifare Classic block. When index >= 0 the caller is telling us the block's position in the dump (so the manufacturer / trailer classification can use it); when index < 0 we classify from the block's structure alone (no manufacturer recognition without an index).

func DecodeDump

func DecodeDump(hexBlob string) ([]Block, error)

DecodeDump decodes a full 1K (64 blocks = 1024 bytes) or 4K (256 blocks = 4096 bytes) Mifare Classic dump. Returns one Block per 16-byte chunk; rejects inputs whose length isn't a 16-byte multiple. Accepts ':' / '-' / '_' / whitespace separators.

type BlockAccess

type BlockAccess struct {
	// C1, C2, C3 are the three access bits.
	C1 int `json:"c1"`
	C2 int `json:"c2"`
	C3 int `json:"c3"`
	// Read, Write, Increment, Decrement enumerate the operations
	// allowed for each key. Values: "A", "B", "A|B", "never".
	// For the trailer block (Blocks[3]) the names map differently
	// (read/write of Key A, access bits, Key B); see TrailerAccess.
	Read      string `json:"read,omitempty"`
	Write     string `json:"write,omitempty"`
	Increment string `json:"increment,omitempty"`
	Decrement string `json:"decrement,omitempty"`
	// TrailerAccess is non-nil only for the trailer block
	// (Blocks[3]), carrying the four trailer-specific permission
	// slots from AN10833 Table 7.
	TrailerAccess *TrailerAccess `json:"trailer_access,omitempty"`
}

BlockAccess names the access bit triplet for one block.

type BlockKind

type BlockKind string

BlockKind enumerates the block roles we recognise.

const (
	// KindManufacturer is sector 0 block 0 — the read-only NUID
	// / BCC / SAK / ATQA / manufacturer-data block.
	KindManufacturer BlockKind = "manufacturer"
	// KindTrailer is the last block of each sector — Key A,
	// access bits, GPB, Key B.
	KindTrailer BlockKind = "sector_trailer"
	// KindValue is a value-formatted block (value + complement +
	// duplicate value + address byte + complement structure).
	// We classify a block as value when the complement integrity
	// check passes.
	KindValue BlockKind = "value"
	// KindData is the catch-all for ordinary data blocks.
	KindData BlockKind = "data"
)

type Manufacturer

type Manufacturer struct {
	NUIDHex         string `json:"nuid_hex"`
	BCC             int    `json:"bcc"`
	BCCValid        bool   `json:"bcc_valid"`
	SAK             int    `json:"sak"`
	ATQA            string `json:"atqa_hex"`
	ManufacturerHex string `json:"manufacturer_data_hex"`
	ICManufacturer  string `json:"ic_manufacturer,omitempty"`
}

Manufacturer is the decoded manufacturer-block view. NUID can be either 4-byte (single-size UID) or part of a 7-byte UID chained across two CT (cascade tag) reads — this dump format only shows the first 4 bytes, so we render them and the BCC without trying to reconstruct a 7-byte UID. ATQA / SAK / IC manufacturer code are surfaced for cross-reference with the well-known tag-type tables.

type Trailer

type Trailer struct {
	KeyAHex     string      `json:"key_a_hex"`
	AccessBytes string      `json:"access_bytes_hex"`
	GeneralByte int         `json:"general_purpose_byte"`
	KeyBHex     string      `json:"key_b_hex"`
	AccessValid bool        `json:"access_bits_valid"`
	AccessBits  *AccessBits `json:"access_bits,omitempty"`
}

Trailer is the decoded sector-trailer view. KeyA / KeyB are hex-rendered for the JSON shape; AccessBits expands into the per-block permission table.

type TrailerAccess

type TrailerAccess struct {
	KeyAWrite       string `json:"key_a_write"`
	AccessBitsRead  string `json:"access_bits_read"`
	AccessBitsWrite string `json:"access_bits_write"`
	KeyBRead        string `json:"key_b_read"`
	KeyBWrite       string `json:"key_b_write"`
}

TrailerAccess is the trailer-block permission table — what each key can do with Key A, the access bits themselves, and Key B.

type Value

type Value struct {
	// Value is the signed 32-bit value extracted from bytes 0-3.
	Value int32 `json:"value"`
	// ValueValid is true iff the value at bytes 0-3, its
	// complement at bytes 4-7, and the duplicate at bytes 8-11
	// all satisfy the complement integrity check.
	ValueValid bool `json:"value_integrity_valid"`
	// Address is the address byte (byte 12).
	Address int `json:"address"`
	// AddressValid mirrors ValueValid for the 4-byte address
	// structure (byte 12 / ~byte 13 / byte 14 / ~byte 15).
	AddressValid bool `json:"address_integrity_valid"`
}

Value is the decoded value-block view.

Jump to

Keyboard shortcuts

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