Reading — step 1 of 5
Read
~1 min readFoundations: X3DH
X3DH — Initial Key Agreement
X3DH (Extended Triple Diffie-Hellman) lets Bob start an encrypted session with Alice when she's offline.
Alice publishes (IK_A, SPK_A, OPK_A) to the server. Bob fetches them.
Bob generates ephemeral keypair (EK_B). Computes:
DH1 = DH(IK_B, SPK_A)
DH2 = DH(EK_B, IK_A)
DH3 = DH(EK_B, SPK_A)
DH4 = DH(EK_B, OPK_A) # if OPK present
SK = HKDF(DH1 || DH2 || DH3 || DH4)
Why each DH?
- DH1: authenticates Alice (she has IK_A) and Bob (he has IK_B) at long-term level.
- DH2: authenticates Alice (IK_A) and proves Bob (EK_B) is fresh.
- DH3: ensures the server can't substitute a different SPK without DH3 changing.
- DH4: each session unique; stronger forward secrecy.
Bob sends his initial message including:
- IK_B (so Alice can identify the sender)
- EK_B (so Alice can run the matching DHs)
- which OPK was used (so Alice knows which one to retrieve)
- ciphertext encrypted with key derived from SK
Alice on receiving:
DH1 = DH(SPK_A, IK_B)
DH2 = DH(IK_A, EK_B)
DH3 = DH(SPK_A, EK_B)
DH4 = DH(OPK_A, EK_B)
SK = HKDF(DH1 || DH2 || DH3 || DH4) # same as Bob's
Decrypt. Delete OPK_A from her storage so it can't be reused. Both sides now have a shared SK and proceed to Double Ratchet.
X3DH (X25519 + HKDF-SHA-256) is the standard. Production code: signal-protocol-c, libsignal.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…