# black-bag
`black-bag` is a zero-trace, no-compromise command-line vault for high-risk operators. It ships as a single Rust binary with the strongest defaults we can provide: Argon2id hardening, ML-KEM-1024 cascaded wrapping (Kyber), XChaCha20-Poly1305 payload encryption, zeroization of every secret buffer, and page-locked memory on Unix. There is no optional telemetry, no cloud, no GUI—just a laser-focused CLI that keeps secrets safe even under hostile conditions.
## Install
Prerequisites (all OS)
- Rust toolchain 1.81+ via rustup: https://rustup.rs
- A C toolchain (C compiler + linker):
- macOS: `xcode-select --install` (Xcode Command Line Tools)
- Debian/Ubuntu: `sudo apt update && sudo apt install -y build-essential`
- Fedora/RHEL: `sudo dnf groupinstall -y "Development Tools"` (or `sudo dnf install -y gcc make`)
- Arch: `sudo pacman -S --needed base-devel`
- Windows: Install “Build Tools for Visual Studio 2022” with the “Desktop development with C++” workload (MSVC + Windows SDK), then install Rust via rustup (MSVC toolchain)
Install the CLI from crates.io (recommended):
```bash
cargo install black-bagg
```
Upgrade to the latest release:
```bash
cargo install black-bagg --force
```
Note: The installed binary is named `black-bag`.
Alternatively, build from source (see “Building and testing” below).
## Post-Quantum Signatures: ML-DSA-87 (at a glance)
ML-DSA-87 is the NIST-standardized module-lattice digital signature scheme (derived from CRYSTALS-Dilithium, highest-security parameter set). In black-bag it provides authenticity for offline vault backups.
- What it is: A post-quantum digital signature (Dilithium Level-5). Public key ≈ 2.6 KiB; signatures ≈ 4.6 KiB.
- What it protects: Ensures a `.cbor` backup and its keyed integrity tag (`.int`) came from an authorized signer (no silent tampering).
- How we use it:
- We compute a BLAKE3 keyed integrity tag `.int` over the vault bytes, keyed by the embedded ML‑KEM public key (binds tag to the specific vault state).
- We sign that tag with ML‑DSA‑87, producing `.int.sig`.
- Verification requires both `.int` and `.int.sig` with the corresponding ML‑DSA public key.
- Commands (preferred PQ flow):
- Generate keys (one‑time):
- `black-bag backup keygen --pub-out backup.mldsa87.pub --sk-out backup.mldsa87.sk`
- Sign a backup:
- `black-bag backup sign --path /path/to/vault.cbor --key backup.mldsa87.sk --pub-out backup.mldsa87.pub`
- Verify before restore/use:
- `black-bag backup verify --path /path/to/vault.cbor --pub-key backup.mldsa87.pub`
- Best practices:
- Keep `backup.mldsa87.sk` offline/air‑gapped. Distribute only `backup.mldsa87.pub`.
- Always verify both integrity and signature; `.int` alone only detects bit‑rot.
- Treat `.cbor`, `.int`, and `.int.sig` as a set; transport them together.
## Security Profile (summary)
- KDF: Argon2id (tunable; default 256 MiB, 3 passes, 1 lane)
- Key Encapsulation: ML‑KEM‑1024 (Kyber Level‑5)
- Payload AEAD: XChaCha20‑Poly1305 with domain‑separated AAD
- PQ Signatures: ML-DSA-87 (Dilithium Level-5) for backup authenticity
- Memory Hygiene: zeroization everywhere + `mlock` on Unix (passphrase/DEK/secret buffers)
- Recovery: Shamir Secret Sharing via unbiased `vsss-rs` (GF(2^8))
- Crash Safety: journaled vault commits with atomic roll-forward on restart
- Zero‑trace UX: no secrets in argv/stdout/logs/tmp; atomic writes with strict perms
## Highlights
- **Zero-trace posture** – secrets never touch stdout, logs, temp files, or the clipboard. All input happens via hidden TTY prompts and is stored only after AEAD encryption.
- **Modern crypto pipeline** – Argon2id → ML-KEM-1024 (Kyber) → random 32-byte DEKs sealed with XChaCha20-Poly1305. Writes are atomic/fdatasync’d with strict permissions and zeroized in memory on drop.
- **Rich record catalogue** – logins, contacts, identity docs, secure notes, payment cards, SSH keys, PGP keys, TOTP seeds, recovery kits, bank accounts, Wi-Fi profiles, API credentials, and crypto wallets. Every record supports tagging and full-text queries.
- **Cross-platform parity** – builds cleanly on macOS, Linux, and Windows. `mlock` is enabled automatically on supported Unix platforms and degrades gracefully elsewhere.
- **Security by default** – all protective features are enabled in every binary; there are no configuration flags that weaken the threat posture.
## Quick Start
```bash
# initialize a vault (recommended memory cost: 256 MiB)
black-bag init --mem-kib 262144
# add and list API credentials (secrets collected via hidden prompts)
black-bag add api --service intel-api --environment production --access-key AKIA-123 --scopes read,write
black-bag list --kind api
# inspect a record by UUID (safe default: masked; use --reveal on a TTY)
black-bag get <UUID>
black-bag get <UUID> --reveal
```
## Quick start
```bash
# prerequisites: Rust toolchain 1.81+ (via rustup) and a standard build environment
cargo build --release
install -m 0755 target/release/black-bag ~/.local/bin/black-bag
black-bag --help
```
Recommended hygiene:
- Run from an encrypted disk.
- Disable shell history or use `HISTCONTROL=ignorespace` with leading spaces.
- Set `RUST_BACKTRACE=0` in operational shells.
## Creating your vault
```bash
black-bag init --mem-kib 262144
```
You’ll be prompted for the master passphrase twice. The vault stores under the platform data directory (e.g., `~/.config/black_bag/vault.cbor`).
## Adding records
```bash
# login
black-bag add login --title "Ops Portal" --username phoenix --url https://ops.example --tags mission
# contact
black-bag add contact --full-name "Analyst Zero" --emails a0@example --phones "mobile:+1-555-0101,desk:+1-555-0110" --tags handler
# identity document
black-bag add id --id-type passport --name-on-doc "Alex Smith" --number X1234567 --issuing-country US --expiry 2032-08-01
# secure note
black-bag add note --title "Fallback Protocol" --tags red-team
# bank account
black-bag add bank --institution "First Federal" --account-name "Ops budget" --routing-number 021000021 --tags finance
# Wi-Fi profile
black-bag add wifi --ssid "safehouse-net" --security WPA2 --location Berlin --tags infrastructure
# API credential
black-bag add api --service intel-api --environment production --access-key AKIA-123 --scopes read,write --tags automation
# crypto wallet
black-bag add wallet --label btc-cold --asset BTC --address bc1q... --network mainnet --tags treasury
# totp secret
black-bag add totp --title "GitHub MFA" --issuer GitHub --account you@example --secret JBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXP
# totp codes
black-bag totp code <UUID> --time 59
```
Sensitive fields (passwords, passphrases, API secrets, private keys) are collected via hidden prompts after the command issues—nothing sensitive ever appears in argv or shell history.
## Listing, filtering, and querying
```bash
black-bag list # masked summaries
black-bag list --kind bank_account # filter by record family
black-bag list --tag mission # filter by tag
black-bag list --query opsnet # full-text search across metadata
```
Inspect a specific record:
```bash
black-bag get <UUID>
black-bag get <UUID> --reveal # requires an interactive TTY
```
## Rotation, health, and recovery
- `black-bag rotate` – rewraps the master DEK with fresh randomness.
- `black-bag doctor` – prints health info (Argon2 params, feature flags, item counts).
- `black-bag recovery split` / `combine` – manage Shamir shares for catastrophic recovery.
- `black-bag version` – display binary version, target, and compiled features (mlock, pq, fuzzing, etc.).
- `black-bag backup keygen/sign/verify` – manage ML-DSA-87 (or legacy Ed25519) authenticity for offline backups.
## CLI Command Reference
| `black-bag init [--mem-kib <KiB>]` | Create a new vault with Argon2id + ML-KEM-1024 wrapping | Default memory cost: 262 144 KiB (256 MiB) |
| `black-bag add <record-type> [...]` | Add login/contact/id/note/bank/wifi/api/wallet/totp/ssh/pgp/recovery records | Sensitive fields captured via hidden prompts |
| `black-bag list [--kind KIND] [--tag TAG] [--query Q]` | Show masked summaries | Combine filters for scoped audits |
| `black-bag get <UUID> [--reveal]` | Inspect records; optionally reveal secrets on a TTY | `--reveal` denied on non-interactive stdout |
| `black-bag totp code <UUID> [--time <UNIX>]` | Generate TOTP codes | Supports historic/time-skew analysis |
| `black-bag rotate [--mem-kib <KiB>]` | Rewrap master DEK with fresh randomness | Optional Argon2 memory override |
| `black-bag doctor [--json]` | Print health diagnostics | JSON output ready for monitoring pipelines |
| `black-bag recovery split/combine` | Manage Shamir shares for disaster recovery | Configurable thresholds and share counts |
| `black-bag backup keygen/sign/verify` | Manage ML-DSA-87 (or Ed25519) backup signatures | Produces `.int` + `.int.sig` companions |
| `black-bag selftest` | Run embedded round-trip checks | Useful after upgrades or migrations |
| `black-bag version` | Display build version, target, and enabled features (`mlock`, `pq`, `fuzzing`) | Validate release binaries |
### Comprehensive CLI Details
Below is a complete list of subcommands, flags, and inputs.
Common
- Global env: `BLACK_BAG_VAULT_PATH` overrides default vault location.
- Optional env: `BLACK_BAG_AUDIT_LOG` appends JSONL authentication events to the given path.
- Hidden prompts: sensitive values are collected interactively (no echo), never via argv.
Init
- `black-bag init [--mem-kib <KiB>]`
- `--mem-kib`: Argon2 memory (KiB). Default: 262144 (256 MiB). Minimum: 131072.
- Prompts: master passphrase (twice).
Add (records)
- Common flags (all add <type>):
- `--title <string>`
- `--tags <t1,t2,...>` (comma separated)
- `--notes <string>`
- Login: `black-bag add login [--username <s>] [--url <s>]`
- Prompts: `Password:` (hidden)
- Contact: `black-bag add contact --full-name <s> [--emails <e1,e2,...>] [--phones <p1,p2,...>]`
- Id: `black-bag add id [--id-type <s>] [--name-on-doc <s>] [--number <s>] [--issuing-country <s>] [--expiry <s>]`
- Prompts: `Sensitive document secret (optional):` (hidden, optional)
- Note: `black-bag add note`
- Prompts: `Secure note body (Ctrl-D to finish):` (multiline)
- Bank: `black-bag add bank [--institution <s>] [--account-name <s>] [--routing-number <s>]`
- Prompts: `Account number / secret:` (hidden)
- Wifi: `black-bag add wifi [--ssid <s>] [--security <s>] [--location <s>]`
- Prompts: `Wi-Fi passphrase:` (hidden)
- Api: `black-bag add api [--service <s>] [--environment <s>] [--access-key <s>] [--scopes <s1,s2,...>]`
- Prompts: `Secret key:` (hidden)
- Wallet: `black-bag add wallet [--asset <s>] [--address <s>] [--network <s>]`
- Prompts: `Wallet secret material:` (hidden)
- Totp: `black-bag add totp [--issuer <s>] [--account <s>] [--secret <BASE32>] [--digits <6|7|8>] [--step <seconds>] [--skew <steps>] [--algorithm <sha1|sha256|sha512>]`
- If `--secret` omitted, prompts: `Base32 secret:` (hidden)
- Defaults: `--digits 6`, `--step 30`, `--skew 1`, `--algorithm sha1`
- Ssh: `black-bag add ssh [--label <s>] [--comment <s>]`
- Prompts: `Paste private key (Ctrl-D to finish):` (multiline, hidden)
- Pgp: `black-bag add pgp [--label <s>] [--fingerprint <s>]`
- Prompts: `Paste armored private key (Ctrl-D to finish):` (multiline, hidden)
- Recovery: `black-bag add recovery [--description <s>]`
- Prompts: `Paste recovery payload (Ctrl-D to finish):` (multiline, hidden)
List / Query
- `black-bag list [--kind <login|contact|id|note|bank|wifi|api|wallet|totp|ssh|pgp|recovery>] [--tag <needle>] [--query <needle>]`
- Outputs masked summaries. Combine filters for precise audits.
Get
- `black-bag get <UUID> [--reveal]`
- Shows metadata; with `--reveal` on a TTY prints sensitive fields.
Rotate
- `black-bag rotate [--mem-kib <KiB>]`
- Rewraps DEK with fresh randomness; optionally adjust Argon2 memory (min 131072).
Doctor
- `black-bag doctor [--json]`
- Human output or JSON with readiness, Argon2 parameters, passphrase rotation timestamp, and mlock probe results.
TOTP
- `black-bag totp code <UUID> [--time <UNIX-seconds>]`
- Generates a code for a stored TOTP secret; `--time` allows historic checks.
Backup (integrity + PQ signatures)
- Keygen (ML‑DSA‑87):
- `black-bag backup keygen --pub-out <path> --sk-out <path>`
- Writes Base64 public key and public||secret concatenated secret blob.
- Sign:
- `black-bag backup sign --path <vault.cbor> --key <secret-key> [--pub-out <path>]`
- Creates/updates: `<vault>.int` (BLAKE3 keyed tag) + `<vault>.int.sig` (ML‑DSA‑87 or Ed25519).
- Verify:
- `black-bag backup verify --path <vault.cbor> [--pub-key <pub-key>]`
- With `--pub-key`, verifies both integrity and signature. Without it, checks only bit‑rot.
Self‑test
- `black-bag selftest`
- Runs an encrypt/decrypt round‑trip sanity check.
Version
- `black-bag version`
- Prints version, target, and compiled features (`mlock`, `pq`, etc.).
### Backup workflow (PQ-safe)
```bash
# one-time: generate ML-DSA-87 keys for signing sidecars
black-bag backup keygen --pub-out backup.mldsa87.pub --sk-out backup.mldsa87.sk
# copy the ciphertext and immediately mint/update integrity + signature sidecars
cp ~/.config/black_bag/vault.cbor /offline/vault-$(date +%Y%m%d).cbor
black-bag backup sign \
--path /offline/vault-$(date +%Y%m%d).cbor \
--key backup.mldsa87.sk \
--pub-out /offline/backup.mldsa87.pub
# later, verify both bit-rot and authenticity before restore
black-bag backup verify \
--path /offline/vault-$(date +%Y%m%d).cbor \
--pub-key /offline/backup.mldsa87.pub
```
The signing command produces two companions next to the ciphertext: `vault-*.cbor.int` (BLAKE3 tag keyed with the ML-KEM public key) and `vault-*.cbor.int.sig` (ML-DSA-87 or Ed25519 signature). Ship all three files together and treat any verification failure as tampering until proven otherwise.
### Rotation, health, and recovery
- `black-bag rotate` – rewraps the master DEK with fresh randomness.
- `black-bag doctor` – prints health info (Argon2 params, feature flags, item counts).
- `black-bag recovery split` / `combine` – manage Shamir shares for catastrophic recovery.
- `black-bag selftest` – quick sanity check of encryption/decryption paths.
- `black-bag version` – confirm binary target/profile and compiled features (`mlock`, `pq`, etc.).
## Threat model (summary)
See [`docs/THREAT_MODEL.md`](docs/THREAT_MODEL.md) for assumptions, adversary capabilities, and residual risks. Treat the vault ciphertext as sensitive and keep backups offline.
## Building and testing
```bash
cargo fmt
cargo clippy --all-targets --all-features
cargo test
```
### Build from source (alternative install)
Prereqs: Rust toolchain 1.81+ (via rustup) and a standard build environment.
```bash
git clone <your-repo-url> black-bag
cd black-bag
cargo build --release
install -m 0755 target/release/black-bag ~/.local/bin/black-bag
black-bag --help
```
CI should run the same three commands on every commit. Tests cover cryptographic round-trips, helper utilities, and zero-trace guarantees.
## Memory Locking (mlock)
On Unix platforms, when built with the default `mlock` feature, black-bag locks sensitive memory (passphrases, DEKs, and secret buffers) using `mlock(2)` for the lifetime of those values and unlocks it on drop. This reduces the risk of secrets being paged to disk.
- Status check: `black-bag doctor` reports whether `mlock` is enabled and functional on the host.
- macOS: `mlock` generally works for unprivileged processes within system limits. If you run into failures, check per-process limits with `ulimit -l` and consider adjusting them in your launch environment.
- Linux: `mlock` requires sufficient `RLIMIT_MEMLOCK` or `CAP_IPC_LOCK`.
- Temporary session limit (KB): `ulimit -l 65536` (example: 64 MiB)
- Or grant the binary capability (use with care): `sudo setcap cap_ipc_lock=+ep $(command -v black-bag)`
Notes:
- Locking is best‑effort; when the OS refuses the lock, black-bag continues to function but warns in `doctor` output. You should raise limits until `doctor` reports `mlock: enabled and working`.
- On non‑Unix targets, the `mlock` feature is ignored and no attempts are made to pin memory.
### Doctor JSON fields
```bash
Emits:
- `ready` (bool): overall health flag
- `recordCount` (number): number of records
- `argonMemKib`, `argonTimeCost`, `argonLanes`: Argon2id params
- `createdAt`, `updatedAt`: RFC3339 timestamps
- `passphraseLastRotated`: RFC3339 timestamp of the last passphrase rotation
- `mlock.enabled` (bool): build/OS support
- `mlock.ok` (bool): lock/unlock probe succeeded
- `mlock.error` (string|null): OS error if locking failed
## Shamir Secret Sharing
The `recovery split` / `combine` commands now use the constant-time GF(2^8) backend from `vsss-rs`, retaining the same CLI and share format (`id-base64`). See docs/SHAMIR.md for details and security notes.
## Configuration
- `BLACK_BAG_VAULT_PATH`: override the default vault path. Useful for testing, multiple vaults, or automation.
- Recommended shell hygiene: `HISTCONTROL=ignorespace` and avoid pasting secrets into terminals; keep `RUST_BACKTRACE=0` in operational shells.
## Troubleshooting
- “mlock: enabled but failed (…)” → Raise OS limits (macOS: check `ulimit -l`; Linux: `ulimit -l 65536` or grant `CAP_IPC_LOCK`).
- “Verify failed” on a backup → Stop; do not restore. Recompute `.int` and re‑verify with the correct `.int.sig` and public key.
- “record … not found” → Use `black-bag list --query <needle>` to locate likely matches, then rerun `get`.
## License
Dual‑licensed under Apache‑2.0 and MIT (your choice). See `LICENSE-APACHE` and `LICENSE-MIT`.
## Mission-ready checklist
- [x] Argon2id + ML-KEM-1024 + XChaCha20-Poly1305 enabled by default
- [x] No GUI, clipboard, or plaintext log exposure
- [x] Cross-platform parity (Windows/macOS/Linux)
- [x] Comprehensive record catalogue with search & tagging
- [x] Lint/tests clean with zero warnings
- [x] Operator docs and threat model committed
For production roll-out, schedule an independent cryptography/code audit and set up fuzzing pipelines (see [`docs/FURTHER_HARDENING.md`](docs/FURTHER_HARDENING.md)).
## Instruction Manual
For a polished, cross-platform instruction manual (macOS, Linux, Windows), see:
- docs/INSTRUCTION_MANUAL.md — professionally formatted manual with installation, operations, backup, and troubleshooting.
The manual covers:
- Install: prerequisites and cargo install on macOS/Linux/Windows
- Basic operations: init, add/list/get, search and filters
- Advanced: rotate, doctor (JSON), totp
- Recovery: split/combine (Shamir via vsss-rs)
- Backup and authenticity: ML-DSA-87 keygen/sign/verify workflow
- Best practices, security considerations, troubleshooting