Zero-knowledge encryption, explained for developers
What "the server can't read your data" actually means: key derivation, key wrapping, AEAD, and the specific hierarchy nvault uses to make it true.
"Zero-knowledge" is an overloaded phrase. In nvault's case it has a precise, checkable meaning: the server never holds the information needed to decrypt your files. Here is how that is arranged.
Passwords are not keys
A passphrase is low-entropy and human-chosen; an encryption key needs to be high-entropy and uniform. You bridge the gap with a key derivation function. nvault uses PBKDF2-HMAC-SHA256 with a large iteration count and a random 128-bit salt per user. The iteration count is stored per user, so it can be raised over time without breaking existing vaults — re-derivation just happens on the next unlock.
vault passphrase
│ PBKDF2-HMAC-SHA256 (many iterations, random salt)
▼
Key Encryption Key (KEK) — derived fresh on every unlock, never storedKey wrapping: a chain, not a single key
If the passphrase directly encrypted every file, changing it would mean re-encrypting everything. Instead the KEK only ever encrypts ("wraps") the next key down:
KEK ──wrap──▶ Master Key (one per account, random 256-bit)
Master Key ──wrap──▶ Project Key (one per project, random 256-bit)
Project Key ──encrypt──▶ file version ciphertextThe server stores the master key and project keys only in wrapped form (wrappedMasterKey, wrappedProjectKey). Without the KEK — which requires the passphrase — they are meaningless bytes. Changing your passphrase re-wraps one key, not your whole history.
AEAD and bound identifiers
Every encryption step uses AES-256-GCM, an authenticated cipher: decryption fails loudly if the ciphertext was tampered with. nvault also passes an identifier as *additional authenticated data* at each step — "master-key", "project:<id>", "<contentId>". The identifier is not secret, but it is covered by the authentication tag, so a blob encrypted for one record cannot be silently swapped onto another; the tag check fails.
What this buys you
- A database dump reveals metadata and doubly-encrypted blobs — no secrets. (There is a second server-side layer on top of this.)
- A malicious or compelled operator cannot produce plaintext they never had the keys for.
- A bug that logs a request body logs ciphertext, not secrets.
The honest cost
Your development environment, available anywhere.
Create a vault, push your first project, and restore it anywhere.