KeyQuorum

Rust · Aug 2026 – present

Secure file sharing centered on hardware key sharing. A file’s data key — or any secret — can be split recursively into a tree. Unlocking means reconstructing that tree, not presenting a single token or password.

0.1.0
Current CLI version
29
Commits since scaffolding on 24 Aug 2026
2-of-3
Quorum split in the shipped demo
<2 weeks
From scaffold to a hardened mailbox relay

Applied cryptography and CLI security

A Rust CLI for hardware-key quorum file sharing — recursive M-of-N secret-sharing trees, PIN unlock windows, and a sealed mailbox relay, with secrets never accepted as a command-line argument.

Why it exists

KeyQuorum implements recursive M-of-N secret sharing for hardware-backed keys: a master secret splits into a tree of departmental and team shares, and reconstructing it requires quorum agreement rather than a single password or token. It also includes a sealed mailbox relay for exchanging shares without a central party ever seeing the underlying secret.

Run the security lab

The KeyQuorum Security Lab compiles the project's real quorum, custody, approval, visibility, sealed-delivery, and eviction logic to WebAssembly. It uses seeded people and mock USB drives so the workflow is safe to explore in the browser. The live build is embedded below from the KeyQuorum repository.

Running it

A 2-of-3 split across three departments, the tree it produces, and a reconstruct that returns the original secret from two shares while the third is skipped. The prompt on the last command is the point: the CLI asks for the missing key rather than accepting it as an argument, so secrets stay out of shell history.

keyquorum 0.1.0 · throwaway demo database

$ keyquorum split --label master --threshold 2 \
    --leaf Acme.Engineering=engineering.pub \
    --leaf Acme.Finance=finance.pub \
    --leaf Acme.Security=security.pub --generate-keys --register
Registered Acme.Engineering as hardware key 1
Registered Acme.Finance as hardware key 2
Registered Acme.Security as hardware key 3
44ccc34d660a918017…
Split key 1; secret printed to stdout above — this tool keeps no copy of it.

$ keyquorum tree 1
master (key 1)
Acme (node 1) [2 of 3]
  Acme.Engineering (node 2) -> hardware key 1 (Acme.Engineering)
    allowed bridges: Acme.Finance, Acme.Security
  Acme.Finance (node 3) -> hardware key 2 (Acme.Finance)
    allowed bridges: Acme.Engineering, Acme.Security
  Acme.Security (node 4) -> hardware key 3 (Acme.Security)
    allowed bridges: Acme.Engineering, Acme.Finance

$ keyquorum reconstruct 1 --share-file engineering.key --share-file finance.key
Key for 'Acme.Security' (node 4, hardware key 3; blank to skip): 
44ccc34d660a918017…

Real output, captured 16 Sep 2026 from cargo build --release at commit c576804, against a throwaway database created for this run. The secret is abbreviated here; in the session the reconstructed value matched the one split printed, character for character.

Since pull request #71 the everyday tasks are one short verb each. setup creates the device container, provisions a slot, registers and binds its keys, and remembers the identity, so doctor and send can leave --as and --slot out. inbox and inbox open are the receiving side; they need a relay, so this run stops at the sealed letter.

keyquorum 0.1.0 · throwaway demo database · short verbs

$ keyquorum setup --device ./usb-bob --label Acme.Bob
Initialized ./usb-bob device fe8be5d905ea7e4dc9988575f0ca7269
Passphrase for Acme.Bob: 
Repeat passphrase for Acme.Bob: 
Provisioned slot Acme.Bob
Registered encryption key for Acme.Bob
Registered signing key for Acme.Bob
Bound Acme.Bob to device fe8be5d905ea7e4dc9988575f0ca7269
default_container = ./usb-bob
default_label = Acme.Bob
default_slot_label = Acme.Bob
caching = on
note: no relay yet; add one with `keyquorum use --url URL` and `keyquorum loadkey`

$ keyquorum setup --device ./usb-alice --label Acme.Alice
Initialized ./usb-alice device 7a3d025e678c2d1a0bdbc3bdcdceffde
Passphrase for Acme.Alice: 
Repeat passphrase for Acme.Alice: 
Provisioned slot Acme.Alice
Registered encryption key for Acme.Alice
Registered signing key for Acme.Alice
Bound Acme.Alice to device 7a3d025e678c2d1a0bdbc3bdcdceffde
default_container = ./usb-alice
default_label = Acme.Alice
default_slot_label = Acme.Alice
caching = on
note: no relay yet; add one with `keyquorum use --url URL` and `keyquorum loadkey`

$ keyquorum doctor --to Acme.Bob
ok    acting as Acme.Alice (slot Acme.Alice in ./usb-alice)
ok    slot Acme.Alice is in the container (checked recently)
ok    encryption key is registered in this store
ok    signing key is registered in this store
ok    the slot is bound to its device
info  no relay is set; sends go to ./outbox (add one with `keyquorum use --url URL`)
ok    Acme.Bob has a registered encryption key
info  caching is on
Everything checks out.

$ keyquorum send report.txt --to Acme.Bob
note: no relay is set up, so the letter is written to ./outbox; see `keyquorum use --url` and `keyquorum loadkey`
Passphrase for Acme.Alice: 
Sealed report.txt to Acme.Bob (delivery a50dbfdd74a257fc8e84593616837b8c)
Wrote outbox/a50dbfdd74a257fc8e84593616837b8c.kqpb

Real output, captured 3 Oct 2026 from cargo build --release at commit 72c9bd7 (#71), against a throwaway database and two throwaway device folders. Device ids and the delivery id differ on every run. The passphrase prompts were answered by a script and are not echoed.

Read the technical write-up

What it is

The README is unusually precise about status: the CLI covers the concept, quorum split/reconstruct is implemented in software, and USB tokens are still on the roadmap. That honesty matches the git pace. The repo is created 24 Aug 2026 and, within days, has a SQLite store, a guarded share schema, a CLI that prompts for secrets instead of taking them as arguments, and review passes that close deletion races and hash leaks.

A flat M-of-N quorum is the simplest tree. The interesting case is organizational: a company master key splits across departments, and a department share splits again across a team. tree --node A B finds the lowest common ancestor; reconstruct starts there. Bridges let independent employee and manager stores sign across a cut without merging private subtrees.

Features in the order they were added

Day one store. PR #2 lands the local SQLite schema and guards against unsafe share deletion and type confusion. The same day: password manager, expiring share links, password-locked files, then the keyquorum binary with file permission and path checks.

Registry and trees. 25 Aug adds generate/register/list, recursive splits, signature verification, export bundles, PIN unlock windows, and pin relock. Review PRs fix share-file validation, weak-key checks, and transaction cleanup.

Arena, LCA, PSS. 30–31 Aug: arena-allocated trees, LCA reconstruct, cross-branch bridges, PSS eviction, and private sign bridges between stores that do not share a canonical document.

Mailbox, then restraint. 1 Sep introduces an Axum mailbox with API keys and Swagger, immediately reverts it, then re-lands a hardened relay (merge, URL, store integrity). 2 Sep adds date-based TTL and a signed provider identity for minting customer keys — and drops network presence checks from the product. The mailbox is a sealed-envelope router; it never unwraps .kqpb packages.

KeyQuorum on GitHub — the full commit history and source.