Skip to content

johnzfitch/dota

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

36 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Defense of the Artifacts (dota)

Post-quantum secure secrets manager with v7 TC-HKEM vaults (ML-KEM-768 + X25519 with ciphertext binding and passphrase commitment), plus a terminal UI.

Defense-in-depth cryptography: v7 vaults protect secrets with both classical security (X25519) and post-quantum security (ML-KEM-768), combined via the TC-HKEM (Triple-Committed Hybrid KEM) construction. Security holds if either algorithm is secure. Legacy v1v6 vaults are migrated in place to v7 on unlock.

Quickstart

# Install
cargo install --path .

# Initialize vault (stored at ~/.dota/vault.json by default)
dota init

# Launch TUI (default command)
dota

# Or use CLI commands
dota set API_KEY "secret-value"
dota get API_KEY
dota list

How it works

flowchart LR
    A[Passphrase] -->|Argon2id| B[Master Key mk]
    B --> C["ML-KEM-768\nencapsulate → ss_kem, ct_kem"]
    B --> D["X25519 ephemeral DH\n→ ss_dh, eph_pk"]
    B -->|"τ = HMAC(mk, ct_kem ‖ eph_pk)"| E
    C --> E["TC-HKEM combiner\nHKDF(ss_kem‖ss_dh‖ct_kem‖eph_pk‖τ)"]
    D --> E
    E --> F["AES-256-GCM"]
    F --> G[Encrypted Secret]
Loading

TC-HKEM: Each secret is encrypted with AES-256-GCM. The per-secret AES key is derived via the Triple-Committed Hybrid KEM combiner:

  1. ML-KEM-768 encapsulation → 32-byte shared secret (ss_kem) + ciphertext (ct_kem)
  2. X25519 ephemeral DH → 32-byte shared secret (ss_dh) + ephemeral public key (eph_pk)
  3. Passphrase commitment: τ = HMAC-SHA256(mk, ct_kem ‖ eph_pk)
  4. Ciphertext binding: ct_kem and eph_pk are included directly in the HKDF input
  5. HKDF-SHA256(ss_kem ‖ ss_dh ‖ ct_kem ‖ eph_pk ‖ τ, "dota-v7-tchkem-salt", "dota-v7-secret-key") → 32-byte AES key

The vault stores ML-KEM ciphertexts, X25519 ephemeral public keys, and AES-GCM ciphertexts. A canonical authenticated header is protected by HMAC-SHA256 under the passphrase-derived master key before any private-key decryption occurs. The v7 TC-HKEM combiner achieves best-of-both-worlds IND-CCA security and binds the passphrase into every per-secret key derivation.

Features

Post-quantum security
Real ML-KEM-768 (NIST FIPS 203 final standard) — resists quantum computer attacks.
Classical security
X25519 elliptic curve Diffie-Hellman — protects against classical adversaries.
Best-of-both-worlds IND-CCA
TC-HKEM ciphertext binding ensures security if either algorithm holds (GHP18 reduction).
Passphrase commitment
Master key mk is bound into every per-secret key derivation via τ = HMAC(mkct_kem ‖ eph_pk). Knowledge of the KEM private keys alone is insufficient.
Memory safety
Rust with ZeroizeOnDrop for all sensitive types — passphrases, shared secrets, and AES keys are wiped from memory on drop.
Authenticated metadata
version, min_version, algorithm IDs, public keys, and suite are covered by the v7 HMAC-SHA256 key commitment before any private-key decryption.
Automatic migration
Legacy v1v6 vaults upgrade to v7 on unlock; originals are backed up automatically.
Key rotation
dota rotate-keys generates fresh ML-KEM-768 and X25519 keypairs and re-encrypts all secrets.
Export to environment
dota export-env VAR1 VAR2 outputs shell-compatible variable assignments for CI/CD pipelines.
TUI and CLI
Interactive ratatui terminal interface or scriptable command-line operations.

Design constraints

Trust boundary
The vault file must be protected at rest. Use full-disk encryption (LUKS, FileVault, BitLocker) or store on an encrypted volume.
Passphrase strength
Argon2id with 64 MiB memory, 3 iterations, 4 threads (OWASP 2024 recommended parameters). Adjust only if you understand the security tradeoffs.
No network
All operations are fully local. There is no cloud sync, remote key escrow, or telemetry.

Security assumptions

Threat model
Protects against passive adversaries with quantum computers (harvest-now-decrypt-later attacks). Does not protect against active quantum adversaries or compromised endpoints.
Algorithm choices
v7 uses ML-KEM-768 (post-quantum), X25519 (classical), AES-256-GCM (authenticated encryption), HKDF-SHA256 (TC-HKEM combiner), and HMAC-SHA256 (header commitment + passphrase binding).
Side channels
No explicit protection against timing or cache attacks beyond what the underlying cryptography libraries provide.
Cryptographic details

