Send use 128-bit AES-GCM encryption via the Web Crypto API to encrypt files in the browser before uploading them to the server. The code is in app/keychain.js.
- A new secret key is generated with
crypto.getRandomValues
- The secret key is used to derive 3 more keys via HKDF SHA-256
- an encryption key for the file (AES-GCM)
- an encryption key for the file metadata (AES-GCM)
- a signing key for request authentication (HMAC SHA-256)
- The file and metadata are encrypted with their corresponding keys
- The encrypted data and signing key are uploaded to the server
- An owner token and the share url are returned by the server and stored in local storage
- The secret key is appended to the share url as a #fragment and presented to the UI
- The browser loads the share url page, which includes an authentication nonce
- The browser imports the secret key from the url fragment
- The same 3 keys as above are derived
- The browser signs the nonce with it's signing key and requests the metadata
- The encrypted metadata is decrypted and presented on the page
- The browser makes another authenticated request to download the encrypted file
- The browser downloads and decrypts the file
- The file prompts the save dialog or automatically saves depending on the browser settings
A password may optionally be set to authenticate the download request. When a password is set the following steps occur.
- The original signing key derived from the secret key is discarded
- A new signing key is generated via PBKDF2 from the user entered password and the full share url (including secret key fragment)
- The new key is sent to the server, authenticated by the owner token
- The server stores the new key and marks the record as needing a password
- The browser loads the share url page, which includes an authentication nonce and indicator that the file requires a password
- The user is prompted for the password and the signing key is derived
- The browser requests the metadata using the key to sign the nonce
- If the password was correct the metadata is returned, otherwise a 401