Note
This document is not a spec, only an explanation of the encryption process.
argon2i
for PKDFargon2id
for password hashingOn all three platforms we use the same exact library for all cryptographic functions. This ensures data integrity across platforms.
Fun story
When we first added encryption, we used AES-GCM-256 across platforms but the cross-platform compatbility was abyssmal. That is when I found out about the great libsodium. Written in C, wrappers available for all platforms…what more could I want?
When you sign up for an account, the app takes your password and hashes it using Argon2 with a predictable per user salt
.
This predictable salt is generated using a fixed client salt
+ your email
.
Your password never leaves your device
Sending the hash over sending your plain text password ensures that there is no way for us (or anyone else) to get your password.
After the hash is generated, it is sent to the server. This hash is used as a password
and is hashed again to mitigate password passthrough attacks.
This process is repeated every time you sign in.
After you are signed in, the app requests your user data which includes, among other things, your salt.
Salt generation
When you create an account, the server generates a cryptographically secure random salt for you. This salt is used for key generation.
You password & salt is then used to derive a strong irreversible key using Argon2 as the password key derivation function (PKDF).
Instead of storing the key as plain text (and allowing anyone to copy/move it), we use browser’s IndexedDB
to store the key as a CryptoKey
.
CryptoKey
is stored securely by the browser and cannot be exported, viewed, copied except by the app & browser.
On iOS and Android, the encryption key is stored in the phone’s keychain.
Encryption only takes place when you sync. Each item in the database is encrypted seperately using XChaCha-Poly1305-IETF.
cipher
iv
)salt
alg
id
See the whole process in action here.
This object is then sent to the server for storage. The server performs no further operation on this data (because it can’t).