How end-to-end encryption works
Open WhatsApp and a banner tells you Meta can't read your messages. That claim sits on a specific protocol — Diffie–Hellman key agreement plus a 'double ratchet' that changes the key on every message. Here's the shape of it.
On this page
The picture version
Five pictures for a reader who has only ever seen the banner, following one conversation: Alice messaging Bob.
1 · The problem
Both say “encrypted.” They differ on where the ciphertext stops.
2 · Starting a conversation
You can’t shake hands with a phone that’s in a pocket.
3 · The part doing the work
The key changes on every single message.
4 · Where the banner stops
It promises what, not whether.
5 · Keep this card
The whole thing on one index card.
Why it exists
Open WhatsApp, start a chat with a friend — call her Alice messaging Bob, since we’ll follow this exact conversation the whole way down — and a small banner tells you “Messages and calls are end-to-end encrypted.” Meta runs the servers the message just travelled through, and the banner is claiming that even Meta, sitting in the middle, cannot read what was typed.
The obvious question is: how is that different from the lock icon next to a URL in your browser? Both say “encrypted.” The difference is where the ciphertext stops. With ordinary TLS, your message is encrypted from your phone to WhatsApp’s server, decrypted there, then re-encrypted from the server to your friend’s phone. The server holds plaintext, even if only for a moment. Anyone who can subpoena, breach, or rogue-employee that server can read messages. End-to-end encryption (E2EE) closes that window: the keys live on the two endpoints, the server only relays ciphertext, and “trust the server operator” stops being part of the threat model.
flowchart LR
subgraph TLS["Ordinary TLS"]
direction LR
A1[Alice's phone] -->|ciphertext| S1["server<br/>holds plaintext briefly"]
S1 -->|ciphertext| B1[Bob's phone]
end
subgraph E2EE["End-to-end encryption"]
direction LR
A2[Alice's phone] -->|ciphertext| S2["server<br/>only sees ciphertext"]
S2 -->|ciphertext| B2[Bob's phone]
end
Why it matters now
E2EE remains a live policy fight, not a settled feature. Critics — Signal prominently among them — argue that the UK’s Online Safety Act and the EU’s recurring “Chat Control” proposals push encrypted services toward client-side scanning: inspecting messages on the device before they’re encrypted. Signal has publicly said it will not weaken its privacy guarantees to comply. Separately, Apple announced a plan in 2021 that would have matched photos on the device against known-material hashes as they were uploaded to iCloud Photos, and drew heavy criticism from cryptographers on exactly the client-side-scanning grounds below; Apple later introduced optional end-to-end encrypted iCloud backups under Advanced Data Protection in December 2022.
On the deployment side, the design Signal published in 2013–2014 — which picked up the name “Signal Protocol” in 2016 — is now the default across the major messengers: WhatsApp turned Signal-protocol E2EE on by default in 2016, Google Messages rolled out one-to-one RCS E2EE in beta from late 2020 and now applies it by default to eligible RCS conversations, and Facebook Messenger finished defaulting all personal chats to E2EE in December 2023. The mechanism this post describes underlies the major consumer-messaging clients, and is the part legislation keeps trying to put a hole in. What share of the world’s messaging traffic that adds up to isn’t something anyone publishes.
The short answer
E2EE = key agreement between the two devices + a per-message symmetric key that the server never sees
Picture to keep: the post office still handles every envelope and still reads the address on the front — but the envelope is welded shut, and the only two people with a cutter are the sender and the recipient. Where the picture breaks: a real envelope uses one lock forever, while the ratchet described below welds each message with a fresh one and destroys that message’s cutter immediately after use.
Two phones do a public-key handshake to agree on a starting secret without trusting the server in the middle. From that secret they derive a fresh symmetric key for every message, ratcheting forward so that compromising today’s key doesn’t reveal the messages already sent — and a periodic Diffie–Hellman step folds in new entropy so future messages eventually recover from the compromise too. The server’s job shrinks to “store and forward opaque blobs.”
How it works
We’ll use the Signal Protocol as the worked example, because it’s the one WhatsApp, Signal, Messenger, and Google Messages all build on, and because it’s been publicly specified and analysed since around 2013. Each piece below fixes the failure of the simpler version before it.
1. Bootstrapping a shared secret (X3DH)
Naive plan: have the two phones do a live handshake. The hard problem is that when Alice first messages Bob, Bob might be offline. You can’t do an interactive handshake with a phone that’s currently in a pocket. Signal’s answer is X3DH: every user uploads a small bundle of public keys to the server in advance — a long-term identity key, a medium-lived “signed prekey,” and a stack of one-time prekeys. When Alice wants to start a conversation, she fetches Bob’s bundle, performs several Diffie–Hellman computations against those keys at once, and mixes the results into a single shared secret. Bob, when he comes online, does the matching operations on his side and arrives at the same secret.
The server hosts the bundles but never sees the resulting secret — Diffie–Hellman is built so the secret is computable from each side’s private keys plus the other side’s public keys, and never has to traverse the network.
2. Ratcheting forward (Double Ratchet)
Naive plan: agree on one shared secret and keep using it. That would be a fragile thing to lean on for years. If a phone is compromised tomorrow, you want yesterday’s messages to stay unreadable (forward secrecy) and you want the conversation to eventually recover so tomorrow’s stop being readable too (post-compromise security).
The Double Ratchet gives both. It combines two clocks:
- A symmetric ratchet that runs a KDF on the current chain key after every single message. The chain key for message N is unrecoverable from the chain key for message N+1. So even if an attacker steals the device right now, they can’t decrypt the messages already sent — those keys have been overwritten.
- A Diffie–Hellman ratchet that carries the sender’s current ratchet public key on every message. When the other side sees a new ratchet key (typically once they reply), both sides do a fresh DH computation, mix it into the chain, and restart from new entropy neither endpoint knew before. That’s the part that gives post-compromise recovery: once a fresh DH step runs — which happens on a direction-reversal, not on every message — a previously stolen key stops being enough. The caveat is in the “once”: if the attacker still has live access to the endpoint, they simply learn the new material too. Recovery is from a snapshot, not from an ongoing intruder.
sequenceDiagram
participant A as Alice's phone
participant B as Bob's phone
Note over A,B: DH step → chain key C₀
A->>B: msg 1 (key from C₀)
A->>B: msg 2 (key from C₁ = KDF(C₀))
A->>B: msg 3 (key from C₂ = KDF(C₁))
Note over A,B: Bob's reply triggers a new DH step → C'₀
B->>A: msg 4 (key from C'₀)
B->>A: msg 5 (key from C'₁ = KDF(C'₀))
Note over A,B: Alice's reply triggers another DH step → C''₀
A->>B: msg 6 (key from C''₀)
The symmetric ratchet is the inside of each run (C₀ → C₁ → C₂ by KDF). The DH ratchet is the jump between runs — a fresh chain key derived from new key material the other side just brought in.
The per-message key that finally encrypts the payload is symmetric. The Double Ratchet spec treats the payload cipher as a pluggable AEAD interface and gives a CBC-plus-HMAC construction — encrypt-then-MAC — as one recommended instantiation, so treat that as “a concrete choice the spec endorses” rather than “the cipher Signal is defined to use.” Either way the expensive public-key math only runs during ratchet steps, not on every keystroke.
3. What the server actually sees
Naive hope: end-to-end encryption hides everything. Once the ratchet is running, the server’s view of each message is roughly: from device A, to device B, this many bytes, at this time, here is an opaque blob and a header. That blob and header are useless without one of the two endpoints’ keys.
Which is also the honest limit of the banner Alice saw in the first paragraph. It promises the server can’t read what she said. It does not promise the server doesn’t know she said it, to Bob, at 2am, for the ninth time this week.
Show the seams
- Metadata is not encrypted. The server still has to route the message, so it sees who sent to whom, when, how often, message sizes, and group-membership patterns. That graph alone is famously informative. Signal goes further than most to minimise this (sealed sender, contact-discovery via secure enclaves), but no E2EE messenger hides all metadata.
- Backups are the usual back door. If iCloud or Google Drive stores your chat history in a form the cloud provider can read, the E2EE guarantee ends at the backup. WhatsApp now offers end-to-end encrypted backups, but they’re opt-in; Apple’s “Advanced Data Protection” for iCloud is similarly opt-in. The default settings often quietly weaken the property the banner advertises.
- Endpoint compromise breaks everything. E2EE protects the channel, not the device. Malware on the phone, a shoulder-surfer, or a forensic extraction of an unlocked device sees plaintext, because plaintext is what the user reads.
- Key verification is the user-experience cliff. The protocol can tell you when your contact’s key changed (Signal’s “safety number,” WhatsApp’s security-code QR), but manual verification is cumbersome enough that services have stopped relying on it. A malicious server could insert a fake key for a brand-new conversation, and unless the two humans compare numbers out of band, neither would notice. Key transparency systems (audit logs of which key the server claims belongs to whom) are the structural answer, and which messengers have shipped one is a moving target.
- Group chats are harder than two-party chats. The straightforward approach is client-side fan-out: encrypt the message separately to each member’s pairwise session, so cost grows with group size. “Sender key” schemes cut that down by encrypting the message once under a shared sending key that is itself distributed pairwise. The IETF MLS standard (RFC 9420, 2023) is the newer construction designed for large groups, using a key tree so per-message key updates cost logarithmic rather than linear work. Which messenger uses which scheme keeps changing and is rarely documented publicly, so read the above as the menu of designs rather than a deployment survey.
- Client-side scanning is the wedge. If a regulator can force the messenger to run a hash check or AI classifier on the plaintext before encryption, the E2EE property survives technically (the network still sees only ciphertext) while being effectively neutralised (the device itself becomes an informant). Whether that counts as “still E2EE” is the fight under the legislative debates above.
You started with E2EE = key agreement between the two devices + a per-message symmetric key that the server never sees. What did this post
add? — + the key keeps moving. That clause is doing almost all the work:
without it, one stolen phone retroactively unlocks every message the server
ever stored, and the ratchet is the entire reason “we can’t read your
messages” is a claim about the design rather than a promise about the
operator’s behaviour. Everything in the seams list above is a place where
that claim stops at the device, not at the protocol.
Check yourself
Before you go — Alice’s phone is seized and fully imaged, keys and all, right after she sends message 12. The server hands over its complete archive of ciphertext for messages 1 through 12. How much of that archive can be decrypted with what’s on the phone?
Answer
None of the archived ciphertext, assuming what was captured is the ratchet state. Each chain key is derived from the previous one by a one-way KDF and the old one is overwritten, and each message key is discarded once it has been used — including message 12’s, spent at the moment she hit send. Nothing in the captured state runs backwards. That’s forward secrecy, and it’s why the server’s archive is worth much less than its size suggests.
Two things do fall, and they’re the ones that matter in practice. The app’s own local database almost certainly holds the plaintext history, because that’s how you scroll up — no protocol break required. And the captured session state decrypts everything Bob sends from now on, and can send as Alice, until she re-establishes the session from a new device. E2EE protected the archive, not the endpoint holding the plaintext.
And one more — a government requires the messenger to hash every photo on the device against a known-material database before encryption, and report matches. Is the service still end-to-end encrypted?
Answer
Technically yes, and that’s the point of the argument. The wire still carries only ciphertext, the server still can’t decrypt, and every property described in this post still holds. What changed is that “the endpoint” is no longer working solely for its user — the plaintext is inspected at the one place the protocol was designed to trust unconditionally. The security critique isn’t that the math breaks; it’s that the reporting channel is a general-purpose one, and the definition of what to scan for is set by whoever controls the list, not by the protocol.
Famous related terms
- Signal Protocol —
Signal Protocol = X3DH + Double Ratchet + authenticated symmetric encryption per message— the spec Signal, WhatsApp, and Google Messages all build on; Messenger uses it alongside its own additions. - Forward secrecy —
forward secrecy = past messages stay safe if today's key leaks— the symmetric-ratchet half of the Double Ratchet exists to deliver exactly this property. - Post-compromise security —
post-compromise security ≈ "self-healing" after key theft once a fresh DH ratchet step runs— the DH-ratchet half. - Diffie–Hellman key exchange —
DH = derive a shared secret over a public channel— the primitive every step of X3DH is built on; see public-key crypto. - TLS —
TLS ≈ encrypt the client↔server hop— protects the network link but not the server itself; the contrast that motivates E2EE. See TLS. - MLS (Messaging Layer Security) —
MLS ≈ E2EE for groups, with a key-tree so per-message cost is logarithmic in group size— the IETF standard (RFC 9420) for the group case. - Client-side scanning —
CSS ≈ run a classifier on plaintext on the device before it's encrypted— the regulatory workaround whose security implications are actively contested. - Sealed sender —
sealed sender ≈ hide the "from" field from the server too— a Signal-specific metadata-minimisation feature.
Going deeper
- The Double Ratchet Algorithm (Signal’s own specification) — the primary source for the question this post only sketches: exactly which keys are derived from what, and in what order, on each send and each direction change.
- Matthew Green, “Attack of the Week: Group Messaging in WhatsApp and Signal” — the explainer for “why does everything above get harder the moment there are three people in the chat instead of two.”
- X3DH — the rabbit hole for anyone who wants to know how you complete a key agreement with someone whose phone is switched off.