WireGuard — A closer look

Uwe Helm
Systems and Network Security
7 min readApr 10, 2021

--

In this post we will take an in-depth look at the WireGuard protocol, a modern and lightweight implementation of a VPN tunnel.

WireGuard was created by Jason Donenfeld in 2016 as a replacement for existing VPN protocols such as IPSec and OpenVPN. Donenfeld’s rationale for the new protocol was that the gold-standard of VPN implementations, IPSec, suffered from immense complexity and was, in his words, “hard to get right”. With a history going back to the 90s and a generally modular approach, IPSec supports many protocols, protocol options and requires backwards compatibility with every standard it ever supported. To Donenfeld it became clear that a radical break was needed and he set out to implement a new protocol from scratch, rather than propose his ideas to the consortium behind IPSec.

WireGuard was originally presented at NDSS 2017 and described in a whitepaper [1] by Jason Donenfeld. Design goals of WireGuard include a fixed, non-negotiable set of modern cryptographic primitives, high performance throughput as well as a small attack surface resulting from simplicity and limited decision-making.

What is a VPN?

VPN stands for Virtual Private Network. The primary goal of a VPN is to provide a secure channel between two endpoints that can be used to encapsulate and transport other network protocols through it. This is no different than that of other VPNs. WireGuard operates at Layer 3 of the OSI model and can encapsulate from this layer upwards.

Secure channels have three primary objectives: authenticity, integrity and privacy. Authenticity means that the origin of the data is guaranteed and that data cannot be spoofed or repeated later. Integrity means that the data was not altered while in transit. Privacy guarantees that only the endpoints involved in the secure channel have the ability to see the plain text data. The data is encrypted while it’s in transit. All common VPN protocols implement these paradigms, although sometimes not all of them are used due to performance reasons or other factors.

Noise

In order to understand WireGuard’s nuances and the way it differs from existing protocols requires a deep dive into its cryptographic primitives.

WireGuard builds on cryptographic framework called Noise which has been praised for its use in the Signal messenger implementation. Noise is a framework for building cryptographic secure-channel protocols based on the
Diffie-Hellman (DH) key exchange mechanism. It is not a protocol by itself, but rather guides designers in building new communication protocols securely with verified best practices. This includes protections such as perfect forward secrecy, identity hiding, mutual authentication and zero round trip encryption. The framework specifies a key exchange method using static and ephemeral keys, a message format, cryptographic functions and processing rules.

A key aspect of Noise is its simplicity and lack of flexibility when negotiating encryption between two parties. The authors note that pre-existing protocols can be verifiably secure, but become increasingly hard to use as complexity is added. The framework prescribes in internal state machine that only advances or aborts. There are no branches, negotiations or retries within it, which reduced the amount of unpredictable errors. The primary design goal of Noise is to make negotiations free of any decision-making.

Cryptography

The principal problem of every secure channel is the establishment of a shared key and its use thereafter. To implement authenticity, integrity and privacy a number of cryptographic primitives are required:

The following protocols and primitives are used in WireGuard [2]:

WireGuard does not rely on X.509 certificates or PKIs for key exchange. This is one of the principal differences to IPSec, which relies heavily on certificates and signatures.

WireGuard instead uses a Diffie-Hellman based key exchange protocol, namely X25519. We will get into more detail later, but for now we have to understand that this requires a pre-shared public key between the parties.

Once the key has been exchanged it can be used for encryption. This is where ChaCha20+Poly1305 is used. This is an AEAD (Authenticated Encryption with Additional Data) cipher that provides confidentiality as well as integrated authenticity of the data. Traditionally these are two separate operations handled by two separate ciphers. However, this can have a significant performance and has been a target of attacks such as POODLE and Lucky13.

BLAKE2s for hashing and HKDF for key derivation are modern implementations of classic functions required in complex secure communication protocols.

Implementation

Before any communication occurs both parties have generated a static public and private key pair. Users configure the desired nodes of the secure channel by associating static public keys with IP addresses. A node with a certain public key will require access to the corresponding private key to continue communication.

Once a connection is initiated, WireGuard starts the handshake as the key exchange phase of the protocol. As part of the initial handshake message, nodes use the static pre-configured public key and short-lived ephemeral keys to derive session keys. After the handshake phase, additional keys are derived from these session keys and used in the transport phase to protect data.

All possible pairwise combinations of static and ephemeral keys are involved in the computation, which gives WireGuard Perfect Forward Secrecy.

By combining multiple secure channels between nodes in star pattern, WireGuard can be used to implement mesh topologies.

The Linux kernel 5.6, released in March 2020, included the WireGuard reference implementation with Linux founder Linus Torvalds calling it a “work of art” compared to OpenVPN and IPsec. He actively advocated for its inclusion in Linux. Other implementations are steadily coming forth, such as CloudFlare’s “BoringTun”, a WireGuard-based userspace VPN solution written in the Rust programming language. There is also a stable implementation for OpenBSD and an implementation for FreeBSD. The latter caused some controversy and had to be reverted after a security audit by Donenfeld himself showed significant implementation errors.

Networking

Contrary to established networking practices, WireGuard does not listen and operate on a standard port. When a configuration wizard is used the port for a node is upwards of 51820/UDP, but any port can be used for a node. All packets are transferred through UDP. TCP is not supported.

WireGuard does not respond to unauthenticated clients in order to prevent DoS attacks. The authors also added a protection mechanism that prevents processing Diffie-Hellman authentication requests when under significant load. Instead, the server responds with a cookie that needs to be included in subsequent requests for authentication. This allows the server to recognize an IP on the second request and rate limit the connection as needed.

Performance

Notable for performance is the use of the ChaCha20 cipher instead of AES. On general-purpose CPUs without instructions for AES (AES-ni), ChaCha20 generally outperforms AES. However, AES instructions within CPUs are very common so that realistically AES-based VPN protocols will outperform WireGuard significantly. A notable exception are low-power devices that do not include AES-ni extensions. The ChaCha20-Poly1305 is a desirable
and more performant option in this case. It remains to be seen if the cipher will gain enough popularity to warrant dedicated hardware support.

Hands-on

Now that we’ve covered the theoretical part we can show how simple the configuration of the secure channel is in practice. To prepare the systems we’ve installed the WireGuard kernel module and userspace tool (“wg”). The screenshots below demonstrate all the necessary steps to setup an association between two nodes:

(1) We generate a private key on each system:

(2) We generate a public key from the private key

(3) We create the tunnel interface and assign the tunnel IP to it

(4) We associate the private key with the tunnel interface (“wg0”)

(5) This displays the system interfaces. The physical interface eth0 which will be the endpoint for the connection, and the virtual tunnel interface wg0

(6) The wg command displays the listening port and public key for each node

(7) We configure the remote node and public key for the wg0 interface. The remote public key and port are needed for this.

(8) The connection is automatically established and functional. The tunnel interface addresses will be accessible even if the endpoints had multiple routing hops between them.

Acknowledgements

[1] Donenfeld, J. 2017. WireGuard — Fast, Modern, Secure VPN Tunnel — NDSS 2017 Presentation. https://www.wireguard.com/talks/ndss2017-slides.pdf.

[2] Donenfeld, J. 2017. WireGuard Protocol & Cryptography. https://www.wireguard.com/protocol/

--

--