Skip to content

Encryption

Encryption is opt in per channel, set when the channel is created. Turn it on and the server stores ciphertext only.

Each of your devices generates a keypair and publishes only its public keys. A channel key is generated on a device, then sealed individually to every member device. When membership changes the channel key is rotated, so someone removed today cannot read tomorrow’s messages, and someone added today cannot read yesterday’s.

The server holds public keys and sealed envelopes. It has nothing that can decrypt a message.

Audio and video are peer to peer with DTLS-SRTP, negotiated between browsers. No media reaches the server, in any channel, encrypted or not. Adding a TURN relay does not change that: a relay forwards ciphertext.

  • Search cannot index those channels. Nothing can. They are excluded from results.
  • Bots cannot read them. An agent is another device with no channel key, so it says so rather than staying silent. Point agents at unencrypted channels.
  • It is not reversible. Turning it off would mean handing the server plaintext, so the switch only goes one way. Make a new channel instead.
  • Push notifications say less. They carry Sent a message in an encrypted channel rather than a preview.

Files posted to an encrypted channel are encrypted too, in the browser, before they are uploaded.

Each file gets its own key, not the channel key. That key travels inside the message, which is itself encrypted with the channel key, so the server never sees either. Two things follow from the separation:

  • Rotating a channel key on a membership change does not orphan every file ever posted to it.
  • A file can be shared without handing over the channel, because one file’s key says nothing about the rest.

The server stores the ciphertext under a generic name with a generic type and no dimensions. That last part matters as much as the bytes: a filename like q3-layoffs.pdf in a database gives away most of what the encryption was for.

The server generates no thumbnails, because there is no image for it to see. The browser makes one instead, before encrypting, and uploads it as a second blob. It shares the file’s key, since anyone who can read the file can read its preview, but gets its own IV, because reusing an IV with the same AES-GCM key breaks the cipher.

A channel of photographs therefore loads previews, not originals. On a 1.1 MB image the preview measured under 4 KB. The original is fetched only when you open it. Images already smaller than 480px on their longest edge are their own preview and get no second copy.

Be clear about the boundary:

  • Metadata is visible to the server. Who is in a channel, when they posted, and how much. Encryption hides content, not the shape of the conversation.
  • A file’s size is visible, since the ciphertext is the same length as the file plus a tag. Padding would hide it and is not implemented. The presence of a second, much smaller blob also implies “this one is an image”.
  • Search cannot see any of it, which is the same trade as message text.