End-to-end encryption is easy to claim and hard to do without making the product miserable to use. The bar we set for PolarHQ: the server stores nothing but ciphertext, and you only ever type one password. No per-file prompts, no key-management homework. Here's how it fits together.
One password, one keypair
When you sign up, your browser does the heavy lifting before anything touches the network:
- Generate an X25519 keypair with libsodium.
- Derive a key-encryption key (KEK) from your login password using Argon2id.
- Wrap (encrypt) your private key with that KEK.
- Send the server only
{ publicKey, wrappedPrivateKey, kdfSalt }.
The server never sees your password, your KEK, or your private key — only an opaque wrapped blob it couldn't open if it wanted to.
password ──Argon2id──▶ KEK ──unwraps──▶ privateKey (memory only)
│
publicKey ──shared──▶ collaborators │
On sign-in, the browser re-derives the KEK, unwraps the private key into memory, and keeps it for the session. That's the only moment your password is in play.
Per-item content keys
Every photo, file, and document gets its own random symmetric content key. The bytes are sealed with crypto_secretbox; the content key itself is wrapped to your public key. To share with someone, we wrap that one content key to their public key — the underlying data never has to be re-encrypted.
This is what lets a single library scale: thousands of items, each independently keyed, all openable with the one private key sitting in your session.
What's encrypted
Short answer: everything that could identify you or your content.
- Photo and video originals, plus every generated thumbnail
- Filenames and folder names
- Document snapshots and the real-time collaboration frames
- EXIF, captions, and search embeddings
The server sees sizes and timing, and that's roughly it. Even the ML search index — the on-device CLIP embeddings — is encrypted at rest and ranked client-side.
The honest trade-offs
E2E isn't free, and we'd rather be upfront:
- Lost password = lost data. Without your password there's no KEK, and without the KEK there's no way back in. That's the whole point — but it means a recovery code is essential, and we generate one at signup.
- No server-side search or rendering of encrypted content. We push that work to the client, which is why search runs in your browser.
- Sharing is key distribution, not link magic. Public, non-E2E links exist for when you explicitly want them.
The goal isn't encryption for its own sake. It's that nobody — not us, not a cloud provider, not a future acquirer — can read your life without your password.
That's the model. It's the same shape across Photos, Drive, and Docs, and it's why "self-hosted" and "end-to-end encrypted" aren't two features in PolarHQ — they're the same promise.