How your data stays yours
Everything you put into jellysuite is locked on your device before it reaches us. We store the locked version and never hold a key to it. This page shows how that works, in plain words with the exact names alongside, and where it stops.
What we can and can't read, app by appThe same message, twice.
On the left, what you see in Jelly Mail. On the right, what our database holds for it.
On your device
- From
- Ines Moreau
- Subject
- Draft contract, second round
- Body
- I went through clause 7 again and I think we can keep the notice period if…
- Attachment
- contract-v2.pdf
On our servers
- From
- HWeSo-X4-N_
- Subject
- b_Ta8L42JGAPnaXOqgwllQEzEE7t
- Body
- cI_zKOes0qUfq52GyUncksrategv-6rkNUy6UXLMISTKkzlPhcH9Mv4n229QFlierbBd9tFPYuS
- Attachment
- KoEId1dMDwFrago
One password, a chain of keys
The whole design is one idea. Every key is locked with the key before it, and the first is locked with your password. The chain is opened on your device, link by link. Our servers store every link locked, and have nothing to open the first one with.
- 1Your password stays on your device. It opens your account key.
- 2Your account key opens your two identity keys. One signs what you do. The other receives the keys people share with you.
- 3Those open the keys of your folders. Each folder's key opens the keys inside it, down to every message, page, file and event.
- 4Each item's key opens that one item. We store all of it and can open none of it.
Your device
Our servers
Your password never leaves your device
When you log in, your device and our server run an exchange that proves you know your password. The password isn't sent, and neither is anything it could be worked out from. Someone who stole our database would still have to guess passwords one at a time, and every guess is made slow on purpose.
The same exchange leaves your device holding a secret our server never sees. That secret opens your account key, which we only ever store locked. So the moment your data becomes readable is the moment you log in, and it happens on your device.
Under the hood
OPAQUE, an augmented PAKE, with Argon2id stretching inside it. It gives your device an export key the server never learns, and a BLAKE2b subkey of that wraps your 32-byte account key. In the browser, the keys kept for your session rest under a WebCrypto key that can't be exported.
Your device
Our servers
Every item has its own key
Each folder, message, page, file and event is locked with a key of its own. An item's key is stored locked with the key of the folder it sits in, so opening a folder opens what's inside it and nothing beside it. Sharing is exact for the same reason: share one folder and you hand over one key.
Every locked item is sealed together with what it is, which item it is and which version of its key locked it. If stored data were moved to another item or passed off as something else, by anyone including us, your app would refuse to open it instead of showing you the wrong thing.
Under the hood
XChaCha20-Poly1305 with a 32-byte key and a fresh random 24-byte nonce every time. Each envelope starts with a format byte and a type tag, and is authenticated with the item's id and key version as associated data.
Has its own key
Locked with
Share Contracts with Ines and she can open the lease. Offsite plan and Personal stay shut.
A locked item, as we store it
Sealed together with the item's id and key version. Put it anywhere else and it won't open.
Links that carry their own key
A share link has two parts. Everything before the # is the address of the app. Everything after it says which item and holds the key, and browsers never send that part to a server.
To open the link, the browser shows our server a proof worked out from the key, not the key. The server answers with the item's key in locked form, which only the link's key opens. Whoever has the link can read the item and we can't. You can switch a link off at any time.
Under the hood
A random 32-byte secret in the URL fragment. Two BLAKE2b subkeys come from it: one wraps the item's key, and the other is sent as the proof and stored only as a SHA-256 hash.
A share link
Your device
Our servers
Mail, inside and outside jellysuite
Between jellysuite accounts, mail is end to end. The sender's device locks the message for each recipient and signs it, and the app shows a green shield once it has checked the sender is who they say.
Email is older than encryption, so mail with everyone else can't work that way unless they use PGP, and we'd rather say exactly what happens. A message from outside arrives as ordinary email. Our server reads it once, in memory, locks it with your key and stores only that. A message you send outside is read in our server's memory while it's signed and handed on, then travels like any other email. Neither is written to disk unlocked, and the app marks both as outside mail.
Two details. If the outside address has a PGP key, your browser signs and encrypts the message itself and it stays locked the whole way. And a message to an outside address that you schedule for later waits on our server locked with a key the server holds, and is deleted once it's sent.
Under the hood
Inside jellysuite, the message key is sealed for each recipient with X25519 and signed with Ed25519. With PGP, your browser builds the message with OpenPGP, and our servers add only outer headers and a DKIM signature over the ciphertext.
jellysuite to jellysuiteEnd to end
Locked by your device for each recipient. We store and deliver ciphertext.
To an outside address that has a PGP keyEnd to end
Signed and encrypted in your browser. We add the outer headers and sign the ciphertext.
From an outside addressReadable on the way in
Arrives as ordinary email. Read once in our server's memory, locked with your key, stored only locked.
To an outside address, no PGPOrdinary email
Our server reads it in memory while it signs and sends it. Your Sent copy is locked by your device.
Locked, we can't read it Readable by the servers it passes
A recovery key, and no back door
We store your account key twice: once locked with your password, and once locked with a recovery key you're shown when you sign up. If you forget the password, the recovery key lets you set a new one.
There is no third copy. We can't reset your password for you, because we never had what it protects. Lose both the password and the recovery key and nobody can get your data back, including us. It's the price of a service that can't be made to read your things.
The same holds in a team. Your organisation can create an account at its domain, suspend it or delete it, but it can't read it or recover it. No admin holds a key to it.
Under the hood
A random 32-byte key, shown as base32 groups. One BLAKE2b subkey of it wraps your account key. Another is stored as a SHA-256 hash and proves you hold the key when you recover.
Your account key, as we store it
p2Qv3iaanXbBTLOpens with your password0yreZwgqyF0-1WOpens with your recovery keyNo third copyWhat encryption doesn't protect
Locking content is a strong promise and a narrow one. These are the things it doesn't cover.
The patterns around your data
Our servers see sizes, times and who you share with. That's less than most services, but it's not nothing. The transparency page lists it for every app.
Who pays for an account
Paying links a real name and billing address to your handle. Those details are held by Stripe, our payment provider, not on our servers, which keep only your plan and whether it's paid. It changes nothing about your content: neither we nor Stripe can read it.
A device someone else controls
Your data is unlocked on your device so you can use it. Malware on that device, or someone with your unlocked laptop, can see what you see.
Mail that leaves for the outside
Once a message reaches someone on another service, it's in their mailbox under their provider's rules.
The app code in your browser
On the web, your browser runs the app code our server sends it. The desktop apps carry their own code instead, and the code that matters most is open for anyone to check.
Check it yourself
The encryption library and the client core are open source under MIT. Nothing is home-made: it's built on libsodium and OPAQUE, both widely reviewed, with OpenPGP.js for PGP mail.
The technical names
- Locking items
- XChaCha20-Poly1305, 32-byte keys, a fresh random 24-byte nonce each time
- Stamped envelopes
- A format byte and type tag, authenticated with the item's id and key version
- Locking a key for a person
- X25519 sealed boxes, signed with Ed25519 by the sender
- Logging in
- OPAQUE (an augmented PAKE), with Argon2id inside
- Deriving keys
- BLAKE2b keyed hashing with fixed context strings
- Safety words
- Twelve words from the BIP39 list, from a SHA-256 hash of the person's signing key
- Link and recovery secrets
- 32 random bytes; BLAKE2b subkeys to wrap and to prove, the proof stored as SHA-256
- PGP mail
- OpenPGP v4 keys (Ed25519 and X25519), signed and encrypted in the browser
- Libraries
- libsodium; OPAQUE via @serenity-kit/opaque; OpenPGP.js