The New Way To Create A Secure Tunnel … The WireGuard Protocol

SSL/TLS is a poor security protocol, and where the secure tunnel can often be broken with a proxy/smart firewall. Those working in a…

The New Way To Create A Secure Tunnel … The WireGuard Protocol

SSL/TLS is a poor security protocol, and where the secure tunnel can often be broken with a proxy/smart firewall. Those working in a secure environment should thus not rely on SSL/TLS to provide a secure environment. The solution for many, then, is to use IPSec in order to create a proper VPN tunnel.

IPSec involves the negation of a tunnel policy, such as for the encryption method used, the key exchange method, the hashing method, and so on. There are normally two phases to this, where in the first phase we define the methods to be used, and the second phase involves the actual handshaking of the encryption key to be used, and the policy involved with the tunnel. But IPSec is overblown and contains many legacy cryptography methods. With this, an intruder could pull down the security of a tunnel to an unacceptable level, and break it. So what’s the solution? Well, one method that can be used is WireGuard. With WireGuard we have a simpler solution than packages such as IKEv2 and OpenVPN, and which is more lightweight. While other packages need 100s of thousands of lines of code, WireGuard only requires only around 4,000 lines of code [here]:

WireGuard

WireGuard was created by Jason A. Donenfeld in 2016 and has now been ported to Windows, Linux, Android and iOS. At its core is the usage of the more modern cryptography methods such as Curve25519 (for ECDH — Elliptic Curve Diffie Hellman — key exchange), ChaCha20 (for fast symmetric key encryption), Poly1305 (for AEAD methods), BLAKE2s (for hashing), SipHash25 (for hashtables) and HKDF (for key derivations). It also uses a connection-less approach (with UDP), and which is generally faster than TCP based methods.

Initially, there is a connection request from an initiator which has the following format:

msg = handshake_initiation {
u8 message_type
u8 reserved_zero[3]
u32 sender_index
u8 unencrypted_ephemeral[32]
u8 encrypted_static[AEAD_LEN(32)]
u8 encrypted_timestamp[AEAD_LEN(12)]
u8 mac1[16]
u8 mac2[16]
}

We can see a practical example here, and where there is a sender index (0xc1039c02), an unencrypted ephermeral value, an encrypted static value, an encrypted timestamp, and two HMAC values:

This is the first part of the ECDH key exchange, and where unencrypted_ephemeral is Bob’s public key for the session. Next Alice, will send back a message in the following format:

msg = handshake_response {
u8 message_type
u8 reserved_zero[3]
u32 sender_index
u32 receiver_index
u8 unencrypted_ephemeral[32]
u8 encrypted_nothing[AEAD_LEN(0)]
u8 mac1[16]
u8 mac2[16]
}

The second part of the response is the closing part of the ECDH handshake, and where the receiver now defines the receiver index value (0xdce3fa01). The sender and the receiver IDs now will match the session connection (in a similar way to TCP ports and IP addresses). The unencrypted_ephemeral field defines the public key of Alice for the session, and when Bob receives this, he can compute the shared key:

After this, Bob and Alice will have the same shared key, and will then use ChaCha20 and Poly1305 to create an encryption tunnel. Overall, for the ECDH handshake, Bob and Alice will use Curve 25519 to produce the shared key.

The packets that come after this are then encrypted with the shared key and contain a message type, a receiver index (to match to the session), a counter, and the encrypted content:

msg = packet_data {
u8 message_type
u8 reserved_zero[3]
u32 receiver_index
u64 counter
u8 encrypted_encapsulated_packet[]
}

In the following, we have an example of Transport Data for a receiver of 0xAB7DF406:

For the next packet sent by the same host, we see that the counter value has been incremented:

In this way, the sender and receiver can keep track of the packets (in a similar way to the TCP segment number).

Conclusions

Our existing tunnelling methods are perhaps overblown. They contain many old methods and which are often resource inefficient, and potentially insecure. One only has to look at SSLLabs to see that many Web sites still support out-of-date methods. With WireGuard, we have only one selection for the methods, but it is a good selection. ChaCha20 and Poly1305 provide AEAD support, Curve 25519 is a fast and secure curve for key exchange methods, Blake2s is one of the fastest cryptography hashing methods around, and HKDF is a fast and secure method of generating encryption keys. So rather than having 100s of thousands of lines of code to implement the tunnel, WireGuard just needs a few thousand lines of code. And, the smaller the code footprint, the more likely that it will be free of code bugs.

For the final comment:

“Can I just once again state my love for [WireGuard] and hope it gets merged soon? Maybe the code isn’t perfect, but I’ve skimmed it, and compared to the horrors that are OpenVPN and IPSec, it’s a work of art.”

— Linus Torvalds