Why v2?
The previous architecture used two separate data keys: a local DEK derived from your PIN to encrypt the on-device database, and a sync DEK derived from your account password to encrypt cloud backups. It worked, but it had a structural problem: if you forgot your password and reset it, a new or cache-cleared device could no longer decrypt the cloud vault. Your data was effectively lost.
v2 rebuilds the key system from the ground up around three principles:
- One data key (DEK), never re-encrypted. Changing any password or key only rewraps the DEK — the encrypted data itself never moves.
- The server never sees your master password. A client-side HKDF split sends only a derived
loginTokento the server; thevaultKEKthat actually unlocks your data never leaves your device. - Every "forgot password" scenario has an explicit path. A mandatory Recovery Key guarantees you can always get back in, even on a brand-new device with no local cache.
The Four-Slot Unified DEK
At the center of v2 is a single 32-byte DEK (Data Encryption Key), generated once at signup and never changed for the lifetime of the account. Every piece of your data — local database, cloud sync blob, attachments — is encrypted with this one key.
The DEK is then wrapped (encrypted) by four independent keys, each stored as its own slot:
- Master Password slot — wrapped by
vaultKEK, derived from your master password via Argon2id. The primary unlock method, works on any device. - PIN slot (optional) — wrapped by a PIN-derived key. Fast unlock on a trusted device.
- Biometric slot (optional) — wrapped by an OS-secured key bound to Face ID / Touch ID / fingerprint. Convenience layer on top of the PIN slot.
- Recovery Key slot (mandatory) — wrapped by a high-entropy key shown to you once at signup. Your last-resort path back to your data.
Because all four slots wrap the same DEK, you can change your master password, reset your PIN, or rotate biometrics without ever re-encrypting your data. Only the affected slot gets rewritten.
How HKDF Keeps the Server Honest
When you type your master password, the client does not send it. Instead, it runs:
vaultKEK = Argon2id(masterPassword, salt)— used locally to unwrap the DEK. Never leaves the device.loginToken = HKDF(masterPassword, "login")— a deterministic, separate value sent to the server purely for authentication.
The server stores only bcrypt(loginToken). Even with a full database breach, an attacker would have to brute-force the master password through bcrypt and Argon2id before they could touch your vault. The vaultKEK itself is mathematically unrecoverable from anything the server holds.
The Recovery Key: Your Insurance Policy
The Recovery Key is generated on your device during signup and shown to you once. You write it down, print it, or store it somewhere safe — we never see it. It does two things:
- Forgot your master password? Enter the Recovery Key on any device. It unwraps the DEK directly, and you immediately set a new master password — your data is intact.
- Lost your only device? The Recovery Key alone, plus your account email, is enough to restore everything on a new device.
This is the same model used by 1Password (Secret Key) and Bitwarden (Recovery Code). It is mandatory in v2 — there is no path to enable sync without setting one.
Multi-Device, Transparent Sync
In v1, logging in on a new device after a password reset could leave you locked out of your cloud data. In v2, the flow is simple:
- Sign in with email + master password on the new device.
- Client downloads your encrypted vault blob from the server.
- Client derives
vaultKEKlocally, unwraps the master-password slot, gets the DEK. - Vault decrypts. Typically under 5 seconds end-to-end.
No cached keys required. No "this device was never sync'd, sorry" failures.
What the Server Can and Cannot Do
| Capability | Server has it? |
|---|---|
| See your master password | ❌ Never |
See your vaultKEK or DEK | ❌ Never |
| See your Recovery Key | ❌ Never (only bcrypt(rk_verifier)) |
| Decrypt your vault blob | ❌ Mathematically impossible |
| Authenticate you | ✅ Via bcrypt(loginToken) |
| Store your encrypted vault blob | ✅ As ciphertext only |
Honest Limits
We hold ourselves to the same security baseline as Bitwarden, and we are honest about what that means:
- v2 is end-to-end encrypted, not a strict zero-knowledge protocol like SRP or OPAQUE. The server briefly holds the
loginTokenin memory at login time before storing only its bcrypt hash. This is the same model as Bitwarden. - A weak master password is the one thing cryptography cannot fix. Use a long passphrase, and keep your Recovery Key safe.
- If your device is compromised by malware (keylogger, memory scraper), no password manager can save you — this is an industry-wide boundary.
Migrating from v1
If you used KeyMe Pass before v2, you will be guided through a one-time migration the next time you unlock the app:
- Your existing data is re-wrapped under the new unified DEK — no data leaves your device during this step.
- You will be asked to set a Recovery Key. This is mandatory before sync can be re-enabled.
- Your master password and PIN continue to work as before; only the underlying key derivation changes.
The Bottom Line
v2 closes the one structural flaw that kept us up at night: the chance that a routine password reset could lose your data. With a unified DEK, four independent unlock slots, client-side HKDF, and a mandatory Recovery Key, every "forgot password" scenario now has a clear, lossless path — and the server learns even less about you than before.