End-to-end encrypted · Zero-knowledge · Client-side keys

Private Data Manager
Built for Privacy

Account credentials, passwords, and sensitive data — encrypted with ECDH P-256 and AES-GCM-256 entirely in your browser. The server only ever stores ciphertext.

AES-GCM-256ECDH P-256PBKDF2-SHA-256200,000 iterationsWebCrypto APIZero-Knowledge

Security-first architecture

Every design decision prioritises your privacy. Your keys never leave your browser.

End-to-End Encryption

Data is encrypted with AES-GCM-256 before any network request. Each field gets a unique random IV — replay attacks are impossible.

AES-GCM-256 · Unique IV per field

Zero-Knowledge Server

The server stores only ciphertext. No encryption keys, no plaintexts, no passphrases ever touch the backend — not even during setup.

Server sees: ciphertext only

Passphrase-Derived Keys

Your wrapping key is derived from your passphrase using PBKDF2 with 200,000 iterations and a user-specific salt, making brute-force infeasible.

PBKDF2 · SHA-256 · 200k iterations

ECDH Key Distribution

Organisation keys are wrapped per-user via ephemeral ECDH P-256 key exchange. Adding a new team member re-wraps the org key — it's never transmitted in the clear.

ECDH P-256 · Ephemeral key exchange

Passphrase Re-derivation

Lose your session? Your passphrase re-derives exactly the same wrapping key using PBKDF2. No key escrow, no recovery codes — by design.

Deterministic · No key escrow

How it works

From passphrase to encrypted field — four deterministic steps.

1

Enter your passphrase

Your passphrase is used locally — it is never sent to the server. PBKDF2 (SHA-256, 200,000 iterations) derives a deterministic AES-GCM-256 wrapping key from your passphrase and a salt generated from your user ID.

PBKDF2(passphrase, SHA-256(userId), 200_000, 32, SHA-256)
derives wrapping key →
2

Decrypt your private key

Your ECDH P-256 private key is stored encrypted (AES-GCM) in the database. The wrapping key decrypts it client-side. A failed AES-GCM tag means an incorrect passphrase — no roundtrip needed.

privateKey = AES-GCM.decrypt(wrappingKey, encryptedPrivKey)
unlocks private key →
3

Recover the organisation key

The org key (32 random bytes) was wrapped for you via ephemeral ECDH. Your private key performs the ECDH agreement, recovering the shared secret, which decrypts the org key — all in the browser.

orgKey = AES-GCM.decrypt(ECDH(privateKey, ephPub), wrappedOrgKey)
unlocks org key →
4

Decrypt your data

Every sensitive field (passwords, email credentials, account data) is encrypted with AES-GCM-256 using the org key. Each field has a unique 12-byte random IV prepended to the ciphertext.

plaintext = AES-GCM.decrypt(orgKey, IV || ciphertext)

Your data stays yours

Invite-only access. Every account is end-to-end encrypted from day one.