Archivecryptography
X25519 and the Shared Secret You Never Use Directly
The raw Diffie-Hellman output is not a key. Feed it through a KDF and bind the transcript.
- Published
- Reading time
- 1 min read
X25519 computes shared = X25519(private, peer_public) and returns 32 bytes. Those bytes are a group element encoding, not uniformly random material, and must not be used as an encryption key directly.
The correct pipeline
shared = X25519(sk, pk_peer)
salt = client_random || server_random
prk = HKDF-Extract(salt, shared)
key = HKDF-Expand(prk, "handshake key" || transcript, 32)
The salt and info bind the key to this specific handshake. A replay of the same curve point in another session produces a different key.
Hygiene
- Reject all-zero outputs (small-order points). X25519 implementations do this, but check.
- Use ephemeral keys per session for forward secrecy; static-static only when you need a long-term shared secret.
- Never mix public keys from different curves without length prefixes.
Takeaway: Diffie-Hellman gives you a secret, not a key. KDF it, label it, bind it to the transcript.