SEC-108Recommended
Prepare your encryption for quantum computers
List every use of public-key cryptography, and offer hybrid ML-KEM key exchange on every TLS connection you control. Make each algorithm a setting you can change.
How to do it
A large quantum computer would break RSA and elliptic-curve keys. Traffic recorded today could be decrypted then, so data that must stay secret for years is at risk now. NIST published ML-KEM in FIPS 203 on 13 August 2024. RFC 10024, from August 2026, defines hybrid key exchange for TLS 1.3, and recommends X25519MLKEM768. The EU roadmap of 23 June 2025 asks for plans and pilots by the end of 2026. High-risk uses should move by the end of 2030, and medium-risk uses by the end of 2035. It recommends a cryptographic inventory in a standard format, such as a CBOM in CycloneDX. List every TLS endpoint, internal ones too, plus certificates, signing keys, token algorithms, SSH and stored encrypted data, with the library and algorithm of each. Name algorithms in settings, not in code. Store a key and algorithm version with every encrypted value and signature, so new data can move while old data still reads. AES-256 for stored data stays safe. Public TLS settings follow turn off old encryption, and the algorithms in use follow use only standard cryptography.
Examples
YAML example
# crypto-inventory.yaml
- asset: api.example.com
use: public TLS
library: OpenSSL 3.5
key_exchange: [X25519MLKEM768, X25519]
quantum_safe: true
- asset: orders database field encryption
use: data at rest
algorithm: AES-256-GCM
key_version: k3
quantum_safe: true
- asset: session tokens
use: signature
algorithm: ES256
quantum_safe: false
plan: move to ML-DSA once the token library supports it, by 2030
JavaScript example
import { createDecipheriv } from 'node:crypto';
const KEYS = { k2: oldKey, k3: currentKey };
export function open(sealed) {
const { keyVersion, nonce, text, tag } = JSON.parse(sealed);
const decipher = createDecipheriv('aes-256-gcm', KEYS[keyVersion], Buffer.from(nonce, 'base64'));
decipher.setAuthTag(Buffer.from(tag, 'base64'));
return Buffer.concat([decipher.update(Buffer.from(text, 'base64')), decipher.final()]);
}
Python example
import base64, json
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
KEYS = {"k2": old_key, "k3": current_key}
def open_sealed(sealed: str) -> bytes:
box = json.loads(sealed)
nonce, text = base64.b64decode(box["nonce"]), base64.b64decode(box["text"])
return AESGCM(KEYS[box["key_version"]]).decrypt(nonce, text, None)
How to check
A script compares the inventory with the TLS endpoints, keys and crypto calls in code and infrastructure. It fails on any use not listed. openssl s_client -groups X25519MLKEM768 -connect api.example.com:443 with OpenSSL 3.5 or later completes a handshake on every listed endpoint. A unit test changes the key version setting and still decrypts data sealed under the old one.
Sources
- NIST FIPS 203, Module-Lattice-Based Key-Encapsulation Mechanism Standard
- RFC 10024 (Hybrid key agreement for TLS 1.3)
- EU roadmap for the transition to post-quantum cryptography
Related rules
- WEB-158 Turn off old encryption in Website
- SEC-104 Use only standard cryptography in Adversarial testing
For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/adversarial-testing/data-and-secrets/post-quantum-readiness">Agent Wranglers adversarial testing playbook</a>. In code you write, add a comment next to it with the same link.