32 lines
5.3 KiB
Markdown
32 lines
5.3 KiB
Markdown
# Local vault security boundary
|
||
|
||
This is a new, unaudited local vault implementation. It uses actual native ML-KEM-1024 in the shipped Electron 44 / Node 24 runtime, not an emulation or a cryptographic fallback. Independent cryptographic and browser-security review is required before production use. It does not claim FIPS validation or audited quantum-safe protection. ML-KEM is a key encapsulation mechanism, not a password-strength mechanism, and does not protect an unlocked or compromised endpoint.
|
||
|
||
Standards and implementation references: [NIST FIPS 203: ML-KEM](https://www.nist.gov/publications/module-lattice-based-key-encapsulation-mechanism-standard), [NIST symmetric cryptography guidance](https://csrc.nist.gov/Projects/post-quantum-cryptography/faqs), and [Node.js native cryptography API](https://nodejs.org/download/release/v24.21.0/docs/api/crypto.html).
|
||
|
||
## Envelope
|
||
|
||
Each vault generates a random 256-bit data key and a native ML-KEM-1024 keypair. Native encapsulation yields a shared key; HKDF-SHA-256 with a vault identifier salt and domain-separated context derives an AES-256-GCM wrapping key for the random data key. The private KEM key is encrypted with a master-password-derived AES-256-GCM key, then protected by the injected Windows user-bound DPAPI adapter. Unlock requires both the master password and the Windows protection factor. DPAPI alone cannot unlock this envelope.
|
||
|
||
The master-password key uses fixed scrypt N=131072, r=8, p=1 (approximately 128 MiB working memory; 192 MiB maximum allowed). Disk parameters cannot select a weaker or excessive KDF. Master passwords must contain at least 16 JavaScript characters, at most 1024; password strength still depends on entropy. Generated credential passwords use cryptographically secure random selection, default 32 characters, minimum 24.
|
||
|
||
Full credential metadata and passwords are encrypted together using AES-256-GCM, fresh random 96-bit nonces and 128-bit authentication tags on each persistence. Associated data binds the format, vault identifier, salt, platform-protected private key, KEM ciphertext, and wrapped data key. File sizes and encoded-field lengths are bounded before expensive cryptography. Ciphertext tampering and wrong factors return a generic refusal and lock the vault.
|
||
|
||
No account origin, username, label, password or master password is stored in plaintext. The outer envelope necessarily reveals format, algorithm-related sizes and ciphertext size; it provides neither padding nor traffic-analysis protection. The format is not a classical/PQC hybrid KEM: it uses ML-KEM plus symmetric encryption.
|
||
|
||
## Browser integration obligations
|
||
|
||
The root/main process supplies trusted DPAPI protect/unprotect callbacks. Production must refuse unavailable Windows protection; portable tests use a simulated authenticated second factor and do not claim to test DPAPI. The engine does not independently validate enterprise enrollment or central policy: main must authorize every operation, enforce administrator disable/revocation, and lock on policy changes, shutdown, OS session lock and explicit logout as applicable.
|
||
|
||
`list()` returns unlocked metadata only and no password. `credential(id, origin)` exposes username/password only to the trusted main fill path and requires the exact stored canonical HTTPS origin, including port. Main must additionally validate the requesting browser session, current committed frame origin and form submission target immediately before filling. A same-origin hostile page or injected script may read a filled password. Filling must not expose values to agent APIs, audit events, chat prompts, general renderer APIs, clipboard, screenshots or logs.
|
||
|
||
The idle timer locks after 60–900 seconds (default 300), refreshed by unlock, credential fill and mutations. Metadata listing and status polling do not refresh it, so background UI polling cannot keep a vault unlocked. Buffers holding keys, plaintext serialization and derived secrets are overwritten on completion/lock. JavaScript immutable strings, cloned credential objects, native crypto KeyObjects, parser allocations, crash dumps, OS paging and garbage-collected copies cannot be reliably erased. Memory protection remains best effort. Windows ACLs, endpoint isolation and crash-dump/pagefile controls must be separately enforced; POSIX-style mode 0600 does not establish a Windows ACL.
|
||
|
||
## Persistence and recovery
|
||
|
||
Writes use a random exclusively created temporary encrypted file, file flush, and atomic rename. A failed save preserves the prior committed file and rolls back the in-memory mutation. Only one process should access a vault; cross-process transactional locking and rollback resistance are not implemented. An attacker able to replace an authenticated old vault file can restore old credential state. Storage does not defend against an administrator or malware executing as the same unlocked Windows user.
|
||
|
||
No sync, export, recovery key, master-password change or Windows-account migration is provided in this iteration. Losing the master password or the Windows DPAPI context can permanently lose access. Backups must preserve both encrypted storage and the appropriate Windows recovery context; there is no cloud copy. Secure deletion of previous encrypted blocks or backups is not guaranteed.
|
||
|
||
References: [Node native cryptography](https://nodejs.org/api/crypto.html) and [NIST FIPS 203](https://csrc.nist.gov/pubs/fips/203/final).
|