# shadowforge

> *"Forge secrets in the shadows, shield them from quantum eyes — and from the eyes of states."*
[](https://releases.rs/docs/1.94.1/)
[](https://doc.rust-lang.org/edition-guide/rust-2024/)
[](LICENSE)
[](https://github.com/greysquirr3l/shadowforge-rs/actions)
[](https://github.com/greysquirr3l/shadowforge-rs/actions)
[](coverage/tarpaulin-report.html)
[](SECURITY.md)
**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)](https://github.com/greysquirr3l/shadowforge), with
PDF as a first-class citizen and a full suite of countermeasures designed
specifically for the journalist-vs-nation-state threat model.
---
## ⚠️ Pre-Production Warning
This software has **not been externally security audited**. Use it as a
supplementary layer alongside established tools (Signal, Tor, SecureDrop).
See [SECURITY.md](SECURITY.md) and [THREAT_MODEL.md](THREAT_MODEL.md).
---
## Feature Matrix
| LSB image steganography | ✅ | ✅ |
| DCT JPEG steganography | ✅ | ✅ |
| Palette steganography | ✅ | ✅ |
| LSB audio (WAV) | ✅ | ✅ |
| Phase encoding (DSSS) | ✅ | ✅ |
| Echo hiding | ✅ | ✅ |
| Zero-width text | ✅ | ✅ (grapheme-cluster-safe) |
| PDF embedding | ⚠️ afterthought | ✅ 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** | ❌ | ✅ |
---
## Quick Start
### Installation
```bash
# 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 Support (Optional)
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.
```bash
# macOS (Apple Silicon)
# macOS (Intel)
# Linux (x86_64)
```
To persist the environment variable, add the `export` line to your shell
profile (`~/.bashrc`, `~/.zshrc`, etc.).
---
## Building with Features
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.
### Available Features
| `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) |
### Disabling Features
By default, `pdf`, `corpus`, and `adaptive` are enabled. To build with fewer features:
```bash
# 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 simd
```
### Installing from crates.io
When using shadowforge as a dependency:
```toml
# 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 }
```
### Installing the Binary with Features
```bash
# 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,adaptive
```
### PDF Support (Optional)
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.
The build process will auto-detect pdfium if:
- Set via `PDFIUM_DYNAMIC_LIB_PATH` environment variable
- Found in a standard system library directory (`/usr/local/lib`, `/usr/lib`, `/usr/lib/x86_64-linux-gnu`, `/usr/lib/aarch64-linux-gnu` on Linux/macOS; `C:\Program Files\pdfium\lib` on 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:
```bash
# macOS (Apple Silicon)
# macOS (Intel)
# Linux (x86_64)
```
### Shell Completions
```bash
# 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
```
### Basic Usage
```bash
# 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.jpg
```
---
## Architecture
**Cargo 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](https://greysquirr3l.github.io/shadowforge-rs/architecture/design.html)
for design rationale and bounded context details.
---
## Threat Model
See [THREAT_MODEL.md](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 Security
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.
---
## Documentation
Full documentation is published at
**[greysquirr3l.github.io/shadowforge-rs](https://greysquirr3l.github.io/shadowforge-rs/)**
— covering CLI reference, threat model, architecture, and contributing
guidelines.
---
## Development
```bash
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 docs
```
### Test Coverage
453 tests across all adapter, domain, and application modules — **85% line
coverage**. Key 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](https://greysquirr3l.github.io/shadowforge-rs/contributing/setup.html)
for full development setup instructions.
---
## License
Apache License 2.0 — see [LICENSE](LICENSE).
---
## Acknowledgements
Built on the shoulders of:
[ml-kem](https://crates.io/crates/ml-kem),
[ml-dsa](https://crates.io/crates/ml-dsa),
[reed-solomon-erasure](https://crates.io/crates/reed-solomon-erasure),
[lopdf](https://crates.io/crates/lopdf),
[pdfium-render](https://crates.io/crates/pdfium-render),
[unicode-segmentation](https://crates.io/crates/unicode-segmentation),
[zeroize](https://crates.io/crates/zeroize),
[subtle](https://crates.io/crates/subtle).
*Go version*: [greysquirr3l/shadowforge](https://github.com/greysquirr3l/shadowforge)