In sintesi: WireGuard non usa TLS e non prevede una negoziazione multi-round-trip come OpenVPN o IPsec/IKEv2. Adotta un handshake crittografico fisso e opinionato, derivato dal Noise Protocol Framework — nello specifico il pattern Noise_IK — che si completa in esattamente due messaggi. Entrambi i peer conoscono in anticipo le rispettive chiavi pubbliche a lungo termine (configurate staticamente, come le chiavi SSH), quindi il compito dell'handshake non è scoprire le identità, ma dimostrare reciprocamente il possesso delle chiavi private corrispondenti e derivare nuove chiavi di sessione simmetriche con forward secrecy. L'intera transazione è abbastanza piccola da stare in due datagrammi UDP da poche centinaia di byte ciascuno. Si completa più velocemente di un tipico handshake TLS, e le chiavi di sessione risultanti ruotano ogni due minuti per tutta la durata della connessione.
Perché esiste un handshake
Due computer vogliono comunicare in modo privato su una rete che non controllano. Il problema crittografico fondamentale: prima di poter cifrare qualsiasi cosa, devono concordare un segreto condiviso che un attaccante che osserva la rete non possa derivare. Devono anche verificare l'identità reciproca — altrimenti un attaccante potrebbe impersonare l'altro lato e indurre uno dei peer a cifrare i dati verso di lui.
Un handshake risolve entrambi i problemi in uno scambio strutturato:
- Autenticazione reciproca — ogni peer dimostra il possesso di una chiave privata corrispondente a una chiave pubblica già fidata dall'altro lato. Nessun peer trasmette mai la chiave privata in sé; dimostra semplicemente di possederla eseguendo operazioni crittografiche che solo quella chiave può produrre.
- Accordo su chiave con forward secrecy — entrambi i peer generano coppie di chiavi nuove e temporanee («effimere») per questa sessione specifica, si scambiano le metà pubbliche e le combinano con le chiavi a lungo termine per derivare una chiave di sessione simmetrica. Le chiavi effimere vengono scartate dopo l'handshake; anche se le chiavi a lungo termine venissero rubate in seguito, le chiavi di sessione passate non potrebbero essere ricostruite da esse. Questa proprietà si chiama forward secrecy ed è il motivo per cui il traffico passato rimane protetto anche in caso di compromissione futura delle chiavi.
- Configurazione della protezione anti-replay — entrambi i peer inizializzano contatori e nonce che impediscono a un attaccante di catturare e riprodurre traffico precedente.
I diversi protocolli VPN implementano questo meccanismo in modo diverso. OpenVPN lo fa tramite TLS, con più round-trip, validazione dei certificati e numerose cipher suite configurabili. IPsec/IKEv2 ha il proprio protocollo di negoziazione con complessità simile. WireGuard lo fa in due pacchetti, senza configurabilità, senza negoziazione di cipher suite — ogni handshake WireGuard usa lo stesso insieme fisso di primitive crittografiche. Il compromesso è intenzionale: meno complessità significa meno superficie d'attacco e maggiore auditabilità, al costo di zero agilità a livello di protocollo.
Il framework Noise — cos'è e perché WireGuard usa Noise_IK
Il Noise Protocol Framework è una specifica per la costruzione di handshake crittografici. È opera di Trevor Perrin, che ha anche progettato il Signal Protocol alla base di Signal, WhatsApp e la maggior parte dei moderni messenger con cifratura end-to-end. Noise non è un singolo protocollo — è un kit di componenti («pattern» di handshake, primitive crittografiche, regole di derivazione) che consente a un progettista di protocolli di scegliere esattamente la forma di handshake necessaria e di ottenere una specifica precisa di ciò che i messaggi contengono e delle garanzie che forniscono.
I pattern di handshake Noise sono denominati con due lettere che indicano cosa ciascun lato conosce in anticipo:
- N — nessuna chiave statica per quel lato; vengono usate solo chiavi effimere. Anonimo.
- K — la chiave statica è «nota» all'altra parte in anticipo.
- X — la chiave statica viene inviata durante l'handshake.
- I — la chiave statica viene trasmessa «immediatamente» nel primo messaggio.
Noise_IK significa: l'initiator invia la propria chiave statica Immediatamente (nel primo messaggio), e la chiave statica del responder è Nota all'initiator in anticipo. Questo pattern è ideale per il caso d'uso di WireGuard perché entrambi i peer conoscono davvero le chiavi statiche dell'altro in anticipo — sono configurate nel file di configurazione WireGuard. La scelta «IK» consente all'intero handshake di completarsi in due messaggi, che è il minimo possibile per uno scambio di chiavi mutualmente autenticato con forward secrecy.
La specifica completa del framework Noise è pubblicata su noiseprotocol.org ed è uno dei pezzi più raffinati di ingegneria crittografica pubblica — scritto per essere auditabile, con verifica formale degli stessi pattern. L'adozione di Noise_IK da parte di WireGuard è stata una scelta progettuale deliberata per ereditare l'analisi del framework.
Pacchetto 1: Initiator → Responder
L'handshake inizia quando l'initiator (il tuo telefono, il tuo laptop, il lato client) decide di comunicare con il responder (il server VPN). Ciò avviene perché c'è traffico in coda in attesa del tunnel, oppure perché la chiave di sessione è scaduta ed è necessario un rekey. L'initiator costruisce un singolo pacchetto UDP contenente:
- Indice mittente — un intero a 32 bit scelto casualmente che identifica questa sessione di handshake. Usato per disambiguare handshake concorrenti tra gli stessi peer.
- Chiave pubblica effimera — una chiave pubblica Curve25519 appena generata. La chiave privata corrispondente è tenuta in memoria dall'initiator. Questa è la «E» nel pattern Noise — la nuova chiave effimera introdotta.
- Chiave pubblica statica (cifrata) — la chiave pubblica Curve25519 a lungo termine dell'initiator, cifrata con una chiave derivata dallo scambio effimero. Questa è parte della «I» in IK — la chiave statica dell'initiator viene inviata nel primo messaggio, ma è protetta dagli osservatori passivi.
- Timestamp (cifrato) — un timestamp in formato TAI64N, cifrato. Questo è l'ancoraggio per la protezione anti-replay: il responder rifiuterà qualsiasi handshake con un timestamp precedente a uno già accettato da questo peer. Impedisce a un attaccante di catturare e riprodurre un messaggio di handshake valido in seguito.
- Campi MAC — due brevi autenticatori (mac1, mac2) che provano che il mittente conosce la chiave pubblica del responder. Il campo mac2 viene anche usato per il meccanismo di mitigazione DoS cookie-reply descritto nel whitepaper di WireGuard.
Cosa dimostra e ottiene questo pacchetto: includendo una nuova chiave effimera, l'initiator si impegna su metà della chiave di sessione finale. Includendo il timestamp e il MAC legato alla chiave statica del responder, l'initiator dimostra «possiedo almeno la chiave pubblica del responder» — il che significa che un attaccante casuale off-path non può inviare banalmente initiation di handshake false sprecando risorse del server. L'intero pacchetto è di 148 byte, si inserisce comodamente in un singolo datagramma UDP e non viene mai frammentato.
Vale la pena notare una sottigliezza: la chiave pubblica statica dell'initiator è inclusa ma cifrata, quindi un osservatore passivo che monitora la rete non può identificare quale client si sta connettendo. Può vedere che qualcuno sta avviando un handshake WireGuard verso questo server, ma non chi. Questa è una proprietà di privacy chiamata nascondimento dell'identità dell'initiator, ed è più forte di quanto TLS fornisca di default.
Pacchetto 2: Responder → Initiator
Il responder riceve il pacchetto di iniziazione, decifra la chiave pubblica statica dell'initiator e la cerca nella propria tabella dei peer. Se il peer è noto e il timestamp è accettabile (più recente dell'ultimo accettato), il responder genera la propria coppia di chiavi effimere e costruisce un pacchetto di risposta:
- Indice mittente — l'identificatore a 32 bit scelto dal responder per questa sessione.
- Indice destinatario — restituito dall'initiator, così entrambi i lati concordano su quale sessione si tratta.
- Chiave pubblica effimera — la chiave pubblica effimera appena generata dal responder.
- Payload cifrato vuoto — un testo cifrato autenticato ma vuoto che dimostra che il responder può derivare la chiave di sessione. Questo è il segnale crittografico «ho letto il tuo messaggio e calcolato la chiave corretta».
- Campi MAC — stesso schema del pacchetto di iniziazione.
Quando l'initiator riceve questa risposta, esegue la derivazione della chiave corrispondente, verifica che il payload cifrato vuoto autenticato si decifri correttamente con la chiave derivata, e ora entrambi i lati sono arrivati alla stessa chiave di sessione simmetrica — indipendentemente, senza che quella chiave abbia mai attraversato la rete. La chiave di sessione ha perfect forward secrecy perché dipende da entrambe le chiavi effimere (che stanno per essere distrutte) e da entrambe le chiavi statiche.
Il pacchetto di risposta è di 92 byte. L'handshake totale — entrambi i pacchetti combinati — è di 240 byte più le intestazioni IP/UDP, si inserisce in due scambi UDP andata-ritorno che si completano in circa un RTT di rete (un pacchetto per direzione), e produce una sessione completamente autenticata con forward secrecy pronta a cifrare il traffico applicativo. Non c'è validazione di catena di certificati, nessuna negoziazione di cipher suite, nessun confronto di versioni, nessuna lista di estensioni — niente di ciò che rende complicati gli handshake TLS.
La sessione che segue
Una volta completato l'handshake, i due peer si scambiano pacchetti dati in un formato molto più semplice. Ogni pacchetto dati contiene:
- Indice destinatario — l'ID di sessione a 32 bit assegnato dal destinatario durante l'handshake.
- Contatore — un nonce a 64 bit che si incrementa con ogni pacchetto inviato. Usato sia come nonce AEAD che per il rilevamento di replay.
- Payload cifrato — il pacchetto IP originale, cifrato con ChaCha20-Poly1305 usando la chiave di sessione e il contatore come nonce.
ChaCha20-Poly1305 è una costruzione AEAD (Authenticated Encryption with Associated Data): cifra il payload e produce un tag di autenticazione che rileva qualsiasi manomissione. Se anche un solo bit del testo cifrato viene modificato, la decifratura fallisce e il destinatario scarta il pacchetto. Non c'è una modalità di errore «soft» — i pacchetti modificati vengono silenziosamente scartati, proprio come i pacchetti con contatore errato o indice destinatario errato.
Il destinatario mantiene una finestra scorrevole di valori di contatore accettati. I pacchetti con contatori che rientrano nella finestra e non sono stati ancora visti vengono accettati; i pacchetti che cadono sotto la finestra (troppo vecchi) o che sono già stati visti vengono rifiutati. Ciò fornisce protezione anti-replay senza richiedere al destinatario di ricordare ogni contatore mai visto — solo i più recenti, in una piccola bitmap.
Dal punto di vista della rete, i pacchetti dati sembrano identici indipendentemente dal contenuto del payload. Sono tutti pacchetti UDP verso lo stesso IP e porta del server, con dimensioni simili (il payload cifrato preserva la dimensione del pacchetto IP sottostante più 32 byte di overhead), e nessun pattern osservabile che li distingua. Non c'è SNI, nessuno scambio di certificati, nessuna struttura handshake-TLS-poi-dati — solo UDP opaco dopo il handshake iniziale di due pacchetti.
Comportamento di rekey — ogni 2 minuti O ogni 2^60 pacchetti
WireGuard ruota le chiavi di sessione in modo aggressivo. La politica di rekey predefinita: un nuovo handshake viene avviato quando la sessione corrente è stata attiva per 2 minuti o ha trasmesso 2^60 pacchetti, a seconda di quale condizione si verifica prima. In pratica, è il limite temporale a innescare il rekey per la maggior parte delle sessioni — 2^60 pacchetti è un numero astronomicamente grande che nessuna connessione reale raggiunge mai.
Perché 2 minuti? Due motivi. Primo, il rekey frequente migliora la forward secrecy. Ogni sessione è cifrata con una chiave derivata da una specifica coppia di chiavi effimere. Più breve è la sessione, meno dati fluiscono attraverso una singola chiave, quindi anche ipotetici futuri attacchi crittoanalitici dovrebbero compromettere molte chiavi per leggere una quantità significativa di traffico. Secondo, il rekey è invisibile all'applicazione — il nuovo handshake avviene in background mentre le vecchie chiavi di sessione continuano a cifrare i dati, e il passaggio è trasparente. Entrambi i peer mantengono una piccola finestra di sovrapposizione in cui accettano pacchetti cifrati con la chiave vecchia o nuova.
Il rekey viene avviato dal peer che nota per primo la scadenza del timer — di solito il lato initiator. Il messaggio del protocollo è lo stesso handshake in due pacchetti descritto sopra. Dal punto di vista di un osservatore esterno, si vede un piccolo flusso di pacchetti UDP aggiuntivi ogni due minuti, ma nessun cambiamento osservabile nel flusso dati stesso.
Le fasi dell'handshake in sintesi
L'handshake completo, suddiviso per fase, pacchetto e primitiva crittografica utilizzata:
| Fase | Pacchetto | Cosa viene trasmesso | Primitiva crittografica |
|---|---|---|---|
| 1. Iniziazione | Initiator → Responder (148 byte) | Indice mittente, chiave pubblica effimera, chiave statica cifrata, timestamp cifrato, MAC | Curve25519 (ECDH), BLAKE2s (hash/MAC), ChaCha20-Poly1305 (AEAD), HKDF (derivazione chiavi) |
| 2. Risposta | Responder → Initiator (92 byte) | Indice mittente, indice destinatario, chiave pubblica effimera, payload cifrato vuoto (conferma chiave), MAC | Curve25519 (ECDH), BLAKE2s, ChaCha20-Poly1305, HKDF |
| 3. Sessione dati | Entrambe le direzioni, indefinitamente (32 byte di overhead per pacchetto) | Indice destinatario, contatore, pacchetto IP cifrato | ChaCha20-Poly1305 (AEAD) |
| 4. Rekey (ogni 2 min) | Stesso scambio in due pacchetti delle fasi 1+2 | Nuove chiavi effimere, derivazione nuova chiave di sessione | Stesse primitive |
Vengono utilizzate cinque primitive crittografiche, nessuna negoziabile: Curve25519 per l'accordo su chiave Diffie-Hellman su curva ellittica, ChaCha20 per la cifratura a stream simmetrica, Poly1305 per il tag di autenticazione, BLAKE2s per la funzione hash e MAC, e HKDF per la derivazione delle chiavi. Questa è la scelta progettuale «senza agilità»: codificando le primitive, la superficie del protocollo si riduce drasticamente e l'analisi diventa molto più trattabile. Il costo è che se una qualsiasi primitiva venisse compromessa, l'intero protocollo richiederebbe una nuova versione — non esiste un modo in-band per aggiornarla. La scommessa che fa WireGuard è che queste primitive sono sufficientemente ben studiate da rendere improbabile una rottura improvvisa.
Cosa può andare storto
Gli handshake crittografici hanno modalità di errore note. Alcune si applicano a WireGuard; altre no. Vale la pena capirle:
Attacchi replay
Il timestamp cifrato nel pacchetto di iniziazione previene i replay. Se un attaccante cattura un pacchetto di iniziazione valido e tenta di riprodurlo in seguito, il responder vede un timestamp che ha già accettato (o uno più vecchio dell'ultimo accettato) e rifiuta il pacchetto. Questo è uno dei motivi per cui WireGuard mantiene per ogni peer lo stato relativo all'ultimo timestamp di handshake — il protocollo ne dipende.
Compromissione della chiave a lungo termine
Se un attaccante ruba la chiave privata a lungo termine di un peer, può impersonare quel peer negli handshake futuri. Non può, tuttavia, decifrare le sessioni passate — le chiavi effimere che hanno derivato quelle chiavi di sessione sono state distrutte dopo ogni handshake. Questa è la garanzia di forward secrecy. La mitigazione per il rischio in corso è ruotare la chiave a lungo termine (generare una nuova coppia, distribuire la nuova chiave pubblica ai peer) — non esiste un meccanismo a livello di protocollo per invalidare una chiave vecchia, quindi questo deve essere fatto out-of-band.
Timeout NAT e morte silenziosa della connessione
WireGuard funziona su UDP, che è senza connessione. I network address translator (nel router di casa o nella rete del provider) a volte eliminano le voci di flusso UDP dopo alcuni minuti di inattività. Quando ciò accade, i pacchetti di risposta del responder non riescono più a raggiungere l'initiator — il NAT ha dimenticato la mappatura. La mitigazione è l'impostazione keepalive (spesso impostata a 25 secondi), che invia un piccolo pacchetto heartbeat dall'initiator al responder per mantenere viva la mappatura NAT. Senza keepalive, le connessioni idle possono morire silenziosamente e richiedono un nuovo handshake per ripristinarsi.
Denial-of-service tramite flood di handshake
Un responder sotto attacco pesante potrebbe ricevere molte initiation di handshake false, ognuna delle quali richiede operazioni Curve25519 per essere elaborata. WireGuard mitiga questo con il meccanismo cookie-reply: quando il responder è sotto carico, può richiedere all'initiator di eseguire un piccolo calcolo simile a un proof-of-work prima che il responder si impegni in un handshake completo. Il campo mac2 nei pacchetti di handshake porta questo meccanismo. La resistenza al DoS non è perfetta — nessun protocollo può esserlo — ma è sostanzialmente più difficile da saturare rispetto a, ad esempio, un servizio basato su TCP non autenticato.
Perché questo è importante per gli utenti VPN, in pratica
L'architettura dell'handshake ha vantaggi concreti visibili all'utente rispetto ai protocolli VPN più vecchi:
- Nessun handshake TLS lato client — WireGuard non valida certificati, non si concatena a una CA, non dipende dal trust store di sistema. Questo elimina un'intera classe di attacchi (CA compromesse, certificati emessi erroneamente) che colpiscono le VPN basate su TLS.
- Nessuna connessione stateful — il protocollo gira su UDP ed è senza connessione. Non c'è una macchina a stati stile TCP da rompere quando la rete cambia. Un dispositivo in roaming che passa da Wi-Fi a rete cellulare non deve ristabilire nulla; inizia semplicemente a inviare pacchetti dal nuovo indirizzo IP e il responder li accetta.
- Roaming istantaneo — poiché la connessione è identificata dalle chiavi crittografiche anziché dall'indirizzo IP sorgente, il responder accetterà pacchetti da qualsiasi IP sorgente che produca l'autenticazione crittografica corretta. Questo è il motivo per cui WireGuard gestisce le transizioni di rete mobile molto meglio di OpenVPN o IPsec, che spesso devono rinegoziare quando l'IP sottostante cambia.
- Superficie d'attacco minima — l'implementazione di riferimento è di circa 4.000 righe di codice. OpenSSL supera le 500.000. Non è un confronto equo (svolgono quantità di lavoro diverse), ma l'implicazione è reale: codice più piccolo è più facile da auditare, più facile da analizzare formalmente, e presenta meno opportunità per bug di implementazione che si trasformano in vulnerabilità.
- Prestazioni prevedibili — ogni handshake usa le stesse primitive con le stesse dimensioni di chiave. Non c'è divergenza fast-path/slow-path basata sulla cipher suite negoziata. L'handshake richiede all'incirca lo stesso tempo sullo stesso hardware indipendentemente da chi ci si connette.
Per il confronto dei compromessi con il protocollo più vecchio che ha sostituito per la maggior parte degli utenti, vedi il nostro articolo su WireGuard vs OpenVPN, che copre le differenze pratiche di prestazioni e sicurezza. Per capire perché le scelte di tunneling di una VPN influenzano ciò che le app vedono, vedi cos'è lo split tunneling.
Casper's Cloak usa WireGuard per tutte le connessioni client, esegue l'implementazione ufficiale in modalità kernel sugli endpoint Linux, e distribuisce il client userspace standard (costruito sul riferimento wireguard-go) su iOS, Android e macOS. L'handshake descritto sopra è esattamente ciò che accade quando accendi l'app. Lo stesso pattern Noise_IK, lo stesso insieme di primitive Curve25519/ChaCha20-Poly1305/BLAKE2s/HKDF, lo stesso rekey di 2 minuti, lo stesso handshake di 240 byte. La funzionalità di protezione dalle minacce aggiunge un filtraggio a livello DNS sopra il tunnel WireGuard — il tunnel gestisce il trasporto, il filtro gestisce la policy di destinazione.
Per la specifica completa del protocollo, il whitepaper originale di WireGuard di Jason Donenfeld è il riferimento autorevole: wireguard.com/papers/wireguard.pdf. Il paper copre la costruzione crittografica, il modello di minaccia, l'analisi formale e la logica implementativa. È uno dei testi più leggibili di moderna progettazione di protocolli — vale l'ora di scorrerlo se vuoi capire i compromessi progettuali alla fonte.
In sintesi: l'handshake WireGuard consiste in due pacchetti, impiega meno di 100 millisecondi in pratica, autentica reciprocamente entrambi i peer, deriva chiavi di sessione con forward secrecy e resiste a ogni schema di attacco comune (replay, downgrade, divulgazione dell'identità, DoS) by design. È un protocollo stretto, fisso e opinionato, e quella opinionatezza è esattamente il punto.