"Forge secrets in the shadows, shield them from quantum eyes — and from the eyes of states."
shadowforge is a quantum-resistant steganography toolkit for journalists, whistleblowers, and dissidents operating against nation-state adversaries.
It is a Rust reimplementation of shadowforge (Go), with PDF as a first-class citizen and a full suite of countermeasures designed specifically for the journalist-vs-nation-state threat model.
This software has not been externally security audited. Use it as a supplementary layer alongside established tools (Signal, Tor, SecureDrop). See SECURITY.md and THREAT_MODEL.md.
| Feature | Go version | Rust version |
|---|---|---|
| LSB image steganography | ✅ | ✅ |
| DCT JPEG steganography | ✅ | ✅ |
| Palette steganography | ✅ | ✅ |
| LSB audio (WAV) | ✅ | ✅ |
| Phase encoding (DSSS) | ✅ | ✅ |
| Echo hiding | ✅ | ✅ |
| Zero-width text | ✅ | ✅ (grapheme-cluster-safe) |
| PDF embedding | ✅ first-class | |
| PDF content-stream LSB | ❌ | ✅ |
| PDF XMP metadata embedding | ❌ | ✅ |
| PDF shard-per-page pipeline | ❌ | ✅ |
| ML-KEM-1024 (NIST FIPS 203) | via CIRCL (CGo) | ✅ pure Rust |
| ML-DSA-87 (NIST FIPS 204) | via CIRCL (CGo) | ✅ pure Rust |
| Reed-Solomon K-of-N | ✅ | ✅ |
| 4 distribution patterns | ✅ | ✅ |
| Adversarial embedding optimisation | ❌ | ✅ |
| Camera model fingerprint matching | ❌ | ✅ |
| Compression-survivable embedding | ❌ | ✅ |
| Deniable dual-payload steganography | ❌ | ✅ |
| Panic wipe | ❌ | ✅ |
| Dead drop mode | ❌ | ✅ |
| Canary shard tripwires | ❌ | ✅ |
| Time-lock puzzle payloads | ❌ | ✅ |
| Stylometric fingerprint scrubbing | ❌ | ✅ |
| Corpus steganography (zero-modification) | ❌ | ✅ |
| Amnesiac mode (zero disk writes) | ❌ | ✅ |
| Geographic threshold distribution | ❌ | ✅ |
| Forensic watermark tripwires | ❌ | ✅ |
# From source (requires Rust 1.94.1)
git clone https://github.com/greysquirr3l/shadowforge-rs
cd shadowforge-rs
make release
sudo install target/release/shadowforge /usr/local/bin/PDF page rasterisation requires the pdfium shared library. Without it, PDF content-stream and metadata steganography still work, but the render-to-PNG pipeline is unavailable.
# macOS (Apple Silicon)
curl -L https://github.com/bblanchon/pdfium-binaries/releases/latest/download/pdfium-mac-arm64.tgz | tar xz
export PDFIUM_DYNAMIC_LIB_PATH="$(pwd)/lib"
# macOS (Intel)
curl -L https://github.com/bblanchon/pdfium-binaries/releases/latest/download/pdfium-mac-x64.tgz | tar xz
export PDFIUM_DYNAMIC_LIB_PATH="$(pwd)/lib"
# Linux (x86_64)
curl -L https://github.com/bblanchon/pdfium-binaries/releases/latest/download/pdfium-linux-x64.tgz | tar xz
export PDFIUM_DYNAMIC_LIB_PATH="$(pwd)/lib"To persist the environment variable, add the export line to your shell
profile (~/.bashrc, ~/.zshrc, etc.).
shadowforge uses Cargo's optional feature system to control which capabilities are compiled in. This allows users to reduce the attack surface and dependencies by disabling features they don't need.
| Feature | Default | Purpose |
|---|---|---|
pdf |
✅ | PDF embedding/extraction and page rasterisation (requires pdfium) |
corpus |
✅ | Corpus-based steganography (zero-modification cover selection) |
adaptive |
✅ | Adaptive embedding (STC-inspired steganalysis evasion) |
simd |
❌ | SIMD acceleration for Reed-Solomon (if available on platform) |
By default, pdf, corpus, and adaptive are enabled. To build with fewer features:
# Disable all optional features
cargo build --no-default-features
# Disable only PDF
cargo build --no-default-features --features corpus,adaptive
# Enable SIMD in addition to defaults (for performance-critical deployments)
cargo build --features simd
# Enable only SIMD without defaults
cargo build --no-default-features --features simdWhen using shadowforge as a dependency:
# In your Cargo.toml
[dependencies]
shadowforge = "0.3" # All default features enabled
# Or with specific features
shadowforge = { version = "0.3", features = ["corpus"] }
# Or with no features
shadowforge = { version = "0.3", default-features = false }# Install with all features (default)
cargo install shadowforge
# Install without PDF support
cargo install shadowforge --no-default-features --features corpus,adaptive
# Install from source with specific features
git clone https://github.com/greysquirr3l/shadowforge-rs
cd shadowforge-rs
cargo install --path crates/shadowforge --features pdf,corpus,adaptivePDF page rasterisation requires the pdfium shared library. Without it, PDF content-stream and metadata steganography still work, but the render-to-PNG pipeline is unavailable.
The build process will auto-detect pdfium if:
- Set via
PDFIUM_DYNAMIC_LIB_PATHenvironment variable - Found in a standard system library directory (
/usr/local/lib,/usr/lib,/usr/lib/x86_64-linux-gnu,/usr/lib/aarch64-linux-gnuon Linux/macOS;C:\Program Files\pdfium\libon Windows) - Found via the OS dynamic loader's configured library search paths
If pdfium is not found, the build will emit a warning with setup instructions.
To manually set up pdfium:
# macOS (Apple Silicon)
curl -L https://github.com/bblanchon/pdfium-binaries/releases/latest/download/pdfium-mac-arm64.tgz | tar xz
export PDFIUM_DYNAMIC_LIB_PATH="$(pwd)/lib"
# macOS (Intel)
curl -L https://github.com/bblanchon/pdfium-binaries/releases/latest/download/pdfium-mac-x64.tgz | tar xz
export PDFIUM_DYNAMIC_LIB_PATH="$(pwd)/lib"
# Linux (x86_64)
curl -L https://github.com/bblanchon/pdfium-binaries/releases/latest/download/pdfium-linux-x64.tgz | tar xz
export PDFIUM_DYNAMIC_LIB_PATH="$(pwd)/lib"# Generate completions for your shell
shadowforge completions bash > ~/.local/share/bash-completion/completions/shadowforge
shadowforge completions zsh > ~/.zfunc/_shadowforge
shadowforge completions fish > ~/.config/fish/completions/shadowforge.fish# Generate a key pair
shadowforge keygen --algorithm kyber1024 --output ~/keys/
# Embed a payload in an image (adaptive mode — defeats commodity steganalysis)
shadowforge embed \
--input secret.txt \
--cover photo.jpg \
--output stego.jpg \
--key ~/keys/public.key \
--technique lsb \
--profile adaptive
# Extract
shadowforge extract \
--input stego.jpg \
--key ~/keys/secret.key \
--output recovered.txt \
--technique lsb
# Deniable embedding (two payloads, one cover, plausible deniability)
shadowforge embed \
--input real_document.txt \
--cover photo.jpg \
--output stego.jpg \
--key ~/keys/public.key \
--deniable \
--decoy-payload innocent.txt \
--decoy-key ~/keys/decoy_public.key
# Analyse detectability before embedding
shadowforge analyze detectability --cover photo.jpg --technique lsb
# Dead drop: encode for Instagram (survives platform recompression)
shadowforge dead-drop encode \
--cover photo.jpg \
--input secret.txt \
--platform instagram \
--key ~/keys/public.key \
--output upload_ready.jpg \
--manifest-output retrieval.json
# Scrub stylometric fingerprints from a text payload
shadowforge scrub --input my_document.txt --output scrubbed.txt
# Distribute across multiple covers with geographic manifest
shadowforge embed-distributed \
--input document.txt \
--covers contact_photos/*.jpg \
--data-shards 3 \
--parity-shards 2 \
--output-archive shards.zip \
--key ~/keys/public.key \
--canary \
--geo-manifest geo.toml
# Zero-trace mode (no disk writes)
shadowforge embed --amnesia \
--input payload.txt \
--cover cover.jpg \
--key public.key > output.jpgCargo workspace mono-repo — all crates live under crates/. The main
crate is crates/shadowforge, organised as Collapsed Hexagonal / DDD-lite
with four layers: domain/ (pure, no I/O), adapters/ (I/O and FFI),
application/ (thin orchestration), interface/ (CLI).
Seventeen bounded contexts live under domain/, sharing a single canonical
type vocabulary (domain/types.rs). Nothing is re-invented per context.
Future crates (shadowforge-web, shadowforge-api, etc.) add as new members
under crates/ — no restructuring required.
See the full architecture documentation for design rationale and bounded context details.
See THREAT_MODEL.md for the full threat model.
Adversary: Nation-state. Automated mass steganalysis, compelled decryption, traffic analysis, endpoint compromise, jurisdictional legal pressure, stylometric source identification.
Operational playbooks with step-by-step procedures for five common journalist scenarios are available in the source repository (clone to access). They cover border crossings, dead drops, geographic distribution, time-lock source protection, and zero-trace operation.
See docs/src/opsec/ after cloning.
Full documentation is published at greysquirr3l.github.io/shadowforge-rs — covering CLI reference, threat model, architecture, and contributing guidelines.
make build # cargo build
make test # cargo test
make lint # cargo clippy -D warnings
make check # fmt + lint + test + deny
make coverage # cargo tarpaulin (requires install)
make deny # cargo deny check
make completions # generate shell completions
make book # build mdbook site locally
make doc # build rustdoc API docs453 tests across all adapter, domain, and application modules — 85% line coverage. Key module coverage:
| Module | Coverage |
|---|---|
application/services |
100% |
domain/types |
100% |
domain/analysis |
98.6% |
domain/crypto |
93.5% |
domain/distribution |
89.2% |
adapters/opsec |
88% |
adapters/media |
86.4% |
adapters/archive |
86% |
adapters/stego |
84.5% |
Coverage is enforced via cargo-tarpaulin with an 85% overall threshold
and a 90% threshold for domain::crypto.
See the contributing guide for full development setup instructions.
Apache License 2.0 — see LICENSE.
Built on the shoulders of: ml-kem, ml-dsa, reed-solomon-erasure, lopdf, pdfium-render, unicode-segmentation, zeroize, subtle.
Go version: greysquirr3l/shadowforge
