genkey optionally takes a second passphrase that unlocks a separate decoy identity. Every command run with it sees and changes only decoy files; records sealed to the other key are skipped silently. The key file always carries two equal-size slots in random order, with random bytes in an unused slot, and both slots are always tried. init seeds each vault with 8-32 entries sealed to a discarded key, so real files are indistinguishable from filler to a decoy-only holder.
1.9 KiB
1.9 KiB
CLAUDE.md
This file provides guidance to Claude Code when working with this repository.
Overview
vault is a post-quantum encrypted file vault: one package main at the repo
root that builds a single vault binary. Module github.com/andydixon/vault.
main.go- CLI:genkey,init,add,list,get,mv,rm.keyfile.go- key file with two passphrase slots (Argon2id + XChaCha20-Poly1305 sealing a suite ID and 32-byte master seed). The second slot is either a decoy identity or random bytes; slot order is random.store.go- on-disk vault:records/holds fixed-size encrypted catalogue records,objects/holds padded encrypted file bodies. Records a key cannot open are skipped, not treated as errors.internal/pqcrypt- file encryption (header + STREAM ChaCha20-Poly1305), suite registry, hybrid FrodoKEM-640 + ML-KEM-768 default suite.internal/format,internal/stream,internal/term- header encoding, chunked payload encryption, terminal passphrase prompts.
Commands
go test ./...
go build .
End-to-end check:
export VAULT_PASSPHRASE=test VAULT_KEY=$PWD/k VAULT_DIR=$PWD/s
./vault genkey && ./vault init && ./vault add README.md docs && ./vault list
Invariants
- Never write a seed or private key unencrypted.
- Keep suite IDs, stanza tags, HKDF info strings and
fileKeySize(32) stable. - Every ciphertext's mtime is pinned to the epoch; records stay one fixed size; objects stay bucket-padded. These hide metadata from the storage host.
- An object's plaintext starts with its own ID, binding it to its record.
getpublishes output only after the entire object has authenticated.- Decoy deniability: both key slots stay the same size and are both always
tried;
initalways writes filler; foreign records are skipped silently. - Keep dependencies pure Go.
- Diagnostics go to standard error, lower-case, no trailing full stops.