The short version: WireGuard does not use TLS, and it does not have a multi-round-trip negotiation like OpenVPN or IPsec/IKEv2. It uses a fixed, opinionated cryptographic handshake derived from the Noise Protocol Framework — specifically the Noise_IK pattern — that completes in exactly two messages. Both peers know each other's long-term public keys in advance (configured statically, the way SSH keys are configured), so the handshake's job is not to discover identities but to mutually prove possession of the corresponding private keys and to derive fresh symmetric session keys with forward secrecy. The whole transaction is small enough to fit in two UDP datagrams of a few hundred bytes each. It finishes faster than a TLS handshake usually does, and the resulting session keys rotate every two minutes for the duration of the connection.
Why a handshake exists at all
Two computers want to communicate privately over a network they don't control. The fundamental cryptographic problem: before they can encrypt anything, they need to agree on a shared secret that an attacker watching the network cannot derive. They also need to verify each other's identity — otherwise an attacker could impersonate the other side and trick one of the peers into encrypting data to the attacker instead.
A handshake solves both problems in a structured exchange:
- Mutual authentication — each peer demonstrates possession of a private key corresponding to a public key the other side already trusts. Neither peer ever transmits the private key itself; they just prove they have it by performing cryptographic operations only that key can produce.
- Forward-secret key agreement — both peers generate fresh, temporary ("ephemeral") key pairs for this specific session, exchange the public halves, and combine them with their long-term keys to derive a symmetric session key. The ephemeral keys are discarded after the handshake; even if the long-term keys are stolen later, the past session keys cannot be reconstructed from them. This property is called forward secrecy and it's the reason past traffic remains protected even if future key compromise occurs.
- Replay protection setup — both peers initialize counters and nonces that prevent an attacker from capturing and replaying earlier traffic later.
Different VPN protocols implement this differently. OpenVPN does it through TLS, with multiple round-trips, certificate validation, and many configurable cipher suites. IPsec/IKEv2 has its own negotiation protocol with similar complexity. WireGuard does it in two packets, no configurability, no cipher suite negotiation — every WireGuard handshake uses the same fixed set of cryptographic primitives. The trade-off is intentional: less complexity means less attack surface and easier auditability, at the cost of zero protocol-level agility.
The Noise framework — what it is and why WireGuard uses Noise_IK
The Noise Protocol Framework is a specification for building cryptographic handshakes. It's the work of Trevor Perrin, who also designed the Signal Protocol that secures Signal, WhatsApp, and most modern end-to-end encrypted messengers. Noise is not a single protocol — it's a kit of building blocks (handshake "patterns," cryptographic primitives, derivation rules) that lets a protocol designer pick the exact handshake shape they need and get a precise specification of what messages contain and what guarantees they provide.
Noise handshake patterns are named with two letters indicating what each side knows in advance:
- N — no static key for that side; only ephemeral keys are used. Anonymous.
- K — the static key is "known" to the other party in advance.
- X — the static key is sent during the handshake.
- I — the static key is "immediately" transmitted in the first message.
Noise_IK means: the initiator sends their static key Immediately (in the first message), and the responder's static key is Known to the initiator in advance. This pattern is ideal for WireGuard's use case because both peers genuinely do know each other's static keys ahead of time — they're configured in the WireGuard config file. The "IK" choice lets the entire handshake complete in two messages, which is the minimum possible for mutually-authenticated forward-secret key exchange.
The Noise framework's full specification is published at noiseprotocol.org and is one of the cleaner pieces of public cryptographic engineering — written to be auditable, with formal verification of the patterns themselves. WireGuard's adoption of Noise_IK was a deliberate design choice to inherit the framework's analysis.
Packet 1: Initiator → Responder
The handshake begins when the initiator (your phone, your laptop, the client side) decides to talk to the responder (the VPN server). This happens either because traffic is queued waiting for the tunnel, or because the session key has expired and a rekey is needed. The initiator constructs a single UDP packet that contains:
- Sender index — a randomly chosen 32-bit integer that identifies this handshake session. Used to disambiguate concurrent handshakes between the same peers.
- Ephemeral public key — a freshly generated Curve25519 public key. The corresponding private key is held in memory by the initiator. This is the "E" in the Noise pattern — the new ephemeral key being introduced.
- Static public key (encrypted) — the initiator's long-term Curve25519 public key, but encrypted with a key derived from the ephemeral exchange. This is part of the "I" in IK — the initiator's static key is sent in the first message but it's protected against passive observers.
- Timestamp (encrypted) — a TAI64N-format timestamp, encrypted. This is the replay-protection anchor: the responder will reject any handshake with a timestamp earlier than one it's already accepted from this peer. Prevents an attacker from capturing and replaying a valid handshake message later.
- MAC fields — two short authenticators (mac1, mac2) that prove the sender knows the responder's public key. The mac2 field is also used for the cookie-reply DoS-mitigation mechanism described in the WireGuard paper.
What this packet proves and accomplishes: by including a fresh ephemeral key, the initiator commits to one half of the eventual session key. By including the timestamp and the MAC tied to the responder's static key, the initiator demonstrates "I have at least the responder's public key" — meaning a random off-path attacker can't trivially send fake handshake initiations and waste server resources. The whole packet is 148 bytes, fits comfortably in a single UDP datagram, and is never fragmented.
One subtlety worth noting: the initiator's static public key is included but encrypted, so a passive observer watching the wire cannot identify which client is connecting. They can see that someone is initiating a WireGuard handshake to this server, but not who. This is a privacy property called initiator identity hiding, and it's stronger than what TLS provides by default.
Packet 2: Responder → Initiator
The responder receives the initiation packet, decrypts the initiator's static public key, and looks it up in its peer table. If the peer is known and the timestamp is acceptable (newer than the last accepted one), the responder generates its own ephemeral key pair and constructs a response packet:
- Sender index — the responder's chosen 32-bit identifier for this session.
- Receiver index — echoed back from the initiator, so both sides agree which session this is.
- Ephemeral public key — the responder's freshly generated ephemeral public key.
- Empty encrypted payload — an authenticated-but-empty ciphertext that proves the responder can derive the session key. This is the cryptographic "I read your message and computed the right key" signal.
- MAC fields — same pattern as the initiation packet.
When the initiator receives this response, it performs the matching key derivation, verifies that the authenticated empty payload decrypts correctly with the derived key, and now both sides have arrived at the same symmetric session key — independently, without that key ever traversing the network. The session key has perfect forward secrecy because it depends on both ephemeral keys (which are about to be destroyed) and both static keys.
The response packet is 92 bytes. The total handshake — both packets combined — is 240 bytes plus IP/UDP headers, fits in two round-trip UDP exchanges that complete in roughly one network RTT (one packet each way), and produces a fully-authenticated forward-secret session ready to encrypt application traffic. There's no certificate chain validation, no cipher suite negotiation, no version comparison, no extension list — none of the things that make TLS handshakes complicated.
The session that follows
Once the handshake is complete, the two peers exchange data packets in a much simpler format. Each data packet contains:
- Receiver index — the 32-bit session ID assigned by the receiver during the handshake.
- Counter — a 64-bit nonce that increments with each packet sent. Used both as the AEAD nonce and for replay detection.
- Encrypted payload — the original IP packet, encrypted with ChaCha20-Poly1305 using the session key and the counter as the nonce.
ChaCha20-Poly1305 is an AEAD (Authenticated Encryption with Associated Data) construction: it both encrypts the payload and produces an authentication tag that detects any tampering. If a single bit of the ciphertext is flipped, the decryption fails, and the receiver discards the packet. There's no "soft" failure mode — modified packets are silently dropped, just like packets with the wrong counter or wrong receiver index.
The receiver maintains a sliding window of accepted counter values. Packets with counters that fall within the window and haven't been seen before are accepted; packets that fall below the window (too old) or have been seen are rejected. This provides anti-replay protection without requiring the receiver to remember every counter ever seen — just the most recent ones, in a small bitmap.
From the network's perspective, the data packets look identical regardless of payload content. They're all UDP packets to the same server IP and port, with similar sizes (the encrypted payload preserves the size of the underlying IP packet plus 32 bytes of overhead), and no observable pattern that distinguishes them. There's no SNI, no certificate exchange, no TLS handshake-then-data structure — just opaque UDP after the initial two-packet handshake.
Rekey behavior — every 2 minutes OR every 2^60 packets
WireGuard rotates session keys aggressively. The default rekey policy: a new handshake is initiated when the current session has been active for 2 minutes or has transmitted 2^60 packets, whichever comes first. In practice, the time bound is what triggers rekeying for most sessions — 2^60 packets is an astronomically large number that no real connection ever reaches.
Why 2 minutes? Two reasons. First, frequent rekeying improves forward secrecy. Each session is encrypted with a key derived from one specific pair of ephemeral keys. The shorter the session, the less data ever flows through any single key, so even theoretical future cryptanalytic attacks would have to compromise many keys to read a meaningful amount of traffic. Second, the rekey is invisible to the application — the new handshake happens in the background while the old session keys continue to encrypt data, and the switchover is seamless. Both peers maintain a small overlap window where they accept packets encrypted with either the old or new key.
The rekey is initiated by whichever peer notices the timer expiring first — usually the initiator side. The protocol message is the same two-packet handshake described above. From an outside observer's perspective, they see a small flurry of additional UDP packets every two minutes, but no observable change in the data stream itself.
Handshake phases at a glance
The full handshake, broken down by phase, packet, and the cryptographic primitive doing the work:
| Phase | Packet | What's transmitted | Cryptographic primitive |
|---|---|---|---|
| 1. Initiation | Initiator → Responder (148 bytes) | Sender index, ephemeral public key, encrypted static key, encrypted timestamp, MACs | Curve25519 (ECDH), BLAKE2s (hash/MAC), ChaCha20-Poly1305 (AEAD), HKDF (key derivation) |
| 2. Response | Responder → Initiator (92 bytes) | Sender index, receiver index, ephemeral public key, empty encrypted payload (key-confirmation), MACs | Curve25519 (ECDH), BLAKE2s, ChaCha20-Poly1305, HKDF |
| 3. Data session | Both directions, indefinitely (32 bytes overhead per packet) | Receiver index, counter, encrypted IP packet | ChaCha20-Poly1305 (AEAD) |
| 4. Rekey (every 2 min) | Same two-packet exchange as phases 1+2 | Fresh ephemeral keys, new session key derivation | Same primitives |
Five cryptographic primitives are used throughout, none of them negotiable: Curve25519 for elliptic-curve Diffie-Hellman key agreement, ChaCha20 for symmetric stream encryption, Poly1305 for the authentication tag, BLAKE2s for the hash function and MAC, and HKDF for key derivation. This is the "no agility" design choice: by hard-coding the primitives, the protocol surface shrinks dramatically and the analysis becomes much more tractable. The cost is that if any primitive is ever broken, the entire protocol needs a new version — there's no in-band way to upgrade. The bet WireGuard makes is that these primitives are well-studied enough that a sudden break is unlikely.
What can go wrong
Cryptographic handshakes have known failure modes. Some apply to WireGuard; some don't. Worth understanding:
Replay attacks
The encrypted timestamp in the initiation packet prevents replays. If an attacker captures a valid initiation packet and tries to replay it later, the responder sees a timestamp it has already accepted (or one that's older than the latest accepted one) and rejects the packet. This is one of the reasons WireGuard maintains per-peer state about the latest handshake timestamp — the protocol depends on it.
Long-term key compromise
If an attacker steals a peer's long-term private key, they can impersonate that peer in future handshakes. They cannot, however, decrypt past sessions — the ephemeral keys that derived those session keys were destroyed after each handshake. This is the forward-secrecy guarantee. The mitigation for ongoing risk is to rotate the long-term key (generate a new pair, distribute the new public key to peers) — there's no protocol-level mechanism to invalidate an old key, so this has to be done out-of-band.
NAT timeout and silent connection death
WireGuard runs over UDP, which is connectionless. Network address translators (in your home router or your ISP's network) sometimes drop UDP flow entries after a few minutes of inactivity. When this happens, the responder's reply packets can no longer reach the initiator — the NAT has forgotten the mapping. The mitigation is the keepalive setting (often set to 25 seconds), which sends a small heartbeat packet from initiator to responder to keep the NAT mapping alive. Without keepalive, idle connections can silently die and require a new handshake to restore.
Denial-of-service via handshake flood
A responder under heavy attack might receive many fake handshake initiations, each of which requires Curve25519 operations to process. WireGuard mitigates this with the cookie-reply mechanism: when the responder is under load, it can demand that the initiator perform a small proof-of-work-style computation before the responder commits to a full handshake. The mac2 field in the handshake packets carries this mechanism. The DoS resistance isn't perfect — no protocol can be — but it's substantially harder to flood than e.g. an unauthenticated TCP-based service.
Why this matters for VPN users, practically
The handshake architecture has concrete user-visible benefits compared to older VPN protocols:
- No client-side TLS handshake — WireGuard does not validate certificates, does not chain to a CA, does not depend on the system trust store. This eliminates a whole class of attacks (compromised CAs, mis-issued certs) that affect TLS-based VPNs.
- No stateful connection — the protocol runs over UDP and is connectionless. There's no TCP-style state machine to break when the network changes. A roaming device that switches from Wi-Fi to cellular doesn't need to re-establish anything; it just starts sending packets from the new IP address and the responder accepts them.
- Instant roaming — because the connection is identified by the cryptographic keys rather than the source IP address, the responder will accept packets from any source IP that produces the correct cryptographic authentication. This is why WireGuard handles mobile network transitions far better than OpenVPN or IPsec, which often need to renegotiate when the underlying IP changes.
- Tiny attack surface — the reference implementation is about 4,000 lines of code. OpenSSL is over 500,000. This isn't a fair comparison (they do different amounts of work), but the implication is real: smaller code is easier to audit, easier to formally analyze, and presents fewer opportunities for implementation bugs that turn into vulnerabilities.
- Predictable performance — every handshake uses the same primitives at the same key sizes. There's no fast-path/slow-path divergence based on negotiated cipher suite. The handshake takes about the same time on the same hardware regardless of who you're connecting to.
For the trade-off comparison with the older protocol it replaced for most users, see our writeup on WireGuard vs OpenVPN, which covers the practical performance and security differences. For why a VPN's tunneling choices matter for what apps see, see what is split tunneling.
Casper's Cloak uses WireGuard for all client connections, runs the official kernel-mode implementation on Linux endpoints, and ships the standard userspace client (built on the wireguard-go reference) on iOS, Android, and macOS. The handshake described above is exactly what happens when you turn the app on. The same Noise_IK pattern, the same Curve25519/ChaCha20-Poly1305/BLAKE2s/HKDF primitive set, the same 2-minute rekey, the same 240-byte handshake. The threat protection feature layers DNS-level filtering on top of the WireGuard tunnel — the tunnel handles transport, the filter handles destination policy.
For the full protocol specification, the original WireGuard whitepaper by Jason Donenfeld is the authoritative reference: wireguard.com/papers/wireguard.pdf. The paper covers the cryptographic construction, the threat model, the formal analysis, and the implementation rationale. It's one of the more readable pieces of modern protocol-design writing — worth the hour to skim if you want to understand the design trade-offs at the source.
Bottom line: the WireGuard handshake is two packets, takes under 100 milliseconds in practice, mutually authenticates both peers, derives forward-secret session keys, and resists every common attack pattern (replay, downgrade, identity disclosure, DoS) by design. It's a tight, fixed, opinionated protocol, and that opinionation is precisely the point.