> WIREGUARD — THE MODERN VPN PROTOCOL
The idea in plain English: Imagine a VPN that fits on a single page of code. That's WireGuard. Created by Jason Donenfeld between 2015 and 2018, it's a VPN protocol that does everything OpenVPN does but in ~4,000 lines of code compared to OpenVPN's ~400,000. It's built into the Linux kernel since version 5.6, it's the default VPN protocol for Mullvad and Proton VPN, and it uses only the most modern cryptographic primitives — Curve25519, ChaCha20, Poly1305, BLAKE2, and HKDF.
Think of WireGuard as the spiritual successor to SSH — simple, auditable, modern. Each interface has a private key and a short list of peers with their public keys. No certificate authorities, no configuration generators, no TLS handshake. Just keys, UDP packets, and the Noise Protocol Framework.
Why this really exists: Before WireGuard, setting up a VPN was painful. OpenVPN required certificate chains, CA management, TLS configuration, and hundreds of options. IPsec was worse — notoriously complex with IKE, ESP, AH, and dozens of RFCs. WireGuard said: what if a VPN was as simple as SSH? The result is a protocol that's 10x faster, 100x simpler, and auditable by a single person in an afternoon.
▸ The WireGuard Handshake — Step by Step
WireGuard uses the Noise Protocol Framework's IK handshake pattern. The "IK" means the initiator (client) knows the responder's (server's) static public key in advance. This is the key insight — WireGuard doesn't need a CA because you already know your peer's key, just like you know your friend's SSH host key.
1. Handshake Initiation (Initiator → Responder) — The initiator generates
an ephemeral Curve25519 key pair (e_i, E_i). It loads the responder's static public key (S_r)
and performs a DH operation between its ephemeral secret and the responder's static key:
dh1 = ECDH(e_i, S_r). It also does dh2 = ECDH(s_i, S_r) using its
own static key. These DH outputs feed into the key derivation function (KDF chain).
2. Handshake Response (Responder → Initiator) — The responder generates its
own ephemeral key (e_r, E_r), performs DH between its ephemeral secret and the initiator's
(now learned) ephemeral public: dh3 = ECDH(e_r, E_i). It also does
dh4 = ECDH(s_r, E_i). The KDF chain advances with each DH operation, producing
separate encryption keys for each message direction.
3. Key Derivation Chain — WireGuard uses a BLAKE2-based KDF
(similar to HKDF but uses BLAKE2s hashing). Each DH output is mixed into a chaining key (CK)
via KDF(CK, dh_output). This produces:
CK = KDF(CK, dh1) ← ephemeral_i × static_r
CK = KDF(CK, dh2) ← static_i × static_r
CK = KDF(CK, dh3) ← ephemeral_r × ephemeral_i
CK = KDF(CK, dh4) ← static_r × ephemeral_i (optional, depends on role)
# After all DH operations, the KDF outputs:
sender_key — used to encrypt data from initiator → responder
receiver_key — used to encrypt data from responder → initiator
Re-key after every ~2^64 packets using a symmetric ratchet
Each DH operation advances a ratchet — compromise one ephemeral key and only that session is affected. Forward secrecy is baked in.
4. Data Transport — Once the handshake completes, all data packets are encrypted with ChaCha20-Poly1305 (AEAD). Each packet has a monotonically increasing counter that prevents replay attacks. The session keys are rotated periodically. Total handshake: 3 messages, 1 round trip.
▸ Concrete Example — Key Derivation Chain
Let's trace a simplified WireGuard handshake with small scalar values to illustrate the KDF chain. In reality, Curve25519 uses 256-bit scalars and BLAKE2s for hashing.
Initiator ephemeral: e_i = 5 → E_i = 5·9 = 45
Initiator static: s_i = 2 → S_i = 2·9 = 18
Responder static: S_r = 3·9 = 27
dh1 = e_i × S_r = 5 × 27 = 135 (simplified scalar multiplication)
dh2 = s_i × S_r = 2 × 27 = 54
# Simplified KDF chain (real uses BLAKE2s + HKDF-like extraction/expansion):
CK₀ = "WireGuard KDF init"
CK₁ = BLAKE2s(CK₀ || dh1) = BLAKE2s("WireGuard KDF init" || 135)
CK₂ = BLAKE2s(CK₁ || dh2) = BLAKE2s(CK₁ || 54)
sender_key = BLAKE2s(CK₂ || 0x01)
receiver_key = BLAKE2s(CK₂ || 0x02)
In the puzzle, you may be given intermediate KDF states and need to compute the final session keys (or vice versa).
The puzzle uses a simplified BLAKE2 or SHA-256 KDF chain rather than the full WireGuard KDF, but the ratchet structure — sequential mixing of DH outputs into a chaining key — is identical.
▸ Difficulty Levels
| Level | What You Work With | Required Knowledge |
|---|---|---|
| 1–2 | Given DH values, compute a single KDF step to find a key | Basic hash function usage |
| 3–4 | Given two of three (DH1, DH2, final key), recover the missing value | BLAKE2/SHA-256, modular arithmetic |
| 5–6 | Full handshake trace with missing ephemeral — recover the private key from DH transcript | Curve25519, ECDH, KDF chain reconstruction |
| 7 | Reverse engineer a real WireGuard packet capture, extract session keys | Noise protocol, AEAD, packet structure |
▸ Real-World Applications
- Mullvad VPN: The most privacy-focused VPN service uses WireGuard as its default protocol — faster connections, no logs, auditable codebase
- Proton VPN: Built-in WireGuard support across all platforms, including their "Stealth" protocol that obfuscates WireGuard traffic
- Linux kernel (since 5.6): WireGuard is built directly into the kernel's networking stack — no user-space daemon needed, minimal latency
- Android / iOS: Both platforms have first-party WireGuard apps (the Android version has over 10 million installs on Google Play)
- Kubernetes: Projects like Submariner and KubeVirt use WireGuard for cross-cluster pod networking and encrypted node-to-node communication
- Enterprise firewalls: Firewalla, OPNsense, pfSense, and Ubiquiti all support WireGuard as a first-class VPN option
▸ Why 4,000 Lines Matters
OpenVPN has ~400,000 lines of code. OpenSSL (which OpenVPN depends on) has ~500,000 more. Combined, that's nearly a million lines of attack surface for a single VPN connection. WireGuard's entire protocol is ~4,000 lines. A single security researcher can read the entire codebase in a day. This is auditability by design — not just fewer bugs, but demonstrably fewer places for bugs to hide.
WireGuard was formally verified using the WireGuard Formal Verification Project which proved the protocol's correctness and security properties (including forward secrecy, resistance to key-compromise impersonation, and more) using the Tamarin prover. You can't formally verify 400,000 lines of code. 4,000 lines? You can prove it correct.
▸ History
- 2015: Jason Donenfeld starts working on a new VPN protocol. First public announcement on the Linux Crypto mailing list in June.
- 2016–2018: Rapid development. Donenfeld presents at Linux Plumbers Conference, Black Hat, and USENIX. WireGuard gains adoption in the privacy community.
- 2019: Linus Torvalds personally merges WireGuard into the Linux networking stack (net-next). Calls it "a work of art."
- 2020 (March): Linux kernel 5.6 ships with WireGuard built-in. This is unprecedented — no VPN protocol had ever been merged into the mainline kernel before.
- 2022: Mullvad becomes the first major VPN provider to default to WireGuard. Proton VPN follows. Apple and Google include WireGuard in their OS distributions.
- Today: WireGuard is the de facto standard for modern VPNs. The protocol is RFC-compliant (RFC 9166) and continues to receive formal verification improvements.
▸ Key Terms
- Noise Protocol Framework: A toolkit for building secure protocols, designed by Trevor Perrin (also co-creator of Signal Protocol). WireGuard uses the IK handshake pattern.
- Curve25519: The elliptic curve used by WireGuard for all DH operations. Fast, constant-time, and resistant to side-channel attacks.
- ChaCha20-Poly1305: Stream cipher + MAC (AEAD). Used by WireGuard and TLS 1.3 as a faster alternative to AES-GCM on devices without AES hardware acceleration.
- BLAKE2: A cryptographic hash function faster than SHA-3 and SHA-2. WireGuard uses BLAKE2s (256-bit) for its KDF and BLAKE2b (512-bit) for hashing.
- HKDF: HMAC-based Key Derivation Function (RFC 5869). WireGuard's KDF is inspired by HKDF but uses BLAKE2s instead of HMAC-SHA256.