Also known as: NXDN scrambler, NXDN encryption, NXDN privacy
The NXDN scrambler is the optional privacy mode NXDN radios expose — the setting sometimes labelled “encryption” — that obscures the voice or data field by XORing a pseudo-random keystream over it.1 The keystream comes from a 15-bit linear-feedback shift register (LFSR) seeded by a 15-bit scrambling key in the range 0 to 32767. It is not cryptography in any meaningful sense: the key space is only 2¹⁵ = 32768 values, small enough to try exhaustively in a fraction of a second, so the “privacy” it offers is defeated by brute force alone.2
Status — synthetic model, not hardware-confirmed. GopherTrunk’s tap polynomial and seed mapping are an internally-consistent working model — a maximal-length 15-bit Fibonacci LFSR, x¹⁵ + x¹⁴ + 1 — chosen so the scrambler is its own inverse and emits a balanced m-sequence of period 32767. They have not been confirmed bit-exact against a known-key capture. The spec-level facts the tooling relies on are the XOR-symmetric (self-inverse) structure and the 15-bit key space; the exact feedback is provisional and should be adjusted when a known-key capture is available.
How the keystream is generated
Each step the register outputs its most significant stage, then shifts left and inserts the XOR of the top two stages as the new least significant bit. Seeding the register with the key and running it over the information field produces the additive keystream:
func (s *Scrambler) Next() byte {
out := byte((s.state >> 14) & 1)
fb := ((s.state >> 14) ^ (s.state >> 13)) & 1
s.state = ((s.state << 1) | fb) & ScramblerKeyMax // mask to 15 bits
return out
}
Key 0 seeds an all-zero register, which produces an all-zero keystream — that is the “clear”
(unscrambled) case, so key 0 means no privacy at all. Every other key produces a distinct
maximal-length sequence. Because scrambling is a bare XOR, Descramble is literally the same
routine as Scramble; the receive side reuses it with the same key.
Why it does not provide security
Two facts collapse the scrambler’s protection. First, the key is only 15 bits, so there are
just 32768 possible keys — an attacker tries them all. Second, NXDN frames carry
CRCs over their decoded contents, which hand the
attacker a free correctness oracle: descramble a captured field under a candidate key, check
whether the frame’s CRC now validates, and the one key in 32768 that produces consistently
valid CRCs is the answer. GopherTrunk’s offline cryptolab nxdn tool does exactly this — it
brute-forces the full key space using this LFSR primitive plus the frame CRCs as the oracle.
An additive stream obscured by a 15-bit register is a scrambler in the historical sense, not an
encryption scheme; it stops a casual listener with a stock radio, nothing more.
Relevance to SDR
internal/radio/nxdn/scramble.go implements the Scrambler (a 15-bit LFSR state), the
Scramble / Descramble XOR helpers, and the ScramblerKeyMax bound the brute-forcer sweeps.
The design deliberately separates the spec-level facts it is confident in — XOR symmetry and
the 2¹⁵ key space, on which the brute-force loop and CRC oracles depend — from the provisional
feedback polynomial, which is a plausible working model pending a bit-exact capture. That
separation is what lets the tooling be useful today (the key-recovery approach is correct
regardless of the exact taps) while being honest that the keystream itself is not yet verified
against real hardware.
Sources
-
Scrambler — Wikipedia, on additive/multiplicative scramblers and their distinction from encryption. ↩
-
Linear-feedback shift register — Wikipedia, on the LFSR construction and maximal-length sequences the keystream is built from. ↩