Post-Quantum Encryption on a Webserver - Overview

Go 1.23rc2’s Post-Quantum Encryption

In a forthcoming version of Go, Post-Quantum Encryption will be used. It is only available by default in the tls package. To try out the new feature, we can write a simple webserver in Go, compile it with the latest release candidate of Go 1.23, and check what encryption is being used for TLS.

TLS and the Role of the Key Exchange Mechanism

The Key Exchange Mechanism is the exchange of a key for symmetric cryptography. AES is the symmetric block cipher whose key needs to be exchanged. It is suitable to encrypt large amounts of data, and can be used for HTTP requests and responses. To exchange the AES key, a public key cryptography system is needed. This allows the browser and webserver to communicate the key without having a shared secret at the start of the TLS 1.3 handshake. Although too computationally expensive to encrypt the whole message, public key cryptography can encrypt an AES key which then encrypts the message.

What’s New: Kyber 768

Traditionally, the public key cryptography system used for the key exchange is elliptic curve cryptography, often using the X25519 curve. Kyber 768, on the other hand, uses lattice based cryptography - specifically a variation of the ‘Learning with Error’ problem. This is a mathematical problem where quantum computers have no particular advantage for cryptanalysis, so anyone recording your TLS handshake and the subsequent HTTP traffic should not be able to decrypt the AES key in years to come.

In fact, the X25519Kyber768Draft00 cipher suite uses both elliptic curve and Post-Quantum Cryptography. The client’s elliptic curve ephemeral share value (32 bytes) and the Kyber 768 public key (1184 bytes) are concatenated together and sent to the server. The server responds similarly with the X25519 ephemeral share (32 bytes) and the Kyber ciphertext (1088 bytes).

The use of a hybrid system means an attacker would need a powerful quantum computer and there would need to be a vulnerability in Kyber for the AES key to be determined.

Uptake of PQC

Cloudflare are using X25519Kyber768Draft00 in production. In fact, their researcher Bas Westerbaan invented the hybrid scheme. (I wrote a post on compiling Caddy with Cloudflare’s fork of Go to use Post-Quantum Cryptography.) Google Chrome now supports Kyber, and it is in use on the Google Search homepage, for visitors with a compatible browser.

Elsewhere, the OpenSSL project uses a similar hybrid system (with a different algorithm) for key encapsulation after authentication has taken place.

Building a Webserver with Go 1.23rc2

Webserver Code

I have built a simple webserver in Go 1.23rc2. Some of its details won’t be of interest to the reader, but the key parts are here:

go.mod:

1
2
3
4
5
module sam-bee/quantum-blogserver

go 1.23rc2

require (

The go.mod file shows the project uses Go 1.23

Incidentally, if you run this project with Go 1.22 or previous, it still works, but hybrid Post-Quantum Cryptography is not used.

Key part of the actual code:

18
19
20
21
	// Start the HTTPS server
	log.Println("HTTPS server started...")
	port := ":" + strconv.Itoa(conf.getPortNo())
	log.Fatal(http.ListenAndServeTLS(port, conf.getCertPem(), conf.getKeyPem(), nil))

The code uses http.ListenAndServeTLS() to act as a webserver

Crucially, we did not specify a TLS curve that we want to use. Under the bonnet in Go 1.23’s tls package, X25519Kyber768Draft00 is the default ‘curve’ (although it is really a curve and a lattice). We can specify overrides, and that will allow us to use other curves, but the x25519Kyber768Draft00 value is un-exported in Go 1.23, meaning it can’t be specified by the user of the tls package. It is likely to stay this way until NIST finalises a new standard, and the Go team are comfortable committing to a public API for the Kyber integration.

Testing Our Webserver

We can test our webserver by navigating to https://localhost:8443 (or whatever port number has been configured.) Looking at the dev tools in Chrome, we can see the relevant cipher suite:

A screenshot of Google Chrome developer tools, with the cipher suite highlighted. It is X25519Kyber768Draft00

A screenshot of Google Chrome developer tools. The cipher suite is X25519Kyber768Draft00

A zoom in on the other screenshot. The text reads: The connection to this site is encrypted and authenticated using TLS 1.3, X25519Kyber768Draft00, and AES_128_GCM

“The connection to this site is encrypted and authenticated using TLS 1.3, X25519Kyber768Draft00, and AES_128_GCM”

We can see that our browser and our webserver are talking to each other using X25519Kyber768Draft00 hybrid Post-Quantum Cryptography.

As noted before, this is only if you use Go 1.23rc2. In Go 1.22, plain X25519 is used.