Vai al contenuto principale
Security

TLS 1.3 + Post-Quantum: Scambio di Chiavi Ibrido ML-KEM (Kyber) nel Mondo Reale

7 min lettura
LD
Lucio Durán
Engineering Manager & AI Solutions Architect
Disponibile anche in: English, Español

Il Modello di Minaccia: Perché Non Possiamo Aspettare

L'argomento per la crittografia post-quantistica non è più speculativo. È matematica del rischio diretta:

  1. I dati cifrati transitano su internet
  2. Gli avversari registrano quel traffico cifrato (lo storage economico lo rende banale)
  3. Un computer quantistico crittograficamente rilevante (CRQC) appare eventualmente
  4. Tutto il traffico registrato cifrato con scambio chiavi classico diventa leggibile

Questo è l'attacco "harvest now, decrypt later" (HNDL). I dati che stai proteggendo con TLS oggi potrebbero dover rimanere confidenziali per 10, 20 o 30 anni. Se un CRQC appare entro quella finestra, il tuo scambio chiavi classico non è servito a nulla.

Il calcolo dell'urgenza: se i tuoi dati necessitano N anni di confidenzialità, e stimi T anni fino a un CRQC, e ci vogliono M anni per migrare la tua infrastruttura, devi iniziare quando N + M > T. Per la maggior parte delle organizzazioni con dati sensibili, quella disuguaglianza è già vera.

ML-KEM: Cosa Ha Realmente Standardizzato il NIST

FIPS 203, pubblicato ad agosto 2024, ha standardizzato ML-KEM in tre set di parametri:

| Set Parametri | Livello Sicurezza | Chiave Pubblica | Ciphertext | Segreto Condiviso | |---------------|-------------------|-----------------|------------|-------------------| | ML-KEM-512 | NIST Livello 1 | 800 byte | 768 byte | 32 byte | | ML-KEM-768 | NIST Livello 3 | 1.184 byte | 1.088 byte | 32 byte | | ML-KEM-1024 | NIST Livello 5 | 1.568 byte | 1.568 byte | 32 byte |

ML-KEM-768 è il punto ottimale che tutti stanno deployando. Sicurezza livello 3 (approssimativamente equivalente ad AES-192), dimensioni chiave ragionevoli, ed è quello che sia Chrome che Firefox hanno scelto per la loro implementazione ibrida.

L'Approccio Ibrido: X25519Kyber768

Nessuno sta deployando ML-KEM da solo. L'intera industria ha converguto su un approccio ibrido dove combini uno scambio chiavi classico con uno post-quantistico. Il segreto condiviso è derivato da entrambi, così mantieni la sicurezza anche se uno dei due algoritmi risulta avere una debolezza inaspettata.

Ecco come appare l'handshake TLS 1.3 con X25519Kyber768Draft00:

Client Server

ClientHello
 + key_share: {
 X25519Kyber768Draft00: x25519_pub || mlkem768_encaps_key,
 X25519: x25519_pub_fallback
 }
 + supported_groups: [X25519Kyber768Draft00, X25519, ...]
 + signature_algorithms: [ecdsa_secp256r1_sha256, ...]
 -------->

 ServerHello
 + key_share: {
 X25519Kyber768Draft00:
 x25519_server_pub || mlkem768_ciphertext
 }
 {EncryptedExtensions}
 {Certificate}
 {CertificateVerify}
 {Finished}
 <--------

{Finished}
 -------->

[Application Data] <-------> [Application Data]

Computazione del segreto condiviso combinato:

def derive_hybrid_secret(x25519_shared, mlkem_shared):
 combined = x25519_shared + mlkem_shared # 32 + 32 = 64 byte

 early_secret = HKDF_Extract(salt=0, ikm=PSK or 0)
 handshake_secret = HKDF_Extract(
 salt=Derive_Secret(early_secret, "derived", ""),
 ikm=combined # <-- Entrambi i segreti contribuiscono qui
 )
 return handshake_secret

La proprietà critica: se ML-KEM viene rotto da un attacco classico che non avevamo anticipato, X25519 ti protegge ancora. Se X25519 viene rotto da un computer quantistico, ML-KEM ti protegge ancora. Servono entrambi i fallimenti simultaneamente perché l'handshake venga compromesso.

Implementazione in Chrome

Un'analisi dell'implementazione BoringSSL di Chromium rivela il flusso reale:

// Da ssl/extensions/ext_key_share.cc (semplificato)
static bool ext_key_share_add_clienthello(
 const SSL_HANDSHAKE *hs, CBB *out) {

 // Lista gruppi preferiti, provati in ordine:
 // 1. X25519Kyber768Draft00 (PQ ibrido)
 // 2. X25519 (fallback classico)

 for (uint16_t group_id : hs->config->supported_group_list) {
 CBB key_exchange;
 if (group_id == SSL_GROUP_X25519_KYBER768_DRAFT00) {
 uint8_t x25519_public[32], x25519_private[32];
 X25519_keypair(x25519_public, x25519_private);

 uint8_t mlkem_encaps_key[MLKEM768_PUBLIC_KEY_BYTES];
 uint8_t mlkem_decaps_key[MLKEM768_SECRET_KEY_BYTES];
 MLKEM768_generate_key(mlkem_encaps_key, mlkem_decaps_key);

 CBB_add_bytes(&key_exchange, x25519_public, 32);
 CBB_add_bytes(&key_exchange, mlkem_encaps_key,
 MLKEM768_PUBLIC_KEY_BYTES);
 }
 }
}

