Post Quantum Cryptography Web Server in Go 1.23

Gil Adda
CyberArk Engineering
6 min readSep 23, 2024

Hey there, fellow Gophers! Ready to leap into the quantum realm? With Go 1.23’s release in August 2024, we’ve got something exciting to talk about — quantum-safe cryptography!

You might wonder, “Why should I care about quantum computers?” These futuristic machines could crack our current encryption methods like a nutshell.

But don’t panic! Go’s got our backs. Go 1.23 introduces the X25519Kyber768 hybrid algorithm for TLS — our new shield against quantum threats, identified by the curve ID 0x6399 (aka “x25519Kyber768Draft00”).

In this post, we’ll dive into:

  1. How to quantum-proof your Go apps (it’s easier than you think!).
  2. Setting up an HTTP server that’s ready for the quantum age.
  3. Peeking under the hood to see what crypto magic is happening in your connections.

So grab your favourite beverage, and let’s future-proof our Go code together! Trust me, your future self will thank you for this quantum leap in security.

TLDR: If you are short of time, make your Golang program post-quantum cryptography safe.

You need to:

  • Compile it using the Golang 1.23 version and higher.
  • Ensure TLS 1.3 support.
  • Avoid explicitly defining curve preferences.

Let’s build a web server, configured to include the post-quantum algorithm.

Post Quantum Cryptography in Go

TLS post-quantum cryptography uses the Hybrid Kyber algorithm, combining classical X25519 elliptic curve key exchange with post-quantum Kyber768 key encapsulation identified by a new TLS configuration curve ID: X25519Kyber768Draft00.

The CurveID type identifies different elliptic curves and key exchange mechanisms, distinct from cipher suite definitions. Cipher suites define complete algorithm sets, while curve IDs specify only the key exchange curve.

In Go, TLS 1.3 cipher suites are automatically selected. Curve ID definitions are also unnecessary, resulting in a minimal TLS configuration.

Understanding the Magic: TLS Communication and Post-Quantum Cryptography

If you’re curious about how this process works, read on or skip to the next sections for TLS configuration examples and code.

TLS communication involves several key steps:

  1. Establishing a TCP connection.
  2. Securely exchanging a symmetric key between the client and server.
  3. Encrypting data with the shared symmetric key, known only to the communicating parties.

Symmetric encryption algorithms like AES with a 256-bit key resist quantum attacks, but key exchange algorithms remain vulnerable.

For example, X25519 is an elliptic curve Diffie-Hellman key exchange protocol using Curve25519. While secure against classical computers, it is vulnerable to quantum attacks.

Enter Kyber: A Post-Quantum Solution

Kyber is a key encapsulation mechanism (KEM) selected by NIST for security against both classical and quantum computers.

The Kyber Key Exchange Process

The key agreement process with Kyber works as follows:

  1. The initiator (typically the client) generates a fresh key pair and sends the public key.
  2. The receiver (typically the server) generates a shared secret and encrypts (“encapsulates”) it using the initiator’s public key.
  3. The receiver sends the ciphertext back to the initiator.
  4. The initiator decrypts (“decapsulates”) the shared secret using its private key.

This ensures a secure key exchange resistant to both classical and quantum attacks.

While slightly slower than X25519 alone, it significantly improves security with minimal performance impact during connection initialization.

For more information, refer to Cloudflare’s blog post: Post-Quantum Cryptography for All.

Let’s Set the TLS Configuration

When configuring an HTTPS / TLS server to support post-quantum cryptography, consider the following:

  1. TLS Version: Ensure TLS 1.3 support, as it’s required for the Hybrid Kyber Algorithm (available from Go 1.23).
  2. Curve Selection: The Hybrid Kyber algorithm uses the x25519Kyber768Draft00 curve (ID: 0x6399), an extension of X25519 (ID: 29).
  3. Automatic Curve Selection: To enable x25519Kyber768Draft00, set an empty CurvePreferences list in your TLS configuration. This allows the server to automatically select the post-quantum curve when supported by the client.

Example: Quantum safe TLS configuration:

&tls.Config{
MaxVersion: tls.VersionTLS13,
CurvePreferences: []tls.CurveID{},
// Other necessary configuration options...
}

This setup ensures your server can use post-quantum cryptography when available, while maintaining compatibility with clients that don’t support it.

Here’s an example of an incorrect configuration (will not support Hybrid Kyber):

