Signal’s end-to-end encryption uses a Double Ratchet algorithm, which isn’t just about encrypting messages; it’s about making sure that even if an attacker compromises one of your past messages, they can’t decrypt any others, and they also can’t impersonate you going forward.
Let’s see this in action. Imagine Alice wants to send a message to Bob.
Alice: "Hey Bob, what's up?"
When Alice’s client sends this, it doesn’t just encrypt it with a single key. It goes through a multi-step process that creates a unique, ephemeral encryption key for this specific message, and also updates the keys Alice and Bob will use for future messages.
The Mental Model: Two Ratchets Turning
The "Double Ratchet" is composed of two distinct but interconnected cryptographic processes:
-
The Diffie-Hellman (DH) Ratchet: This is responsible for establishing new, shared secret keys between Alice and Bob. Every time Alice or Bob sends a message, they send along a new "public key" that they generated. The other party uses this public key, along with their own secret key, to derive a new shared secret. This new shared secret is then used to further derive the actual message encryption keys. The key insight here is that each new DH exchange invalidates the previous shared secret, meaning past communications are safe even if the current DH public key is compromised.
-
The Symmetric-Key Ratchet (KDF Ratchet): This ratchet takes the shared secret derived from the DH ratchet and uses it to generate a sequence of unique symmetric keys. Think of it like a key derivation function (KDF) that produces a new key from an old one, along with some "chaining" information. Each time a message is sent or received, the KDF is advanced, producing a new, unique key for that specific message. If an attacker intercepts a message and its key, they can’t use that information to derive the next key, and therefore can’t decrypt subsequent messages.
How it all comes together: Alice sends to Bob
Let’s break down the lifecycle of a message:
-
Initial Setup: When Alice and Bob first start a conversation, their clients perform an initial Diffie-Hellman exchange to establish a base shared secret. This base secret is then fed into the KDF ratchet to generate the first set of message encryption keys.
-
Alice Sends Message 1:
- Alice’s client generates a new DH public key pair (
DH_A1). - It uses the current shared secret (
SS_current) and Bob’s latest DH public key (let’s sayDH_B_latest) to derive a new shared secret (SS_new) via a DH operation. - This
SS_newis then used by the KDF ratchet to generate the encryption key for Message 1 (K_M1) and the key for the next message (K_next). - Alice’s client encrypts "Hey Bob, what’s up?" with
K_M1. - Crucially, Alice’s client sends the encrypted message along with her new DH public key (
DH_A1). - Alice’s client then discards
SS_currentandDH_A_current, and updates its state to useSS_newandDH_A1as the basis for the next DH ratchet step.
- Alice’s client generates a new DH public key pair (
-
Bob Receives Message 1:
- Bob’s client receives the encrypted message and Alice’s public DH key (
DH_A1). - Bob uses his own private DH key and Alice’s new public DH key (
DH_A1) to derive the sameSS_newthat Alice derived. - Bob then uses this
SS_newwith his KDF ratchet to deriveK_M1(to decrypt the message) andK_next(for future messages). - Bob decrypts "Hey Bob, what’s up?" with
K_M1. - Bob’s client then updates its state, ready for Alice’s next message.
- Bob’s client receives the encrypted message and Alice’s public DH key (
-
Bob Sends Reply:
- Bob’s client generates a new DH public key pair (
DH_B2). - It uses the current shared secret (
SS_current_B) and Alice’s latest DH public key (DH_A1) to derive a new shared secret (SS_new_B). - This
SS_new_Bis fed into Bob’s KDF ratchet to generateK_M2andK_next_B. - Bob encrypts his reply with
K_M2. - Bob sends the encrypted reply along with his new DH public key (
DH_B2). - Bob’s client discards its old state and updates to
SS_new_BandDH_B2.
- Bob’s client generates a new DH public key pair (
-
Alice Receives Reply:
- Alice uses her private DH key and Bob’s new public DH key (
DH_B2) to deriveSS_new_B. - She then uses her KDF ratchet with
SS_new_Bto deriveK_M2andK_next_A. - She decrypts Bob’s reply.
- Alice uses her private DH key and Bob’s new public DH key (
The "Double" Part: Forward and Backward Secrecy
The genius is in the "double" aspect:
-
Forward Secrecy: If an attacker somehow gets hold of Alice’s current DH private key, they can decrypt future messages Alice is sending if they also have the corresponding public keys. However, because Alice’s client always sends a new DH public key with every message, and the next shared secret is derived from that, the attacker would need to compromise Alice’s private key at the moment she sends each message. More importantly, this new DH exchange allows Bob to derive a new shared secret, and the KDF ratchet uses that new secret to generate a completely new set of message keys. The attacker can’t use the compromised key to derive the next key in the KDF chain.
-
Post-Compromise Security (or Backward Secrecy): If an attacker compromises Alice’s current DH private key, they can decrypt the message Alice is currently sending and any future messages until Alice or Bob initiates a new DH exchange. However, once Alice sends her next message, she sends a new DH public key. Bob uses this new public key to establish a brand new shared secret, completely independent of the compromised one. The KDF ratchet then uses this new shared secret to generate a fresh sequence of message keys. This means that even if Alice’s state was compromised yesterday, today’s messages are secure because a new DH exchange has reset the cryptographic foundation.
The core idea is that every message exchange advances both ratchets independently. The DH ratchet establishes a fresh, ephemeral shared secret for each round of communication (e.g., Alice sending to Bob, then Bob sending to Alice), and the KDF ratchet generates a unique message key for each individual message within that round. This creates a strong chain of keys where compromising any single key only compromises a single message, and even then, only if the attacker also has the ephemeral DH private key used for that specific exchange.
This continuous re-keying and unique key generation for every message is what makes Signal’s encryption so robust. The next step after understanding this is how Signal handles group messages, which introduces even more complex key management.