L'aumento dimensionale del ClientHello è significativo. Un'entry key_share solo X25519 è 32 byte. Con il gruppo ibrido, è 32 + 1184 = 1216 byte. Aggiungi padding e estensioni, e il tuo ClientHello si gonfia da ~250 byte a ~1400+ byte.

Il Problema dei Middlebox

Qui la teoria incontra la realtà brutale di internet. Ecco i problemi più comuni riscontrati in pratica:

Segmentazione TCP

Molti ClientHello TLS stanno in un singolo segmento TCP (MSS ~1460 byte sulla maggior parte delle reti). Il ClientHello post-quantistico ingrandito a volte richiede due segmenti. Alcuni middlebox — firewall, motori DPI, load balancer — riassemblano i record TLS ma assumono che inizino e finiscano in un singolo segmento TCP.

Prima (classico):
[Segmento TCP 1: header IP + header TCP + ClientHello completo (250 byte)]

Dopo (PQ ibrido):
[Segmento TCP 1: header IP + header TCP + ClientHello parte 1 (1400 byte)]
[Segmento TCP 2: ClientHello parte 2 (byte rimanenti)]

La soluzione a livello applicazione è TCP_NODELAY + assicurarsi che la tua libreria TLS invii il ClientHello completo prima di aspettare una risposta. A livello infrastruttura, devi auditare ogni middlebox nel percorso.

Implicazioni Certificate Transparency

Il post-quantum non cambia i certificati ancora, ma cambia come pensi alla CT. Il deployment attuale usa ML-KEM solo per lo scambio chiavi — l'autenticazione usa ancora firme classiche ECDSA o RSA.

Tuttavia, le firme post-quantistiche arrivano per i certificati. ML-DSA (FIPS 204) è standardizzato. Il problema? Le firme ML-DSA-65 sono 3.309 byte (vs 72 byte per ECDSA P-256). Una catena di certificati con tre certificati ML-DSA aggiunge ~10KB all'handshake.

Dimensione catena certificati attuale (ECDSA):
 Firma cert foglia: 72 byte
 Firma cert intermedio: 72 byte
 Firma cert root: 72 byte
 Totale firme: ~216 byte

Catena certificati futura (ML-DSA-65):
 Firma cert foglia: 3.309 byte
 Firma cert intermedio: 3.309 byte
 Firma cert root: 3.309 byte
 Totale firme: ~9.927 byte

Guida Pratica al Deployment

Ecco come configurare nginx con scambio chiavi post-quantistico:

# nginx.conf - richiede OpenSSL 3.2+ con oqs-provider
ssl_protocols TLSv1.3;
ssl_ecdh_curve X25519Kyber768Draft00:X25519:secp256r1;
ssl_prefer_server_ciphers off;

Per applicazioni Node.js dietro il reverse proxy:

import { createServer } from 'https';
import { readFileSync } from 'fs';

const server = createServer({
 key: readFileSync('/etc/ssl/private/server.key'),
 cert: readFileSync('/etc/ssl/certs/server.crt'),
 ecdhCurve: 'X25519Kyber768Draft00:X25519',
 minVersion: 'TLSv1.3'
});

Verifica:

openssl s_client -connect iltuodominio.com:443 \
 -groups X25519Kyber768Draft00 \
 -tls1_3 2>&1 | grep "Server Temp Key"
# Output atteso:
# Server Temp Key: X25519Kyber768Draft00, 1216 bits

Performance: Numeri Reali

Benchmark dell'overhead su un setup production-class (nginx, 64 core AMD EPYC, 10Gbps):

| Metrica | Solo X25519 | X25519Kyber768 | Overhead | |---------|------------|----------------|----------| | Latenza handshake (p50) | 1,2ms | 1,4ms | +16% | | Latenza handshake (p99) | 3,1ms | 3,8ms | +22% | | Dimensione ClientHello | 253 byte | 1.438 byte | +468% | | Dimensione ServerHello | 105 byte | 1.193 byte | +1036% | | CPU per handshake | 0,08ms | 0,12ms | +50% | | Handshake/sec (1 core) | 12.500 | 8.333 | -33% |

L'overhead di latenza è trascurabile per la maggior parte delle applicazioni. L'overhead CPU conta su scala ma è gestibile. Il vero problema è la larghezza di banda — quegli handshake più grandi si accumulano quando fai milioni di nuove connessioni al secondo.

Azioni Raccomandate

  1. Abilita PQ ibrido sul tuo edge se il tuo reverse proxy lo supporta. Cloudflare e AWS CloudFront lo hanno già abilitato di default.
  2. Audita i tuoi middlebox per la tolleranza alla dimensione del ClientHello.
  3. Monitora i tuoi log CT per certificati nel tuo dominio che usino tipi di chiave inaspettati.
  4. Non aspettare le firme post-quantistiche. Lo scambio chiavi è il pezzo urgente. Inizia da lì.
  5. Testa con browser reali. Chrome 124+ e Firefox 128+ supportano X25519Kyber768Draft00.

La transizione post-quantistica non è un problema futuro. Chrome sta già negoziando Kyber ibrido con ogni server che lo supporta. Se il tuo server non lo offre, il traffico dei tuoi utenti si sta accumulando nello storage di qualche avversario, aspettando il giorno in cui un computer quantistico potrà leggerlo. La risposta è adesso.

tlspost-quantumkyberml-kemcrittografiax25519certificate-transparency

Strumenti menzionati in questo articolo

CloudflareProva Cloudflare
AWSProva AWS
Divulgazione: Alcuni link in questo articolo sono link di affiliazione. Se ti registri tramite questi, potrei guadagnare una commissione senza costi aggiuntivi per te. Raccomando solo strumenti che uso e di cui mi fido personalmente.
Compartir
Seguime