&tls.Config{
MaxVersion: tls.VersionTLS13,
CurvePreferences: []tls.CurveID{
tls.CurveP256,
tls.CurveP384,
tls.CurveP521,
tls.X25519,
},
}

Creating and Running the Web Server

Using the TLS configuration above, let’s create an HTTP server that responds with the connection curve preference and cipher suite.

// Create a new TLS configuration
cfg := &tls.Config{
MaxVersion: tls.VersionTLS13,
CurvePreferences: []tls.CurveID{},
}

// Create a new HTTP server mux
mux := http.NewServeMux()
mux.HandleFunc("/", handler)

// Set an HTTP server instance with configuration with the TLS configuration
srv := &http.Server{
Addr: ":443",
Handler: mux,
TLSConfig: cfg,
}

// Start the server
fmt.Printf("Starting server on %s\n", srv.Addr)
log.Fatal(srv.ListenAndServeTLS(certFileName, keyFileName))

The full code examples are published here.

Running Different Clients vs the Server We Created

Cloudflare reports which web clients support post-quantum cryptography. Among them, we can find modern browsers (Chrome, Edge, Firefox, Opera) and libraries such as BoringSSL. We used a Chrome browser and a cURL client browser for our tests.

Invoking a Request to the Server Using the Chrome Browser

Running Chrome vs this server using the address https://localhost:443 results in an exciting post-quantum algorithm X25519Kyber768Draft00 usage. The server output contains a cipher suite and the selected curve mentioned below. As the server certificate was self-signed, I needed to dismiss Chrome warnings.

If you want to dive deep into the curve selection flow, jump here.

Here are the results returned from the server while using Chrome:

This is an example server.
TLS Connection: Curve ID: 0x6399, Name: X25519Kyber768Draft00
TLS Connection: Cipher Suite: 0x4865 , Name:TLS_AES_128_GCM_SHA256

Invoking a Request to the Server Using cURL

The cURL command application I’m using (curl 8.7.1), does not support the Hybrid Kyber Algorithm.

Running this command to invoke a request to the server:

curl -insecure https://localhost:443

Results in:

This is an example server.
TLS Connection: Curve ID: 0x1d, Name: X25519
TLS Connection: Cipher Suite: 0x4867 , Name:TLS_CHACHA20_POLY1305_SHA256

As you can see, the selected curve is X25519 which is not considered quantum safe.

Note: I added the flag –insecure, to avoid the self-signed certificate warnings.

Extracting the TLS Connection Curve ID

Accessing the curve ID of a TLS connection is not straightforward, as it’s stored in a private field.

Here’s how to extract it using Go reflection:

// getRequestCurveID returns the curve ID of the request
func getRequestCurveID(r *http.Request) tls.CurveID {
if r.TLS == nil {
return 0 // Not a TLS connection
}

// Access the private 'testingOnlyCurveID' field using reflection
connState := reflect.ValueOf(*r.TLS)
curveIDField := connState.FieldByName("testingOnlyCurveID")

if !curveIDField.IsValid() {
return 0 // Field not found
}

// Convert the reflected value to tls.CurveID
return tls.CurveID(curveIDField.Uint())
}// getRequestCurveID returns the curve ID of the request

The Need For Go 1.23 and Post-Quantum Cryptography

Go 1.23 introduces support for post-quantum algorithms, specifically the X25519Kyber768Draft00 hybrid key exchange. This allows developers to improve their applications’ security against potential quantum computing threats.

These improvements include:

  1. Minimal Code Changes: Developers need only minor adjustments to their TLS configurations:
    • Ensure TLS 1.3 support
    • Avoid explicitly defining curve preferences
  2. Automatic Negotiation: Leaving CurvePreferences undefined allows Go to negotiate the most secure options, including the new post-quantum algorithm when supported.
  3. Backward Compatibility: The implementation maintains compatibility with existing systems while enhancing security for supported connections.
  4. Future-Proofing: This update protects against potential “harvest now, decrypt later” attacks from future quantum capabilities.
  5. Community Contributions: This advancement results from collaborative efforts, notably from the Go team, Filippo Valsorda, and Bas Westerbaan from the Cloudflare team.

Based on this information, I recommend developers update to Go 1.23 and adjust their TLS configurations to leverage this post-quantum capability.

If you are interested in the role of Cryptography in Go, I discussed it with Shay Nehmad, Jonathan Hall, and Ran Bar-Zik at the Cup O’ Go podcast:

--

--

Gil Adda
CyberArk Engineering

System Architect at Cyberark. Technologies and Engineering of big things are amazing