MCPcopy Index your code
hub / github.com/PentHertz/LUKSbox

github.com/PentHertz/LUKSbox @v0.4.0

Chat with this repo
repository ↗ · DeepWiki ↗ · release v0.4.0 ↗ · + Follow
2,286 symbols 10,181 edges 147 files 621 documented · 27% updated 1d agov0.5.0-rc.2 · 2026-07-06★ 6204 open issues
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

LUKSbox

LUKSbox

Encrypted vaults that survive the next decade.

Open-source, FIDO2 + TPM 2.0 native, post-quantum-ready.

Store sensitive files in the cloud or on shared media without trusting the host.

Built by Penthertz

Website | Docs | Security | Fuzzing | Compare

License: Apache-2.0 Made with Rust Status: pre-1.0


What it solves

You probably already store sensitive files where you don't fully control the storage: cloud sync (iCloud, Drive, Dropbox, OneDrive, S3, Backblaze), NAS units, USB sticks that travel, backup tapes that end up at a recycler. The provider promises encryption-at-rest "with their keys." LUKSbox encrypts the file before it ever leaves your machine, under your keys, in a single container that is opaque to the provider and tamper-evident on the way back.

A LUKSbox vault is one file (.lbx), optionally with a separate header (.hdr) and post-quantum sidecar (.kyber) that you keep on different storage. Drop it on any cloud or shared medium. The provider sees one indistinguishable-from-random blob and cannot decrypt it even under legal compulsion. Mount it locally as a real drive when you need to use it.

Concern Plain cloud upload Cloud + provider encryption LUKSbox vault on cloud
Provider can read your files Yes Yes (they hold the key) No
Government request to provider exposes data Yes Yes No
Silent file tamper detected No Sometimes (TLS in transit only) Yes (per-chunk AEAD)
Whole-vault rollback detected No No Yes (anchor sidecar)
"Harvest now, decrypt later" (post-quantum) Vulnerable Vulnerable ML-KEM-768/1024 hybrid slot
Hardware-key requirement to open N/A Provider-specific FIDO2 / TPM / Windows Hello
Vault file looks like random data No No Yes (with detached header)
Source you can audit No No Yes (Apache-2.0)

The full per-tool comparison (vs LUKS2 / VeraCrypt / age / gocryptfs / Cryptomator / BitLocker / FileVault) lives at https://luksbox.penthertz.com/compare/.

A LUKSbox vault is a travelling copy, not a master copy. Use it for the cloud, a USB stick, a vault you share with a colleague or client, anywhere you would not put plaintext. Like every encrypted container it is a single point of failure: if the .lbx file is corrupted or every keyslot becomes inaccessible, the data is gone. The forensic toolkit (header-backup, check, extract --tolerate-errors) helps in many damage scenarios but cannot recover bytes that are no longer on disk or no longer AEAD-tagged. Always keep an unencrypted copy somewhere you trust for any file you cannot afford to lose.


Status

This is a pre-1.0 release. The on-disk format is locked, the cryptographic primitives are NIST/RFC standards built on RustCrypto, and 9 internal audit rounds have shipped. External paid audit and broader real-world deployment are the next milestones. The cloud-storage threat model, provider can't read your data even under subpoena, is what LUKSbox is built for and what it does today.

Surface State
cargo test --workspace 200+ passing, 0 failing, 0 ignored
cargo audit (Linux/macOS) 0 vulns / 0 unsound / 0 unmaintained
cargo audit (Windows) 1 unmaintained (registry, transitive via WinFsp)
Internal audit rounds 9 documented at https://luksbox.penthertz.com/docs/security/audit/ (per-round details kept internal)
Third-party audit not yet performed; engagement scope package available on request to security@penthertz.com
Fuzz iterations across 10 libFuzzer harnesses 30M+

How a vault is opened

flowchart LR
    User[User knowledge

passphrase or PIN] --> Unlock[Unlock material]
    FIDO[FIDO2 authenticator

hmac-secret] --> Unlock
    TPM[TPM 2.0

sealed KEK] --> Unlock
    PQ[ML-KEM seed file

separate storage] --> Unlock

    Unlock --> KEK[Key encryption key]
    KEK --> MVK[Master volume key]
    MVK --> HeaderMac[Header HMAC key]
    MVK --> MetadataKey[Metadata AEAD key]
    MVK --> FileKeys[Per-file HKDF keys]
    MVK --> AnchorKey[Anchor HMAC key]

    HeaderMac --> Header[Authenticated header]
    MetadataKey --> Metadata[Encrypted metadata tree]
    FileKeys --> Chunks[Encrypted file chunks]
    AnchorKey --> Anchor[Rollback anchor]

The Master Volume Key (MVK) is the root secret. Keyslots do not encrypt files directly; they wrap the MVK. Once a valid keyslot unwraps the MVK, every other key in the vault is derived from it via HKDF-SHA256 with a per-purpose info string. Lose the keyslot material, lose the MVK; revoke a slot and that material is permanently unable to recover the MVK from this vault.

