Local-first, modular password manager written in Rust.
Status: pre-alpha. Do not store real credentials yet.
- Local-first: vault stored encrypted on disk, never sent anywhere by default.
- Modular: a small Rust core (
pm-crypto,pm-core,pm-storage) usable by any frontend (CLI, GUI, mobile, sync). - Strong crypto: XChaCha20-Poly1305 AEAD + Argon2id KDF + per-record encryption.
- Master password = key wrapper: changing the master password is O(1), it does not re-encrypt the database.
What this design tries to defend against:
| Threat | Defense |
|---|---|
| Stolen DB + offline brute-force | Argon2id (auto-tuned, ≥256 MiB) + HMAC-protected header (anti-downgrade) |
| User-space malware reading the file | Argon2id slows brute-force; zeroize-on-drop + keys page-locked in RAM (mlock/VirtualLock, best-effort) |
| Lost PC, vault locked | KDF + auto-lock agent |
| Lost PC, vault unlocked | Idle auto-lock (default 10 min) + explicit pm lock |
| Offline tampering of the SQLite DB | AEAD per record + AAD = id‖version‖updated_at + header HMAC |
| Side-channel timing on crypto ops | RustCrypto constant-time + subtle::ConstantTimeEq for comparisons |
| Clipboard leak | Auto-clear after 30 s; pm get doesn't copy unless --copy |
What this design does NOT defend against:
- Malware running with root / privilege escalation — a full system compromise can read anything.
- Keyloggers capturing the master password.
- Screenshots / screen scrapers while the vault is unlocked.
- Physical attacks with hardware access (cold boot, JTAG, etc.) — out of scope.
master password
│ Argon2id(salt, m,t,p)
▼
KEK (Key Encryption Key)
│ XChaCha20-Poly1305 wrap
▼
DEK (Data Encryption Key, random)
│ HKDF-SHA256 (per-domain)
├──► K_records — record blob encryption
├──► K_index — HMAC blind index for lookups
└──► K_header — HMAC-SHA256 of vault header (anti-downgrade)
The desktop GUI (Tauri 2 + Svelte 5, in apps/pm-gui) is the primary frontend; the CLI is frozen at the login-only feature set.
The on-disk vault format is fully specified in FORMAT.md so
that independent readers can be implemented without consulting the source.
Every release artifact is signed with minisign.
The public key lives in minisign.pub at the repo root:
RWR3gyR2d0W/aXEwxyu2n0K9UB/EmvTQyXQzRRfo4xPaCRT5L/wHbbf/
To verify a downloaded artifact (and the checksum list):
minisign -Vm SHA256SUMS.txt -P RWR3gyR2d0W/aXEwxyu2n0K9UB/EmvTQyXQzRRfo4xPaCRT5L/wHbbf/
sha256sum -c --ignore-missing SHA256SUMS.txtOS-level code signing (Windows SmartScreen / macOS Gatekeeper) is not active yet — first launch will show a warning on those platforms.
MPL-2.0