Field Guide · algorithm

Also known as: ADP, P25 keystream, P25 decryption

P25 link-layer encryption protects voice by generating a keystream from the key and the call’s message indicator, then XORing that keystream onto the IMBE voice codewords frame by frame.1 Every P25 cipher is used as a stream cipher in this sense:2 whether the primitive is RC4 or a block cipher, the output is a byte stream XORed onto the protected bits. This means a monitor that has the key can decrypt purely by regenerating the same keystream — no inversion of the cipher is needed. GopherTrunk’s p25crypto package realises these keystreams so its assessment harness can attempt decryption against candidate, known, or weak keys; it performs no key recovery.

key MI (72-bit IV) keystream generator encrypted IMBE clear voice
Decryption mirrors encryption: regenerate the keystream from the key and MI, then XOR it against the ciphered codewords — so possession of the key is the whole game.

The generators

Each algorithm ID selects a keystream construction, all seeded by the Message Indicator (MI) as the IV. The constructions follow the common open implementations (OP25, DSD-FME):

ALGID Algorithm Key Keystream construction
0xAA ADP / RC4 5 bytes RC4 keyed with key ‖ first 8 MI octets, discard 256 bytes, then XOR
0x81 DES-OFB 8 bytes Single-DES in OFB; IV = first 8 MI octets
0x85 AES-128 16 bytes AES-OFB; IV = MI left-justified into 16 bytes
0x84/0x89 AES-256 (-OFB) 32 bytes AES-256-OFB; IV = MI left-justified into 16 bytes
0x83 TDES-2 16 bytes Two-key 3DES expanded to K1‖K2‖K1, OFB
0x86 TDES 24 bytes Three-key 3DES in OFB

For the block ciphers, OFB (output feedback) mode turns the block cipher into a byte-stream generator: the IV is repeatedly re-encrypted and the output is the keystream, independent of the plaintext. The MI supplies that IV — exactly 8 octets for DES, and left-justified into a 16-byte block for AES (the exact TIA MI-to-IV expansion for AES is a refinement over this simplest documented form).

The ADP 256-byte discard

ADP is RC4 keyed with the 5-octet key followed by the first eight octets of the MI, but with one non-obvious step: the first 256 keystream bytes are thrown away before any encryption begins. This warm-up discard is a spec / reverse-engineering detail — it is the OP25/DSD-FME convention and is what makes GopherTrunk’s ADP keystream line up with real ADP traffic. Getting it wrong (or omitting it) produces a keystream that XORs to garbage even with the correct key, which is why the constant is called out explicitly (adpDiscard = 256). The discard mitigates the well-known RC4 key-schedule weakness where early output leaks key structure — though it does not rescue ADP’s tiny 40-bit key from brute force.

Relevance to SDR

internal/cryptolab/engine/p25crypto/keystream.go realises these generators so GopherTrunk can attempt decryption when a key is supplied or under test — including a small dictionary of weak/default keys (all-zero, all-FF, incrementing) that a misconfigured radio might carry. The package deliberately stops at producing the byte-stream keystream; mapping it onto the exact IMBE voice-bit positions is the caller’s job, and no key recovery is performed. This keeps decryption strictly a function of the key ID and key an operator already holds — the honest boundary between monitoring and attacking a system.

Sources

  1. Project 25 — Wikipedia, on the P25 standard and its encryption. Keystream constructions follow the open OP25 / DSD-FME implementations. 

  2. Stream cipher — Wikipedia, on XOR-keystream encryption and OFB-mode block-cipher keystreams. 

See also