Documentation
¶
Overview ¶
Package tpms decodes TPMS (Tire Pressure Monitoring System) Sub-GHz bit-streams into the format-independent fields a pentester can trust: the Manchester line-decoded payload bytes, the 32-bit sensor ID, and CRC-8 validity. TPMS sensors beacon on 315 MHz (North America) and 433.92 MHz (Europe/Asia) and are a prime Flipper Sub-GHz target — they uniquely identify (and so let you track) a specific vehicle, and the wire format has no authentication.
Wrap-vs-native judgement ¶
Native. The hard, reusable part — recovering bytes from a Manchester-coded FSK/OOK bit-stream — is a public, deterministic transform (IEEE 802.3 and G.E. Thomas conventions). Operators bring a pre-demodulated bit-stream (rtl_433, a Flipper FSK Sub-GHz capture pre-extracted to bits, or Universal Radio Hacker) and decode offline, exactly as subghz_pocsag_decode does for paging.
What this package covers ¶
- Manchester line decoding under both conventions (IEEE 802.3: data 0 = "10", data 1 = "01"; G.E. Thomas: the inverse) at both bit alignments, auto-selecting the convention/alignment that yields the longest clean (no illegal "00"/"11" transition) decode — the correct one runs clean while the wrong one trips an illegal pair almost immediately.
- Leading-preamble tolerance: the alternating "0101…" preamble that most TPMS sensors send before the payload decodes to a run of data bits and is reported, not rejected.
- The decoded payload as hex, plus the 32-bit sensor ID — the first four payload bytes, which across virtually every TPMS family is the unique per-sensor identifier (the field-independent signal an operator uses to fingerprint or track a vehicle).
- CRC-8 validity probing against the polynomials TPMS sensors commonly use (0x07 CCITT, 0x2F, 0x13), reported as a confidence/alignment hint.
What this package does NOT cover (deliberately out of scope) ¶
- Manufacturer-specific pressure / temperature / status field interpretation: the byte offsets and scaling differ per family (Schrader, Toyota, Ford, Renault, Citroën, GM, Hyundai, …) and cannot be verified here without per-model captures. The raw decoded bytes are surfaced so an operator can apply the relevant rtl_433 model layout. Encoding this without sample data would risk a confidently-wrong reading — worse than none for a security tool.
- FSK/OOK demodulation (bring a pre-demodulated bit-stream).
- Differential-Manchester / biphase-mark variants used by a minority of sensors (standard Manchester is the common case here).
Index ¶
Constants ¶
const DefaultExpectedSensors = 4
DefaultExpectedSensors is the TPMS sensor count of a typical passenger vehicle (one direct sensor per wheel).
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Analysis ¶ added in v0.367.0
type Analysis struct {
FramesAnalyzed int `json:"frames_analyzed"`
FramesDecoded int `json:"frames_decoded"`
ExpectedSensors int `json:"expected_sensors"`
UniqueSensorIDs []string `json:"unique_sensor_ids"`
SensorFrameCounts map[string]int `json:"sensor_frame_counts"`
CRCValidFrames int `json:"crc_valid_frames"`
CRCInvalidFrames int `json:"crc_invalid_frames"`
Frames []FrameSummary `json:"frames"`
Anomalies []Anomaly `json:"anomalies"`
Notes []string `json:"notes,omitempty"`
}
Analysis is the structured result of AnalyzeFrames.
func AnalyzeFrames ¶ added in v0.367.0
AnalyzeFrames decodes a sequence of TPMS bit-streams (each the same '0'/'1' input Decode accepts) and reports defensive anomaly signals over the set. expectedSensors is the vehicle's direct-TPMS wheel count (<=0 uses DefaultExpectedSensors).
Two deterministic signals are surfaced, both with their benign explanation stated so the operator correlates rather than concludes:
- excess_sensors: more unique 32-bit sensor IDs than a single vehicle carries. Consistent with sensor-ID injection/spoofing (the TPMS attack class) OR simply more than one vehicle in radio range.
- crc_invalid: frames matching no covered CRC-8 polynomial. Consistent with a crafted/injected frame OR a TPMS family whose CRC poly is not among the covered set (0x07/0x2F/0x13). Not conclusive on its own.
Pressure/temperature anomaly detection is intentionally absent: the field layouts are per-family and unverifiable here (see decode.go), so flagging on them would risk the confidently-wrong reading this package refuses to produce.
type Anomaly ¶ added in v0.367.0
type Anomaly struct {
Kind string `json:"kind"` // "excess_sensors" | "crc_invalid"
Severity string `json:"severity"` // "info" | "warning"
Detail string `json:"detail"`
}
Anomaly is one observation flagged during sequence analysis. It is an OBSERVATION with interpretation, never a definitive attack verdict — every flagged condition has a benign explanation that the detail spells out, in keeping with the package's "a confidently-wrong reading is worse than none" stance.
type FrameSummary ¶ added in v0.367.0
type FrameSummary struct {
Index int `json:"index"`
SensorID string `json:"sensor_id,omitempty"`
CRCValid bool `json:"crc_valid"`
DecodedHex string `json:"decoded_hex,omitempty"`
DecodeError string `json:"decode_error,omitempty"`
}
FrameSummary is the per-frame view used by Analysis.
type Result ¶
type Result struct {
InputBits int `json:"input_bits"`
LineCoding string `json:"line_coding"`
BitAlignment int `json:"bit_alignment"`
DecodedBits int `json:"decoded_bits"`
DecodedBytes int `json:"decoded_bytes"`
DecodedHex string `json:"decoded_hex"`
SensorID string `json:"sensor_id,omitempty"`
SensorIDDecimal *uint32 `json:"sensor_id_decimal,omitempty"`
CRC8Matches []string `json:"crc8_matches,omitempty"`
Notes []string `json:"notes,omitempty"`
}
Result is the structured decode of a TPMS bit-stream.