For the full architecture map (on-disk graph, unlock sequence, concurrency / crash-safety pipeline, on-disk footprint), see https://luksbox.penthertz.com/docs/security/architecture/.


Security mechanisms

Mechanism What it does Where it lives
AES-256-GCM-SIV (default) / AES-256-GCM / ChaCha20-Poly1305 AEAD on every file chunk and on the metadata blob crates/luksbox-core/src/aead.rs
HMAC-SHA256 over the entire 8 KiB header Detects header tampering once a keyslot unwraps the MVK crates/luksbox-core/src/header.rs
HKDF-SHA256 with per-purpose info strings Derives every subkey from the MVK; uniqueness verified by regression test crates/luksbox-core/src/key.rs
Argon2id (default 256 MiB / 3 / 4) Stretches passphrases; cost params bounded by parser to reject DoS attempts crates/luksbox-core/src/kdf.rs
FIDO2 hmac-secret (CTAP2 sec.6.5) Hardware-backed unlock, wrap mode or direct mode crates/luksbox-fido2/
TPM 2.0 sealed KEK (Linux) Bind a vault to the local chip; optional PIN; fused TPM+FIDO2 mode crates/luksbox-tpm/
ML-KEM-768 / ML-KEM-1024 (FIPS 203) Post-quantum half of every hybrid keyslot; classical+PQ mixed via HKDF crates/luksbox-pq/
Per-chunk AAD (file_id || chunk_index || generation) Detects chunk substitution, position swap, and replay of older chunks at the same position crates/luksbox-vfs/src/chunk.rs
Detached header sidecar (.hdr) Vault file alone is opaque random, no magic, no version, no keyslots crates/luksbox-format/src/container.rs
Anchor sidecar (.anchor) External rollback detection via MVK-keyed HMAC over a generation counter crates/luksbox-format/src/anchor.rs
Lock-before-read open Concurrent enrolls / revokes can't race on the keyslot table crates/luksbox-format/src/container.rs::open
Post-lock path-inode re-stat Catches narrow open-then-rename TOCTOU swaps with Error::PathSubstituted crates/luksbox-format/src/container.rs::verify_path_inode
Atomic temp + rename + parent-dir fsync All sidecar writes survive power loss; works on POSIX (fsync on dir handle) and Windows (FILE_FLAG_BACKUP_SEMANTICS + FlushFileBuffers) crates/luksbox-core/src/file_util.rs
O_NOFOLLOW on plaintext extraction luksbox get refuses pre-existing symlink destinations to defeat attacker-staged symlink-target overwrites crates/luksbox-core/src/file_util.rs::secure_create_or_truncate
memfd_secret(2) for the unlocked MVK on Linux 5.14+ Excludes the MVK from coredumps and hibernate images; mlock + Zeroize fallback elsewhere crates/luksbox-core/src/secret_box.rs
Workspace-wide Zeroizing audit on every secret-bearing intermediate AEAD plaintext, HKDF I/O, ML-KEM shared, CLI/GUI PIN copies all scrub on drop covered across luksbox-core, luksbox-pq, luksbox-tpm, luksbox-cli

The full attack matrix (defended vs not defended) is at https://luksbox.penthertz.com/docs/security/threat-model/.


Quick start

# Create a vault (defaults: AES-256-GCM-SIV, Argon2id interactive)
luksbox create my-vault.lbx

# Mount it on a drive letter / mountpoint
luksbox mount my-vault.lbx /mnt/v       # Linux/macOS
luksbox mount my-vault.lbx Z:           # Windows

# Add a FIDO2 hardware factor
luksbox enroll my-vault.lbx --kind fido2

# Add a TPM 2.0 keyslot bound to this machine (Linux)
luksbox enroll my-vault.lbx --kind tpm2

# Hybrid post-quantum: needs a separate `.kyber` seed file
luksbox create my-vault.lbx --kind hybrid-pq \
    --pq-hybrid /media/usb/my.kyber

# v3 format: no per-vault size ceiling (default v2 caps around 10 GiB).
# Old LUKSbox binaries refuse v3 vaults -- opt in only when you need
# bigger vaults than the v2 default can hold.
luksbox create my-vault.lbx --format v3

# Migrate an existing v2 vault to v3 (source untouched)
luksbox migrate-to-v3 old-v2.lbx --dst new-v3.lbx

# Interactive walkthrough, no flags to remember
luksbox wizard

Three interfaces, one on-disk format: the luksbox CLI for scripts, the luksbox wizard interactive TUI, and the luksbox-gui desktop application. See https://luksbox.penthertz.com/docs/ for per-flow walkthroughs.


Install

Platform Method
Debian / Ubuntu / Mint .deb from Releases, sudo apt install ./luksbox_*_amd64.deb
Fedora / RHEL / Rocky .rpm from Releases, sudo dnf install ./luksbox-*.x86_64.rpm
macOS .dmg from Releases, drag to /Applications, install macFUSE on first run
Windows LUKSboxSetup.exe from Releases (bundles WinFsp); IT admins can use the bare .msi and install WinFsp separately
From source cargo build --release -p luksbox-cli -p luksbox-gui after the deps in BUILDING.md

