Part 1 of Crypto Lab, a 10-part series on GopherTrunk’s optional cryptographic-research toolkit — the third leg of the Lab Bench trilogy (Signal Lab finds and names signals, RF Scope dissects them like Wireshark, and Crypto Lab tries to break their encryption). It is also where a recurring mystery — a signal we call Mercury — finally gets an answer.
TL;DR: Crypto Lab is a byte-oriented cryptographic-research toolkit that lives inside the
gophertrunkbinary but is excluded from the default build behind acryptolabbuild tag. Itsassessharness attempts to decrypt captured frames by every applicable method and grades each one — because attempting decryption is the test. It cannot brute a strong cipher with a good key and rotated IVs (that grades RESISTANT); what it breaks is what fails in the field: reused IVs, default/test keys, keyless obfuscation, and weak keystreams.
Key takeaways
- Attempting decryption is the security test. A complete decryption means the deployment failed; recovering nothing means the encryption held.
- Opt-in by design. The toolkit is behind a build tag, so a default operator install never ships an attack toolkit it doesn’t need.
- Three verdicts. Every assessment lands on RESISTANT, PARTIAL, or BROKEN.
- Honest about limits. Crypto Lab does not pretend to break AES. It finds the misconfigurations and weak constructions that break real deployments.
Responsible use — read this first. Crypto Lab is for authorized security testing only: assessing systems you own or operate, systems you are explicitly licensed to test, and security research, CTF, and classroom use on your own material. Radio encryption exists to protect real people — decrypting traffic you are not authorized to touch is illegal in most jurisdictions, and nothing in this series is a licence to do it. Every workflow here assumes you are testing your own deployment or one you have written permission to assess. If that is not you, stop here.
In this post
- What Crypto Lab is — a research toolkit, not a magic decryptor, and why “breaking it is the test.”
- Why it is a build-tag opt-in — how the toolkit ships inside the binary yet stays out of the default install.
- The CLI shape —
gophertrunk cryptolab <tool> [<mode>] [flags], pluslistandserve. - The verdict scale — RESISTANT / PARTIAL / BROKEN, and the escalation ladder of methods behind it.
- A map of the series so you can jump to the tool you care about.
Cheat sheet
| Command / flag | What it does |
|---|---|
make build TAGS=cryptolab |
Build gophertrunk with the toolkit linked in |
go build -tags cryptolab ./cmd/gophertrunk |
Equivalent raw go build |
make test-cryptolab |
Run the toolkit’s tests (including the tagged CLI) |
gophertrunk cryptolab list |
List every tool and its modes |
gophertrunk cryptolab serve -open |
Launch the web console at 127.0.0.1:8096 |
gophertrunk cryptolab <tool> [<mode>] [flags] |
Run one tool; global flags precede the tool name |
gophertrunk cryptolab assess crypto -in frames.jsonl |
The headline: attempt every attack, grade each |
What Crypto Lab actually is
Crypto Lab is a byte-oriented cryptographic-research toolkit that collects the analyses you reach for when you are staring at an unfamiliar RF payload and asking two questions: what am I looking at, and can I break it? Statistical triage, autocorrelation period detection, a NIST SP 800-22 randomness battery, an obfuscation-class classifier, keyspace brute force, LFSR and keystream analysis, keystream-reuse / many-time-pad recovery, CRC parameter recovery, analog voice descrambling, and a pluggable “subject” framework for studying specific byte obfuscators — all in one subcommand.
The philosophy behind it is worth stating plainly, because it reframes what the tool is for. Attempting decryption is the test. When you point Crypto Lab at a captured encrypted system, a complete decryption means the deployment failed — its encryption did not do its job. Recovering nothing means the encryption held. You are not “hacking” the system; you are measuring it, the same way a penetration tester measures a network by trying to get in and reporting exactly how far they got.
This is why the toolkit is deliberately honest about its ceiling. It cannot brute-force a strong key out of a strong cipher. Point it at AES-256 with a non-default key and rotated IVs and it will tell you, plainly, that the keyspace is infeasible and the encryption is RESISTANT. That result is not a failure of the tool — it is the security finding: the encryption is doing its job. What Crypto Lab breaks is what actually fails in the field: reused IVs, default and test keys, keyless “obfuscation” dressed up as encryption, and structurally weak keystreams (short LFSRs, backdoored small keyspaces). Those are the findings that matter, because those are the deployments that leak.
The Mercury thread
Running through all three Lab Bench series is a single mystery. Mercury is an intermittent, apparently-encrypted burst Ada first captured near 453 MHz in the UHF business band — short transmissions on a ~12.5 kHz channel that come and go with no obvious schedule. In Signal Lab Part 8, blind signal-ID gave a best guess (~4800 sym/s, 4-level FSK-like) but no protocol lock. In RF Scope Part 7, the entropy analyzer triaged Mercury’s payload as not obviously strong and exported the raw frames. Those frames land here, in Crypto Lab. We’ll pick Mercury back up in Part 5, and in Part 10 we finally reveal what it was — a reveal that turns out to be the whole moral of the series. For now, just know the thread is there.
Why it’s a build-tag opt-in
Here is the design decision that shapes everything: the toolkit ships inside the gophertrunk binary but is excluded from the default install. It sits behind the cryptolab build tag — the same mechanism the DVSI vocoder uses. A standard build does not link it in:
make build # default: `gophertrunk cryptolab` just prints how to opt in
make build TAGS=cryptolab # opt in: the full toolkit is linked
go build -tags cryptolab ./cmd/gophertrunk # equivalent raw go build
make test-cryptolab # run the toolkit's tests, including the tagged CLI
In a default build, the cryptolab subcommand exists but does nothing except tell you how to opt in. Rebuild with TAGS=cryptolab and the same subcommand becomes the whole toolkit.
Why bother? Two reasons. First, the standard operator install stays lean — someone running GopherTrunk as an unattended scanner at an antenna has no need for a cryptanalysis toolkit in their binary, and now it isn’t there. Second, and more importantly, it’s a statement of intent. Attack tooling is opt-in. You have to deliberately build the security-testing version. That friction is a feature: it keeps the default distribution firmly a scanner, not an interception tool.
There’s a subtlety worth calling out. The toolkit’s engine and subject packages under internal/cryptolab/ carry no build tag — they always compile and are covered by the normal make test. Only the binary’s cryptolab subcommand is gated. So the cryptographic code is continuously tested; what the build tag controls is merely whether the CLI surface is wired into the shipped binary.
The CLI shape
Every invocation follows one grammar:
gophertrunk cryptolab [global flags] <tool> [<mode>] [tool flags]
gophertrunk cryptolab list # list tools and modes
gophertrunk cryptolab serve # launch the web console
Global flags precede the tool name — flag parsing stops at the first non-flag argument, then the tool and mode parse their own flags. The globals are -out (artifact directory for survivor logs and checkpoints), -resume (resume a resumable mode), -format (text|json|jsonl|yaml|csv), -log-level, and -log-format. So a full command reads left to right as globals, then tool, then mode, then that mode’s flags:
gophertrunk cryptolab -out ./out -format json alias structure -csv ground_truth.csv
cryptolab list prints the whole catalogue — eleven tools, each with its modes and a one-line synopsis. It’s the fastest way to remember what exists. And cryptolab serve (covered in Part 9) launches a browser console at 127.0.0.1:8096 that renders a form for every tool automatically. Everything the CLI can do, the console can do — except the handful of operations that run a host program, which are CLI-only for safety.
The verdict scale and the escalation ladder
The unifying idea across the toolkit is the three-way verdict. Every assess run ends on one of three chips:
- RESISTANT — no applicable method recovered anything. The encryption held.
- PARTIAL — information leaked: a reused IV, structured (non-random) ciphertext, a recovered keystream segment, or an algorithm with a published break in use.
- BROKEN — a method achieved verified, complete decryption. A fail.
Behind that verdict is a ladder of methods that escalate in capability, from cheap statistical checks to full key recovery:
Reese’s rule of thumb: the top of the ladder tells you this could be weak; the bottom tells you this is broken, here’s the plaintext. A responsible assessment reports both, and never claims a break it did not verify.
The series map
| Part | Topic | What you’ll do |
|---|---|---|
| 1 | Breaking It Is the Test (this post) | Understand the philosophy, build tag, and verdicts |
| 2 | First triage: classify & stats |
Triage an unknown payload and get the next command |
| 3 | Randomness: NIST SP 800-22 & LFSRs | Tell strong keystreams from scramblers |
| 4 | Classical ciphers: brute |
Break XOR, Caesar, Vigenère, substitution |
| 5 | Keystream reuse & many-time-pad | Exploit IV/MI reuse with ks |
| 6 | The assess battery |
Grade P25/DMR/TETRA end to end |
| 7 | CRC recovery & the recipe pipeline | Recover a CRC and chain transforms |
| 8 | Analog voice descrambling | Undo inversion, split-band, rolling code |
| 9 | Web console, live bridge, external ciphers | Drive it from a browser; feed it live captures |
| 10 | Subject framework, alias & the Mercury reveal |
Recover a keyless obfuscator; solve Mercury |
Where this goes next
Part 2 starts where every investigation should: triage. Before you brute anything, you run classify auto and stats scan to find out what class of thing you’re holding — plaintext, a shift cipher, repeating XOR, a periodic scrambler, an LFSR, or strong encryption — and let the tool hand you the exact next command. If you want the full picture of where these payloads come from, the cryptolab docs cover the tool surface, and the sibling series (Signal Lab, RF Scope) cover finding and dissecting the signals that feed it.
FAQ
Is Crypto Lab a tool for decrypting other people’s radio traffic? No. It is a security-testing toolkit for encryption you are authorized to assess — your own deployment, a system you’re licensed to test, or research and teaching material. Decrypting traffic you have no authorization for is illegal, and the toolkit’s whole framing is defensive: measure how well your encryption holds up.
Why hide it behind a build tag instead of just shipping it?
Two reasons: it keeps the default operator binary lean, and it makes attack tooling a deliberate opt-in rather than something every install carries by default. The default build’s cryptolab command just prints how to enable it.
Can it break AES or a properly-keyed P25 system? No, and it says so — it reports RESISTANT. It cannot brute a strong key out of a strong cipher. What it finds is misconfiguration: reused IVs, default keys, keyless obfuscation, and weak keystreams — the things that actually break deployments.
What does “breaking it is the test” mean in practice?
The assess harness tries every applicable attack and grades each. A full decryption means the deployment’s encryption failed the test; recovering nothing means it passed. The attempt is the measurement.
Series navigation
Part 1 of 10 · Next →
Part 2: First Triage — classify auto and stats scan