Step 1 of 5 · Reading · ~4 min
Read
VPN Fundamentals
Tunnel Encapsulation and Replay Protection
After this lesson your program takes apart WireGuard transport messages byte by byte, reads the session index and the packet counter, and refuses any counter it has already accepted.
The outer packet
Everything your program sends to a peer is one UDP datagram whose payload is a WireGuard message. The transport data message (whitepaper section 5.4.6) is laid out like this, every integer little-endian:
| Offset | Size | Field |
|---|---|---|
| 0 | 1 | type, always 4 for transport data |
| 1 | 3 | reserved, zero |
| 4 | 4 | receiver index |
| 8 | 8 | counter |
| 16 | n | encrypted padded inner packet, then a 16 byte tag |
The first four bytes are really one 32 bit integer whose value is 4. A keepalive, the smallest valid message, carries no inner packet and is 32 bytes: the header and the 16 byte tag. One as it appears on the wire:
04 00 00 00 | 2a 00 00 00 | 07 00 00 00 00 00 00 00 | a54dca182530bb1d6d132cded6237b2e
type 4 index 42 counter 7 16 byte tag
Little-endian means the least significant byte comes first, so 2a 00 00 00 is 42, not 704643072. Three other types exist: 1 is the handshake initiation (148 bytes), 2 the response (92 bytes) and 3 a cookie reply (64 bytes). This stage handles transport data only; anything else is dropped here.
The receiver index is a number the receiving side picked when the session was created and told the sender during the handshake. It lets the receiver find the right session and key without trying them all. The counter is a per-direction packet number that starts at 0 and goes up by one for each packet. Soon it will also be the encryption nonce, which is why it must never repeat.
Replay protection
UDP may deliver a datagram twice, and an attacker on the path can record a valid message and send it again later. Both must fail. The receiver keeps the highest counter accepted so far and a bitmap of which of the last N counters below it were already seen. For each message:
- A counter above the highest is new. Accept it, slide the window up to it, and mark it as seen.
- A counter at or below
highest - Nis too old to judge. Reject it. - Otherwise it is inside the window: reject it if its bit is already set, else set the bit and accept.
Worked trace with a window of N = 5:
| Counter | Highest before | Decision | Highest after |
|---|---|---|---|
| 1 | none | new | 1 |
| 2 | 1 | new | 2 |
| 5 | 2 | new | 5 |
| 4 | 5 | in window (distance 1), unseen: accept | 5 |
| 4 | 5 | in window, already seen: replay | 5 |
| 0 | 5 | distance 5 is not below N: too old | 5 |
Real WireGuard uses a window of about 8,000 counters. This exercise limits N to 64 so the whole bitmap fits in one 64 bit integer; the logic is identical. Packets legitimately arrive out of order, which is why a plain "must be larger than the last" rule would drop good traffic.
In a real implementation the window is only updated after the message authenticates. If a forged message could move the window, an attacker could push it far ahead and make every genuine packet look too old. Authentication arrives in the AEAD lesson; here every well-formed message counts as authentic.
Common mistakes
- Big-endian reads. The index comes out as 704643072 instead of 42, and the counter is garbage.
- Counters in a 32 bit or floating point number. The counter uses all 64 bits. A value such as 2^53 + 1 is silently rounded in a double.
- Off by one at the edge. With N = 64 and highest 100, counter 37 is still inside, counter 36 is not.
- Not clearing the bitmap on a big jump. When the new counter is N or more above the highest, nothing old stays in the window. Shifting a 64 bit integer by 64 is undefined in some languages.
- Calling a short or foreign message good. Fewer than 32 bytes, or type other than 4, is dropped.
Your exercise
The starter reads the lines and decodes the hex. You validate the header, decode the two fields and keep the window. The most likely mistake is mixing up which end of the window is inclusive.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…