Key derivation

  1. Passphrase → Argon2id (64 MiB, 3 iterations, 4 threads, 32-byte master key mk)
  2. mk → purpose-labeled wrapping keys for encrypting the ML-KEM-768 and X25519 private keys, HMAC-SHA256 header commitment, and TC-HKEM passphrase commitment τ
  3. ML-KEM-768 and X25519 keypairs are generated from OsRng and stored encrypted in the vault (no deterministic derivation from mk)

Secret encryption (TC-HKEM)

1. ML-KEM-768 encapsulate(pk_kem)  → (ss_kem, ct_kem)
2. X25519 ephemeral DH(pk_x25519)  → (ss_dh, eph_pk)
3. τ = HMAC-SHA256(mk, ct_kem ‖ eph_pk)
4. IKM = ss_kem ‖ ss_dh ‖ ct_kem ‖ eph_pk ‖ τ    (≈ 1216 bytes for ML-KEM-768)
5. aes_key = HKDF-SHA256(IKM, "dota-v7-tchkem-salt", "dota-v7-secret-key")
6. (ciphertext, tag) = AES-256-GCM(plaintext, aes_key, random_nonce)

Security properties:

  • Theorem 1 — Best-of-both-worlds IND-CCA: Adv ≤ Adv_ML-KEM^{ind-cca}(B₁) + Adv_X25519^{gap-cdh}(B₂) + q_H/2^256. Ciphertext binding enables the B₁ reduction.
  • Theorem 2 — Passphrase binding: Adv^{mk-bind} ≤ Adv_HMAC^{prf}(B₃) + q_H/2^256. Knowledge of (dk, sk_dh) alone is insufficient without mk.

Vault format

JSON structure with versioning (current: v7, suite: dota-v7-tchkem-mlkem768-x25519-aes256gcm):

version
Protocol version for forward compatibility. Current: 7.
min_version
Anti-rollback floor — vault is rejected by implementations older than this version.
kdf
Argon2id parameters: algorithm, salt, time_cost, memory_cost, parallelism.
key_commitment
HMAC-SHA256 over the canonical header (version, min_version, KDF params, algorithm IDs, public keys, suite). Verified before any private-key decryption.
kem
ML-KEM-768 public key and AES-256-GCM-wrapped private key.
x25519
X25519 public key, algorithm label, and AES-256-GCM-wrapped private key.
suite
Active cipher-suite identifier: dota-v7-tchkem-mlkem768-x25519-aes256gcm.
secrets
Map of name → {algorithm, kem_ciphertext, x25519_ephemeral_public, ciphertext, nonce, created, modified}.
migrated_from
Original version and migration path for vaults upgraded from older formats.

Commands

dota init
Initialize a new vault at ~/.dota/vault.json (or --vault PATH).
dota  /  dota unlock
Launch the interactive TUI (default command when no subcommand is given).
dota set NAME VALUE
Store or update a secret. Omit VALUE to read from stdin or an interactive prompt.
dota get NAME
Print a secret value to stdout.
dota list
List all secret names (values are never printed).
dota rm NAME
Permanently remove a secret.
dota export-env [NAMES…]
Print export KEY=VALUE lines for the named secrets (or all secrets if no names given). Safe to eval in shell scripts.
dota change-passphrase
Re-derive the master key and re-wrap all private key material under a new passphrase.
dota rotate-keys
Generate fresh ML-KEM-768 and X25519 keypairs and re-encrypt all secrets.
dota upgrade
Explicitly migrate the vault to the current format version (v7). Migration also happens automatically on any unlock.
dota info
Show vault metadata: version, suite, KDF parameters, key commitment status, and secret count.

All commands accept --vault PATH to override the default vault location.

TUI keyboard shortcuts
j / k  or  /
Navigate the secrets list.
Enter
Copy the selected secret value to the clipboard.
n
Create a new secret (prompts for name and value).
e
Edit the selected secret’s value.
d
Delete the selected secret (requires confirmation).
r
Rotate all encryption keys.
q
Quit.

Troubleshooting

  • Failed to decrypt vault: Incorrect passphrase or corrupted vault file. Check ~/.dota/vault.json.
  • Slow unlock: Argon2id intentionally uses 64 MiB RAM and 3 iterations with 4 threads. This takes roughly 1–3 seconds on modern hardware and is by design.

Development

# Run all tests
cargo test

# Run with debug logging
RUST_LOG=debug cargo run

# Check formatting and lints
cargo fmt --check && cargo clippy

# Build optimized release binary
cargo build --release

License

MIT

Citation

If you use this in research or security audits:

@software{dota2026,
  author = {Fitch, Zack},
  title = {Defense of the Artifacts: Post-quantum secure secrets manager},
  year = {2026},
  url = {https://github.com/johnzfitch/dota}
}

About

Defense of the Artifacts - Post-quantum secure secrets manager with TUI

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors