Skip to main content
joão

2025 — Case Study

Desktop Password Vault

Offline desktop password manager with a Rust security boundary, envelope encryption, authenticated metadata, and local-only persistence.

RustTauri 2React 19TypeScriptViteAES-256-GCMArgon2id
01

Context

Desktop Password Vault is a local password manager built as a secure-software project rather than a cloud service. The React interface manages the unlocked user experience, while Tauri commands keep key derivation, encryption, vault persistence, and the in-memory vault-key session in Rust. Decrypted entries are returned to the UI only after a successful unlock; the raw vault key remains in the Rust session.

02

Architecture

Tauri separates the React webview from the native security-sensitive path. Rust owns cryptographic operations and the per-user unlocked key session, while the frontend works with decrypted entry data only for the active unlocked session.

/src

React + TypeScript — profile selection, unlock flows, credential editing, password generation, clipboard behavior, and automatic locking

lib.rs

Tauri command boundary — validates users, enforces the 12-character master-password minimum, owns the in-memory vault-key session, and exposes narrow native operations

vault.rs

Argon2id + AES-256-GCM — derives the key-encryption key, wraps a random 256-bit vault key, authenticates metadata, encrypts entries, and handles local vault persistence

Tauri CSP

Production webview policy limits content to local application origins, blocks object embedding, and prevents framing with `frame-ancestors 'none'`

03

Engineering Decisions

01

Envelope encryption for password rotation

Credential entries are encrypted with a random 256-bit vault key. The master password derives a separate key-encryption key with Argon2id, which wraps the vault key. Changing the master password derives a new wrapping key and re-wraps the vault key instead of re-encrypting every credential.

02

Authenticate unlock parameters with the wrapped key

The vault version, KDF parameters, and key-file requirement are serialized as AES-GCM associated data for the wrapped vault key. A test modifies the stored version and verifies that the vault can no longer be opened.

03

Keep the raw vault key in the native session boundary

Successful unlock stores the vault key in a Rust Session map keyed by user. React receives decrypted entries while the vault is open, but the raw vault key is not returned to the frontend. Lock and user deletion remove and zeroize the session key.

04

Limit secret lifetime where the architecture allows it

Master-password values and derived key material use zeroizing wrappers in the Rust path. The UI locks after five minutes of inactivity or when minimized, and copied passwords are conditionally cleared after 30 seconds if the clipboard still contains the same value.

05

Defend local file boundaries explicitly

Profile names are restricted before becoming filenames, preventing arbitrary path components. Vault persistence writes a temporary file and then renames it into place; this reduces partial replacement risk without claiming stronger durability guarantees than the implementation provides.