Skip to content

Cryptography

A summary of the cryptographic flows used in Zero-TOTP

Keys generation process

In the different cryptographic flows, we use different keys. This section defines these keys and details their generation process.

User derived key

  • Name : User derived key.
  • Notation : derived_key.
  • Purpose : Encrypt/decrypt the zke_key.
  • Storage : NOT stored.
  • Generation process :
  • The derived_key is a cryptographic derivation from the user's passphrase.
  • The salt is retrieved from the database.
  • Algorithm : PBKDF2 with 700 000 iterations and SHA256 as hash algorithm. The key is derived into an AES-GCM 256 key.
  • Where : In the browser, by the frontend (deriveKey())
  • Used by: The frontend only. This key never leaves the browser and is never stored, even client side

Zero-Knowledge Encryption Key

  • Name : Zero-Knowledge Encryption Key.
  • Notation : zke_key. Encrypted version :zke_key_enc
  • Purpose : Encrypt/decrypt the user vault.
  • Storage : Stored ENCRYPTED in the database. The encryption is performed by the derived_key.
  • Generation process :
  • At signup the zke_key is generated by the browser from 32 bytes of cryptographically secure random bytes.
  • It is a AES-256 random key.
  • This key is encrypted by the derived_key and stored encrypted in the database.
  • At login, the key is retrieved from the database and decrypted by the browser with the derived_key.
  • Where : In the browser, by the frontend (generateZKEKey() and decrypt)
  • Used by: The frontend only. This key never leaves the browser in clear and is only stored in clear in the angular service (which is restricted to the current tab session. This means this value is proper to each page (re-)loading and is wiped-out when the tab is reloaded or closed. It cannot be restored).

User creation flow

  1. A ZKE key is randomly generated by the browser. This is zke_key.
  2. The user's passphrase is derived using PBKDF2 and a random salt by the browser. This is derived_key.
  3. derived_key is used to encrypt zke_key. This is zke_key_enc
  4. The user's passhrase is hashed by the browser with SAH256 and a random salt. This is pass_hash1
  5. pass_hash1, its salt, zke_key_enc and derived_key's salt are sent by the browser to the API for storage.
  6. Before being stored, the pass_hash1 is hashed using Bcrypt and a random salt

User login flow

  1. The pass_hash1's salt is retrieved from the API before anything using the user's email as identifier.
  2. The user's passphrase is hashed using the retrieved hash, producing pass_hash1.
  3. pass_hash1 is sent to the API for authentification. It will be hashed using BCrypt and compare to the hash generated during signup.
  4. If the auth is not successful, this is the end of the flow.
  5. If the auth is successful, the API store a JWT cookie used to authenticate the future user's API calls. The API also returns the user's derived_key's salt.
  6. The browser uses the derived_key's salt derive the user's passphrase. This is derived_key.
  7. An API call is made by the browser with the JWT to retrieve the user's zke_key_enc.
  8. derived_key is used by the browser to decrypt zke_key_enc. This is zke_key
  9. derived_key is forgotten and zke_key is stored in the Angular service, so in tab live session.

Vault encryption flow

Note

To maintain the integrity of the entire vault, secrets are encrypted one by one. Among all information associated with secrets (secret, URI, color, etc ...) the only information kept in clear is its uuid.

  1. All the secret information are encrypted using zke_key.
  2. Encrypted secret is sent to the backend for storage.
  3. If google drive backup option is enabled, the whole vault is backed up to google drive

Vault decryption flow

  1. Secret (or secrets) is (are) retrieved from the API. They are all encrypted.
  2. zke_key is used to decrypt each secret.