The .deb and .rpm packages now Recommend tpm-udev + tpm2-tools (Debian / Ubuntu) and tpm2-tss + tpm2-tools (Fedora / RHEL / openSUSE), so installing them via apt / dnf brings the /dev/tpm* udev rules and the tss system group along for the ride. After install you still need to add yourself to the group once and log back in, that is the Debian / Fedora convention for any package that grants new device access:

sudo usermod -aG tss "$USER"
# log out + log back in, then verify:
id | tr , '\n' | grep tss

The Linux release tarball's dist/install.sh --tpm-setup does the same thing for users who installed via tarball instead of apt / dnf and don't have tpm-udev / tpm2-tss already.


Help find bugs

LUKSbox is a young codebase. The cryptography rests on standardised primitives and well-audited Rust libraries (RustCrypto, libfido2, tss-esapi), but the integration layer and the on-disk format are ours. We want external eyes on this.

Run the fuzzers

Every parser that touches attacker-controlled bytes has a libFuzzer harness in fuzz/ and an AFL++ harness in fuzz-afl/. PR CI runs each libFuzzer target for 5 minutes on the persistent corpus; a dedicated server runs the AFL++ campaigns for hours per release.

cargo install cargo-fuzz
cd fuzz
cargo +nightly fuzz run header_parse -- -max_total_time=300

The current target list (header_parse, keyslot_parse, metadata_parse, hybrid_sidecar_parse, seed_file_parse, auth_then_process, header_roundtrip, winfsp_path_parse, webauthn_device_path, vfs_ops) plus per-target invariants is in FUZZING.md.

Add corpus seeds

The fastest way to push fuzzing further is dropping a real-world input file into fuzz/corpus/<target_name>/ and opening a PR. Examples that would help today:

  • Real headers from old vault layouts (V1 / V2) for header_parse
  • Authenticator-specific cred IDs (Google Titan, SoloKey stateless, Trezor) for keyslot_parse
  • Edge-case Windows paths (UNC, network share, long path with device-namespace prefix) for winfsp_path_parse
  • Truncated / extended .hybrid sidecars for hybrid_sidecar_parse

Add a new fuzz target

If a parser doesn't have a harness yet and you can imagine an attacker shaping its input, please add one. See the harness template in FUZZING.md.

Suggest a regression test

If you spot a code path where invariants aren't tested but feel like they should be, file a regular GitHub issue (label security-regression) with the invariant in plain English. We write the test and credit the suggestion in the changelog.

Run the AFL++ campaign

scripts/fuzz_server.sh runs an AFL++ campaign indefinitely against any target. If you have spare cycles and want to find something the libFuzzer 5-minute PR run misses, this is the lever.


Reporting issues

Category Channel Priority
Suspected vulnerability (key recovery, plaintext disclosure, authentication bypass, FUSE/WinFsp escape, integer / memory unsafety reachable via a crafted vault file) Email `security@penthertz

Extension points exported contracts — how you extend this code

Fido2Authenticator (Interface)
All operations require user presence (touch). Operations may also require a PIN if the authenticator was provisioned wit [4 …
crates/luksbox-fido2/src/authenticator.rs
LbxFile (Interface)
Abstraction over the backing storage for the `.lbx` file. Real production code uses `std::fs::File`; the crash-impact te [3 …
crates/luksbox-format/src/container.rs
Filesystem (Interface)
(no doc) [2 implementers]
crates/luksbox-fuse-t/src/lib.rs

Core symbols most depended-on inside this repo

open
called by 356
crates/luksbox-core/src/aead.rs
label
called by 322
crates/luksbox-gui/src/app.rs
as_bytes
called by 291
crates/luksbox-core/src/key.rs
clone
called by 236
crates/luksbox-gui/src/app.rs
is_empty
called by 226
crates/luksbox-core/src/keyslot.rs
write
called by 195
crates/luksbox-pq/src/seed_file.rs
as_ref
called by 184
crates/luksbox-fido2/src/authenticator.rs
persist_header
called by 123
crates/luksbox-format/src/container.rs

Shape

Function 1,491
Method 598
Class 133
Enum 61
Interface 3

Languages

Rust100%

Modules by API surface

crates/luksbox-vfs/src/vfs.rs203 symbols
crates/luksbox-format/src/container.rs192 symbols
crates/luksbox-gui/src/app.rs146 symbols
crates/luksbox-cli/src/main.rs128 symbols
crates/luksbox-gui/src/ops.rs124 symbols
crates/luksbox-cli/src/wizard.rs109 symbols
crates/luksbox-core/src/keyslot.rs89 symbols
crates/luksbox-core/src/file_util.rs68 symbols
crates/luksbox-core/src/deniable.rs52 symbols
crates/luksbox-cli/tests/functional.rs48 symbols
crates/luksbox-mount/src/fuse.rs44 symbols
crates/luksbox-core/src/header.rs44 symbols

For agents

$ claude mcp add LUKSbox \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact