How it works
Sending a file
Files are chopped into pieces, each locked with its own key, and scattered across a storage room that has no idea what they are or who they belong to.
A file is broken into chunks; each chunk gets its own lock, and the pieces are dropped into a big storage room addressed only by a random fingerprint. The room has no idea what was uploaded, who sent it, or even that the pieces belong to the same file. The instructions to reassemble them travel inside an already-sealed message, readable only by the recipient.
The client encrypts each chunk with a per-chunk key derived from a random Content Encryption Key,
then addresses it by chunk_id = SHA-256(ciphertext). Upload goes through the API (which
re-verifies the hash) to the object store; blob_index tracks size, expiry, and download state.
The manifest — file name, MIME, chunk list, wrapped CEK — is sent as an ordinary Sealed Sender message, never
uploaded.
FILE_UPLOADS_ENABLED.Step by step
Encrypts each chunk locally and names it by the hash of its ciphertext.
On upload, recomputes the hash and rejects any chunk whose bytes don’t match its id (integrity + anti-tamper).
Holds the encrypted bytes under a derived path — no name, MIME, owner, or recipient.
Records only size, expiry, and a downloaded flag in blob_index.
Gets the manifest inside a sealed message, downloads chunks by id, and reassembles + verifies locally.
Shortens retention to at most 24 hours after the first download; the default is 7 days.
What the server learns
Server can observe
- Chunk hash, ciphertext size, upload/download timing, retention state.
- No durable owner or recipient column exists.
Server cannot learn
- File name, MIME type, plaintext, or plaintext hash.
- The file key, or the file contents.
- That several chunks belong to the same file.