Encryption Overview
End-to-end encryption in Chatalot: why it matters and how it protects your messages.
Status. End-to-end encryption is implemented, enabled by default, and runs client-side in the bundled WASM crypto module. DMs use X3DH + Double Ratchet and the server never sees their plaintext. Group and community channels use Sender Keys, and in the default configuration the server is given the group's chain key, so it can derive group message keys and read group content. That is a real limitation of the default setup — see Privacy Guarantees below before relying on this page.
Why End-to-End Encryption Matters
When you send a message on most chat platforms, the server can read it. The company operating the service, any employee with database access, and any attacker who compromises the server can see your conversations. Even if the connection uses TLS (HTTPS), that only protects messages between your device and the server -- the server itself still handles plaintext.
End-to-end encryption (E2E) changes this. With E2E, messages are encrypted on your device before they leave, and only the intended recipient's device can decrypt them. The server transports encrypted blobs it cannot read. Even if someone gains full access to the server's database, they see ciphertext, not conversations.
For a self-hosted platform like Chatalot, this means:
- Server administrators cannot read direct-message content (intentionally or accidentally)
- Database breaches do not expose direct-message history
- Network eavesdroppers see only encrypted traffic
- Legal compulsion cannot produce plaintext the server does not possess
Each of those holds for direct messages. For group and community channels on the default configuration the server does possess the group key, so none of them hold there — see Privacy Guarantees.
What is the Signal Protocol?
Chatalot's encryption is based on the Signal Protocol, the same cryptographic foundation used by Signal, WhatsApp, and Google Messages. It was chosen for several reasons:
- Proven security: The protocol has been formally analyzed by academic cryptographers and has withstood years of scrutiny.
- Forward secrecy: Compromising a key does not reveal past messages. Each message uses a unique key that is deleted after use.
- Break-in recovery: Even if an attacker compromises your current keys, they lose access once the next key exchange occurs.
- Asynchronous setup: Two users can establish a secure session even if one is offline, thanks to the X3DH (Extended Triple Diffie-Hellman) handshake.
- Efficient group messaging: The Sender Keys extension allows group messages to be encrypted once rather than once per recipient.
Privacy Guarantees
When encryption is active, the Chatalot server:
- Cannot read the content of your direct messages
- Cannot forge messages as if they came from you (messages are tied to your identity key)
Group and community channels are the exception, and it is the most important thing on this
page. In the default configuration the sender uploads the group's chain key to the server,
so the server holds the material from which group message keys are derived and can read group
message content. An operator can enable pairwise distribution (sender_key_v2_enabled) to close
this; it is off by default, enabling it does not remove chain keys the server already stored,
and the app does not currently show you which mode your instance is using. If group
confidentiality from the server matters to you, ask your operator. See
Group encryption.
File content is not end-to-end encrypted. Files are protected in transit by TLS and then stored server-side, so the server — and anyone with access to its disk or backups — can open any file you upload. Per-file content encryption is designed but not implemented (CHAT-401). See Limitations.
What Is Encrypted vs. What Is Not
It is important to understand the boundaries of E2E encryption. Not everything is hidden from the server.
| Encrypted (server cannot read) | Not encrypted (server can see) |
|---|---|
| Message text content | Message timestamps |
| Sender and recipient IDs | |
| Channel and community names | |
| File contents, names, and sizes* | |
| User presence and status | |
| Reactions (which emoji, who reacted) | |
| Message existence and approximate size | |
| Who is in which channel |
* File content is not end-to-end encrypted. Files travel over TLS and are then stored server-side, readable by the server operator. Content encryption is designed but not implemented (CHAT-401).
Think of it like sending a sealed letter through the postal service: the post office can see the envelope (who sent it, who it is addressed to, when it was mailed, and how heavy it is), but it cannot read what is inside.
See Limitations for a thorough discussion of what the encryption does and does not protect.
Current Implementation Status
The encryption system is implemented in layers:
-
Rust crypto crate (
chatalot-crypto) -- All cryptographic protocols are implemented and covered by 23 unit tests. This is the core engine. -
WASM bridge (
chatalot-crypto-wasm) -- The Rust crypto crate is compiled to WebAssembly so it can run in the browser. The WASM module is compiled and bundled with the web client. -
Web client integration (
clients/web/src/lib/crypto/) -- The KeyManager, SessionManager, and CryptoStorage classes wire the WASM crypto into the Svelte web client. Key generation on registration, prekey replenishment, DM encryption/decryption, and Sender Key group encryption are implemented. -
Server key exchange -- The server provides REST endpoints for uploading and fetching prekey bundles (
/keys/{user_id}/bundle) and sender key distributions (/channels/{id}/sender-keys). For prekey bundles the server stores only public keys. For sender-key distributions this depends on the mode: under the default (v1) the stored distribution contains the group's chain key in readable form; under v2 (sender_key_v2_enabled, off by default) it stores only ciphertext envelopes it cannot open.
End-to-end encryption is enabled by default. When it is on, messages are always encrypted on your device before they leave: if the crypto module cannot load or a session cannot be established, the send fails and you are notified — the client never silently transmits your message as plaintext. (An instance operator can turn E2E off server-wide via a setting, in which case message content is sent without this protection; the default is on.)
Next Steps
- How It Works -- See the encryption flow step by step
- Key Management -- Learn about the different key types
- Limitations -- Understand the security boundaries