End-to-end encryption #

Encrypted rooms in Matrix use Olm and Megolm, two related ratchet protocols. The effect is that even the homeserver operator (us — Meldry) can only see ciphertext for encrypted rooms. Decryption happens in your client, using keys that never leave your devices.

This page explains the moving parts so you understand what happens when Element asks you to verify a device or save a recovery key.

Olm vs Megolm #

  • Olm — implements the Signal-style Double Ratchet for 1:1 sessions between a pair of devices. Used by Matrix for device-to-device messages (sharing keys, sending secrets, verifying identities). Not used directly for room messages.
  • Megolm — a group ratchet built on top of Olm. When you start speaking in an encrypted room, your device generates a Megolm session and distributes the starting key material to every other device in the room (over Olm). Everyone can then decrypt your messages forward using only the ratchet; they do not need a new handshake for every message.

Why the split? Double Ratchet gives perfect forward secrecy per pair of devices, but doesn't scale to a group — you'd need O(n²) ratchets. Megolm gives one-way forward secrecy per room (past messages are safe if a current key leaks, but not the other way around) while keeping the cost O(n) per membership event.

When Megolm sessions rotate #

  • Membership changes. New joiner → new session (so they can't read historical messages). Member leaves → new session (so they can't read future messages).
  • Time / message count. After a configurable number of messages or a configurable wall-clock time (defaults: 100 messages or 1 week), sessions auto-rotate.
  • Manual. You can force-rotate from Element's security settings.

Rotation looks like a tiny pause in message flow — you'll occasionally see "Unable to decrypt" for a split second while the new session propagates, then it self-heals.

Device keys #

Every device you sign in on generates its own set of long-lived identity keys (a Curve25519 + Ed25519 pair) on first launch. These are uploaded to your homeserver so other people can encrypt to you, but the private halves never leave the device.

When Alice starts talking in an encrypted room, her client:

  1. Fetches Bob's device list from his homeserver.
  2. For each of Bob's devices, opens an Olm session (Double Ratchet) using Bob's device identity key.
  3. Sends the starting Megolm key over each Olm session (one per device).
  4. Writes the room message encrypted with the Megolm key.
  5. Bob's devices decrypt the Megolm key (over Olm), then decrypt the message (over Megolm).

None of this is visible to the user — it all happens in the client automatically. What the user sees is the verification step.

Device verification and cross-signing #

Because keys are per device, the first time you sign in from a new phone your laptop sees an "unverified device" warning. Verification is how you confirm "yes, that new device is really me (or really the friend I'm talking to)":

  • Emoji verification — both devices display the same 7 emoji out of 64. You compare them in person or over a trusted channel. (Cryptographically this is a Short Authentication String derived from a key-commitment exchange.)
  • QR code scan — mobile shows a QR, desktop scans it. Matches the same Short Authentication String under the hood.
  • Recovery key — if you don't have a second device, you can verify new devices against a recovery key you saved when you first set up encryption. The recovery key unlocks your cross-signing identity.

Cross-signing #

Cross-signing is the mechanism that makes per-device verification scale. It introduces three long-lived keys per account:

  • Master Signing Key (MSK) — the root of trust. You generate it once, when you first set up encryption. It signs the other two.
  • Self-Signing Key (SSK) — signs your own devices. When you add a new device and verify it, the new device gets signed by the SSK, and the MSK signs the SSK, so anyone who trusts your MSK automatically trusts the new device.
  • User-Signing Key (USK) — signs other users you've verified. When you verify Bob, your USK signs Bob's MSK; from then on, anyone trusting you transitively trusts Bob's whole identity.

End result: you verify once per person (not once per device), and verification persists across reinstalls and new devices.

Secure Secret Storage and Sharing (SSSS) #

Your cross-signing secret keys, Megolm backup key and other long-lived secrets are encrypted with a passphrase you choose, then stored on the homeserver in an opaque blob called SSSS (Secure Secret Storage and Sharing). You unlock it on a new device by entering the passphrase (or pasting the recovery key), and only you can unlock it — the server can't read it.

This is how a fresh device bootstraps itself into an existing encrypted account without a second device being present. Without SSSS you'd need either your old device to cross-sign the new one manually, or you'd have to start a fresh cross-signing identity (and re-verify everyone).

SSSS uses PBKDF2-HMAC-SHA512 to derive the key from your passphrase. A well-chosen passphrase (or a random recovery key) is the only thing protecting your secrets at rest on the server.

Key backup #

Individual Megolm sessions are separately backed up to the homeserver, encrypted with a key that's itself stored in SSSS. This lets you decrypt old history on a new device: sign in, unlock SSSS with your passphrase, fetch the backup, decrypt the old Megolm sessions, decrypt the old messages.

Without key backup, signing in fresh and having lost your only other device means losing your encrypted history — by design. The server never had the keys, and we can't reconstruct them.

Practical implication for Meldry users: when you first set up encryption, Element prompts you to save a recovery key. Save it. A lost phone + no other device + no recovery key = lost encrypted history. There is no "reset password" that recovers the messages.

What gets encrypted, what doesn't #

Encrypted (E2EE):

  • Message bodies, reactions, edits, file uploads in any encrypted room
  • Direct messages (Meldry enables E2EE by default for DMs)
  • Room name / topic / avatar changes inside an encrypted room (post-E2EE-enable)
  • To-device messages between your devices

Not encrypted:

  • Public rooms (by design — new joiners have to be able to read history)
  • Room membership events (who's in the room is visible to your homeserver)
  • Typing indicators, presence, read receipts (not sensitive enough to justify the complexity)
  • Server-side metadata: which rooms you're in, when you last connected, device count

If a room was public first and encryption was turned on later, messages after the enable are encrypted but messages from before are not. Turning encryption on is a one-way switch — you can't turn it off once enabled.

Common failure modes #

"Unable to decrypt" errors. Usually means you don't have the Megolm session for that message. Happens when:

  • The message was sent before you joined the room (no key was ever shared with you)
  • You signed in on a new device and haven't restored the key backup yet
  • A session rotation is in progress

"Verify this device" prompts on every restart. You haven't set up cross-signing. Do it from Element's Settings → Security & Privacy → Cross-signing → Set up.

"Session expired / not found" on the server. Very rare — usually a homeserver-side bug. Restart the client; if it persists, file a support ticket.

What's next #