If you haven’t heard, Firefox Send is a service that solves the problem of sending large attachments without going through email. It does this in a privacy-preserving manner by encrypting the file in your browser first, before upload.
The concept is simple:
- An encryption key is generated in your browser
- Your file is encrypted with that key before being uploaded to the server.
- The download URL is returned by the server,
but will only work after the browser appends the secret key to the URL fragment.
Note that URL fragments are never sent to the server. They are often used for page anchors, and sometimes to keep track of local state in SPA.
The code that powers Firefox Send is actually open source, so you can run your own server, or read the code to figure out exactly how it works. The encryption details are documented in docs/encryption.md.
A master key is first generated and from it, a few keys are derived using HKDF SHA-256. The derived key length depends on its purpose, so for AES-128 encryption, the key will be 128-bit. Oddly though, the Subtle Crypto API returns a a 512-bit key for HMAC SHA-256, which had me stumped for a while. I wrote some code that you can try out online.
Because HKDF is based on a hash algorithm, derived keys are inherently not reversible to obtain the master key from which they were derived (unless the algorithm itself is somehow broken).
3 keys are derived from the master key:
- Data Encryption key. Used to encrypt the actual file contents.
- Authentication key. Given to the service and used to authenticate future downloaders.
- Metadata key. Used to encrypt the upload manifest (filename and size information) for display.