Documentation
¶
Overview ¶
Package pacs decodes Physical Access Control System (PACS) credential payloads — the upper-layer encoding that sits on top of the Wiegand bit-stream produced by an HID Prox / iCLASS / EM-style reader.
Wrap-vs-native judgement
Native. The HID format catalogue is fully public via the HID OEM-format spec sheets, the Proxmark3 Iceman codebase (`hidpacs.go` table), and decades of community reverse-engineering. Each format is a small fixed-width bit-field layout with one or more parity bits — pure bit-twiddling, no crypto, no state. Operators feed the raw bit string that drops out of `wiegand_decode` (or a proxmark3 lf hid demod) and get the documented facility-code / card-number / OEM-code fields plus a parity-validity check.
What this package covers
Input convention: a bit string ("0"/"1" only) of one of the recognised widths. Hex+bit-length input is also accepted for convenience (hex is left-aligned into a bit buffer of exactly the declared width, MSB first).
Recognised formats and their wire layouts:
**HID H10301 26-bit** — the canonical HID Prox format. P + 8 FC + 16 CN + P. Bit 0 is even parity over bits 1-12; bit 25 is odd parity over bits 13-24.
**HID H10306 34-bit** — extended FC range. P + 16 FC
16 CN + P. Bit 0 is even parity over bits 1-16; bit 33 is odd parity over bits 17-32.
**HID H10304 37-bit** — wide CN. P + 16 FC + 19 CN + P. Bit 0 is even parity over bits 1-18; bit 36 is odd parity over bits 18-35.
**HID H10302 37-bit** — no FC, 35-bit CN. P + 35 CN + P. Bit 0 is even parity over bits 1-18; bit 36 is odd parity over bits 18-35.
**HID Corporate 1000 35-bit** — proprietary. 2 leading parity bits (even/odd over a complex bit pattern per HID OEM spec) + 12 FC + 20 CN + trailing parity.
**HID Corporate 1000 48-bit** — extended variant. 2 parity bits + 22 FC + 23 CN + trailing parity.
When the input length matches a single recognised format, the decoder returns that format. When the length matches multiple formats (e.g. 37-bit could be H10304 OR H10302), the decoder returns all candidates and lets the caller pick by parity-validity or by facility-code sanity.
Parity is computed and surfaced as parity_valid bool for each candidate. A failed parity bit doesn't suppress the candidate (the bit-pattern is still useful for debugging) but is clearly flagged.
What this package does NOT cover (deliberately out of scope)
The reader-layer Wiegand bit-stream extraction — `wiegand_decode` already handles that.
The crypto layer of iCLASS Standard or Elite (3DES key diversification, MAC validation) — payload-level decryption is a separate Spec.
DESFire AID / EV1 application records — those are NFC APDU exchanges decoded by `desfire_decode`.
LF / EM4xxx baseband modulation (Manchester / biphase) — `em4100_decode` handles EM-style baseband.
Cardholder-database lookup — facility-code / card-number to "who owns this badge" mapping is the operator's job (the PACS database is external).
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func EncodeWiegand ¶ added in v0.376.0
EncodeWiegand builds the raw Wiegand bit-string for a named HID format from a facility code + card number — the inverse of DecodeBits. The result is the exact frame DecodeBits parses back (round-trip verified): leading even-parity bit, the BCD-less binary FC + CN fields, and the trailing odd-parity bit, MSB-first.
Wrap-vs-native judgement ¶
Native, and the inverse of the existing decoder. HID Wiegand formats are public, fixed-width bit layouts with parity — pure bit-twiddling, no crypto, no state, no hardware. Generation only: this produces the bits an operator would write to a T5577/emulate; it performs no write or TX, so it carries the same Low risk as the decoder. Correctness is verifiable three ways: round-trip against DecodeBits, hand-computed parity vectors, and the published HID format layouts.
Covered formats (clean, non-overlapping parity — hand-verifiable) ¶
- "H10301" — 26-bit: even parity + 8-bit FC + 16-bit CN + odd parity. Even parity over the top 12 data bits, odd over the bottom 12.
- "H10306" — 34-bit: even parity + 16-bit FC + 16-bit CN + odd parity. Even parity over the FC, odd over the CN.
- "H10304" — 37-bit: even parity + 16-bit FC + 19-bit CN + odd parity. Even parity over the top 18 data bits, odd over the bottom 18 (the two ranges overlap at the 18th bit — both are still clean functions of the data, so the frame round-trips parity-valid).
- "H10302" — 37-bit, no facility code: even parity + 35-bit CN + odd parity. Identical parity ranges to H10304; pass facility code 0.
Deliberately deferred ¶
The HID Corporate 1000 (35/48-bit) formats use a self-referential / proprietary parity scheme that the decoder validates only best-effort (the parity bits fall inside their own coverage range). Encoding them to a guaranteed-valid frame is not reliable without an external reference vector, so they are not offered here (decode still surfaces them as candidates).
Types ¶
type Candidate ¶
type Candidate struct {
Format string `json:"format"`
Spec string `json:"spec_summary"`
FacilityCode uint64 `json:"facility_code,omitempty"`
CardNumber uint64 `json:"card_number"`
OEMCode uint64 `json:"oem_code,omitempty"`
Issue uint64 `json:"issue_code,omitempty"`
ParityValid bool `json:"parity_valid"`
ParityNotes string `json:"parity_notes,omitempty"`
}
Candidate is one decoded PACS format interpretation.
type Result ¶
type Result struct {
BitLength int `json:"bit_length"`
BitsRaw string `json:"bits_raw"`
HexLeft string `json:"hex_msb_first"`
Candidates []Candidate `json:"candidates"`
Notes []string `json:"notes,omitempty"`
}
Result is the top-level decoded view.
func DecodeBits ¶
DecodeBits parses a bit-string PACS payload.
func DecodeHex ¶
DecodeHex parses a hex-encoded PACS payload with a declared bit count. The hex bytes are left-aligned into a bit buffer of exactly bitLen bits (MSB first). Unused trailing bits in the last byte are silently discarded; callers are expected to provide a bitLen consistent with what `wiegand_decode` or the reader actually emitted.