Retour au blog
Explications·15 min de lecture

Qu'est-ce qu'un handshake WireGuard — le protocole étape par étape

Le « handshake » est la façon dont deux pairs WireGuard (votre téléphone et un serveur VPN) se prouvent mutuellement leur identité et s'accordent sur les clés de chiffrement qu'ils utiliseront pendant les 2 à 3 prochaines minutes. Il s'effectue en deux paquets UDP, dure moins de 100 ms, repose sur Noise_IK + Curve25519 + ChaCha20-Poly1305, et constitue l'une des réalisations d'ingénierie cryptographique les plus élégantes disponibles aujourd'hui. Voici exactement ce qui se passe à l'intérieur.

Par Casper's Cloak Security Team

En bref : WireGuard n'utilise pas TLS et ne possède pas de négociation en plusieurs allers-retours comme OpenVPN ou IPsec/IKEv2. Il emploie un handshake cryptographique fixe et précis, dérivé du Noise Protocol Framework — plus précisément le pattern Noise_IK — qui se conclut en exactement deux messages. Les deux pairs connaissent à l'avance les clés publiques à long terme de l'autre (configurées de façon statique, à l'image des clés SSH), si bien que le handshake n'a pas pour but de découvrir des identités, mais de prouver mutuellement la possession des clés privées correspondantes et de dériver de nouvelles clés de session symétriques avec confidentialité persistante. L'ensemble de la transaction tient dans deux datagrammes UDP de quelques centaines d'octets chacun. Elle s'achève plus rapidement qu'un handshake TLS classique, et les clés de session résultantes sont renouvelées toutes les deux minutes pendant toute la durée de la connexion.

Pourquoi un handshake est nécessaire

Deux ordinateurs souhaitent communiquer de façon privée sur un réseau qu'ils ne contrôlent pas. Le problème cryptographique fondamental : avant de pouvoir chiffrer quoi que ce soit, ils doivent s'accorder sur un secret partagé qu'un attaquant surveillant le réseau ne pourra pas dériver. Ils doivent également vérifier mutuellement leur identité — sinon, un attaquant pourrait se faire passer pour l'autre partie et inciter l'un des pairs à chiffrer des données à destination de l'attaquant.

Un handshake résout ces deux problèmes dans un échange structuré :

  • Authentification mutuelle — chaque pair démontre qu'il possède une clé privée correspondant à une clé publique en laquelle l'autre a déjà confiance. Aucun pair ne transmet jamais la clé privée elle-même ; il prouve simplement qu'il la détient en effectuant des opérations cryptographiques que seule cette clé peut produire.
  • Accord de clé avec confidentialité persistante — les deux pairs génèrent des paires de clés fraîches et temporaires (« éphémères ») pour cette session spécifique, échangent les moitiés publiques et les combinent avec leurs clés à long terme pour dériver une clé de session symétrique. Les clés éphémères sont détruites après le handshake ; même si les clés à long terme venaient à être volées ultérieurement, les clés de session passées ne pourraient pas être reconstituées à partir d'elles. Cette propriété est appelée confidentialité persistante (forward secrecy) et explique pourquoi le trafic passé reste protégé même en cas de compromission future des clés.
  • Mise en place de la protection contre le rejeu — les deux pairs initialisent des compteurs et des nonces qui empêchent un attaquant de capturer et de rejouer du trafic antérieur.

Les différents protocoles VPN l'implémentent de façon différente. OpenVPN le fait via TLS, avec plusieurs allers-retours, une validation de certificat et de nombreuses suites de chiffrement configurables. IPsec/IKEv2 dispose de son propre protocole de négociation d'une complexité similaire. WireGuard le fait en deux paquets, sans configurabilité ni négociation de suite de chiffrement — chaque handshake WireGuard utilise le même ensemble fixe de primitives cryptographiques. Le compromis est délibéré : moins de complexité signifie une surface d'attaque réduite et une auditabilité facilitée, au prix d'une agilité nulle au niveau du protocole.

Le framework Noise — ce qu'il est et pourquoi WireGuard utilise Noise_IK

Le Noise Protocol Framework est une spécification pour la construction de handshakes cryptographiques. C'est l'œuvre de Trevor Perrin, qui a également conçu le Signal Protocol qui sécurise Signal, WhatsApp et la plupart des messageries modernes chiffrées de bout en bout. Noise n'est pas un protocole unique — c'est une boîte à outils de composants (« patterns » de handshake, primitives cryptographiques, règles de dérivation) qui permet à un concepteur de protocole de choisir exactement la forme de handshake dont il a besoin et d'obtenir une spécification précise de ce que contiennent les messages et des garanties qu'ils fournissent.

Les patterns de handshake Noise sont nommés avec deux lettres indiquant ce que chaque partie connaît à l'avance :

  • N — aucune clé statique pour cette partie ; seules des clés éphémères sont utilisées. Anonyme.
  • K — la clé statique est « connue » de l'autre partie à l'avance.
  • X — la clé statique est transmise pendant le handshake.
  • I — la clé statique est transmise « immédiatement » dans le premier message.

Noise_IK signifie : l'initiateur envoie sa clé statique Immédiatement (dans le premier message), et la clé statique du répondeur est Connue de l'initiateur à l'avance. Ce pattern est idéal pour le cas d'usage de WireGuard, car les deux pairs connaissent effectivement les clés statiques de l'autre à l'avance — elles sont configurées dans le fichier de configuration WireGuard. Le choix « IK » permet à l'intégralité du handshake de se conclure en deux messages, ce qui est le minimum possible pour un échange de clés mutuellement authentifié avec confidentialité persistante.

La spécification complète du framework Noise est publiée sur noiseprotocol.org et constitue l'une des réalisations d'ingénierie cryptographique publique les plus rigoureuses — rédigée pour être auditable, avec vérification formelle des patterns eux-mêmes. L'adoption de Noise_IK par WireGuard était un choix de conception délibéré pour bénéficier de l'analyse du framework.

Paquet 1 : Initiateur → Répondeur

Le handshake commence lorsque l'initiateur (votre téléphone, votre ordinateur portable, le côté client) décide de communiquer avec le répondeur (le serveur VPN). Cela se produit soit parce que du trafic attend en file d'attente que le tunnel soit établi, soit parce que la clé de session a expiré et qu'un renouvellement est nécessaire. L'initiateur construit un unique paquet UDP contenant :

  • Index expéditeur — un entier 32 bits choisi aléatoirement qui identifie cette session de handshake. Utilisé pour distinguer les handshakes simultanés entre les mêmes pairs.
  • Clé publique éphémère — une clé publique Curve25519 fraîchement générée. La clé privée correspondante est conservée en mémoire par l'initiateur. C'est le « E » dans le pattern Noise — la nouvelle clé éphémère introduite.
  • Clé publique statique (chiffrée) — la clé publique Curve25519 à long terme de l'initiateur, mais chiffrée avec une clé dérivée de l'échange éphémère. C'est une partie du « I » dans IK — la clé statique de l'initiateur est envoyée dans le premier message, mais elle est protégée contre les observateurs passifs.
  • Horodatage (chiffré) — un horodatage au format TAI64N, chiffré. C'est l'ancre de protection contre le rejeu : le répondeur rejettera tout handshake avec un horodatage antérieur à celui qu'il a déjà accepté de ce pair. Empêche un attaquant de capturer et de rejouer un message de handshake valide ultérieurement.
  • Champs MAC — deux courts authentificateurs (mac1, mac2) qui prouvent que l'expéditeur connaît la clé publique du répondeur. Le champ mac2 est également utilisé pour le mécanisme d'atténuation DoS par réponse de cookie décrit dans l'article WireGuard.

Ce que ce paquet prouve et accomplit : en incluant une clé éphémère fraîche, l'initiateur s'engage sur la moitié de la clé de session finale. En incluant l'horodatage et le MAC lié à la clé statique du répondeur, l'initiateur démontre « j'ai au moins la clé publique du répondeur » — ce qui signifie qu'un attaquant hors chemin quelconque ne peut pas envoyer trivialement de fausses initiations de handshake et gaspiller les ressources du serveur. Le paquet entier fait 148 octets, tient confortablement dans un seul datagramme UDP et n'est jamais fragmenté.

Un point subtil mérite d'être noté : la clé publique statique de l'initiateur est incluse mais chiffrée, de sorte qu'un observateur passif surveillant le réseau ne peut pas identifier quel client se connecte. Il peut voir que quelqu'un initie un handshake WireGuard vers ce serveur, mais pas qui. Il s'agit d'une propriété de confidentialité appelée masquage de l'identité de l'initiateur, qui est plus forte que ce que TLS offre par défaut.

Paquet 2 : Répondeur → Initiateur

Le répondeur reçoit le paquet d'initiation, déchiffre la clé publique statique de l'initiateur et la recherche dans sa table de pairs. Si le pair est connu et que l'horodatage est acceptable (plus récent que le dernier accepté), le répondeur génère sa propre paire de clés éphémères et construit un paquet de réponse :

  • Index expéditeur — l'identifiant 32 bits choisi par le répondeur pour cette session.
  • Index destinataire — renvoyé depuis l'initiateur, afin que les deux parties s'accordent sur la session concernée.
  • Clé publique éphémère — la clé publique éphémère fraîchement générée par le répondeur.
  • Charge utile chiffrée vide — un texte chiffré authentifié mais vide qui prouve que le répondeur peut dériver la clé de session. C'est le signal cryptographique « j'ai lu votre message et calculé la bonne clé ».
  • Champs MAC — même schéma que dans le paquet d'initiation.

Lorsque l'initiateur reçoit cette réponse, il effectue la dérivation de clé correspondante, vérifie que la charge utile vide authentifiée se déchiffre correctement avec la clé dérivée, et les deux parties ont désormais abouti à la même clé de session symétrique — de façon indépendante, sans que cette clé ait jamais traversé le réseau. La clé de session possède une confidentialité persistante parfaite car elle dépend des deux clés éphémères (qui vont être détruites) et des deux clés statiques.

Le paquet de réponse fait 92 octets. Le handshake total — les deux paquets combinés — représente 240 octets plus les en-têtes IP/UDP, tient dans deux échanges UDP aller-retour qui s'achèvent en environ un RTT réseau (un paquet dans chaque sens), et produit une session entièrement authentifiée avec confidentialité persistante, prête à chiffrer le trafic applicatif. Pas de validation de chaîne de certificats, pas de négociation de suite de chiffrement, pas de comparaison de version, pas de liste d'extensions — rien de ce qui complique les handshakes TLS.

La session qui suit

Une fois le handshake terminé, les deux pairs échangent des paquets de données dans un format beaucoup plus simple. Chaque paquet de données contient :

  • Index destinataire — l'identifiant de session 32 bits assigné par le destinataire lors du handshake.
  • Compteur — un nonce 64 bits qui s'incrémente à chaque paquet envoyé. Utilisé à la fois comme nonce AEAD et pour la détection de rejeu.
  • Charge utile chiffrée — le paquet IP d'origine, chiffré avec ChaCha20-Poly1305 en utilisant la clé de session et le compteur comme nonce.

ChaCha20-Poly1305 est une construction AEAD (Authenticated Encryption with Associated Data — chiffrement authentifié avec données associées) : elle chiffre à la fois la charge utile et produit un tag d'authentification qui détecte toute altération. Si un seul bit du texte chiffré est modifié, le déchiffrement échoue et le destinataire rejette le paquet. Il n'existe pas de mode d'échec « doux » — les paquets modifiés sont silencieusement abandonnés, tout comme les paquets avec le mauvais compteur ou le mauvais index destinataire.

Le destinataire maintient une fenêtre glissante de valeurs de compteur acceptées. Les paquets dont les compteurs se situent dans la fenêtre et n'ont pas encore été vus sont acceptés ; les paquets dont les compteurs tombent en dehors de la fenêtre (trop anciens) ou ont déjà été vus sont rejetés. Cela assure une protection anti-rejeu sans que le destinataire ait à mémoriser tous les compteurs jamais vus — seulement les plus récents, dans un petit bitmap.

Du point de vue du réseau, les paquets de données paraissent identiques quel que soit le contenu de la charge utile. Ce sont tous des paquets UDP vers la même IP et le même port de serveur, de tailles similaires (la charge utile chiffrée préserve la taille du paquet IP sous-jacent plus 32 octets de surcharge), sans aucun motif observable qui les distingue. Pas de SNI, pas d'échange de certificat, pas de structure handshake TLS puis données — juste de l'UDP opaque après le handshake initial de deux paquets.

Comportement de renouvellement de clé — toutes les 2 minutes OU tous les 2^60 paquets

WireGuard renouvelle les clés de session de façon agressive. La politique de renouvellement par défaut : un nouveau handshake est initié lorsque la session en cours a été active pendant 2 minutes ou a transmis 2^60 paquets, selon ce qui survient en premier. En pratique, c'est la limite de temps qui déclenche le renouvellement pour la plupart des sessions — 2^60 paquets est un nombre astronomiquement grand qu'aucune connexion réelle n'atteint jamais.

Pourquoi 2 minutes ? Pour deux raisons. Premièrement, des renouvellements fréquents améliorent la confidentialité persistante. Chaque session est chiffrée avec une clé dérivée d'une paire spécifique de clés éphémères. Plus la session est courte, moins de données transitent par une seule clé, de sorte que même des attaques cryptanalytiques théoriques futures devraient compromettre de nombreuses clés pour lire une quantité significative de trafic. Deuxièmement, le renouvellement est invisible pour l'application — le nouveau handshake se déroule en arrière-plan pendant que les anciennes clés de session continuent de chiffrer les données, et la transition est transparente. Les deux pairs maintiennent une petite fenêtre de chevauchement où ils acceptent les paquets chiffrés avec l'ancienne ou la nouvelle clé.

Le renouvellement est initié par le pair qui remarque en premier l'expiration du minuteur — généralement le côté initiateur. Le message de protocole est le même handshake en deux paquets décrit ci-dessus. Du point de vue d'un observateur extérieur, il voit une petite salve de paquets UDP supplémentaires toutes les deux minutes, mais aucun changement observable dans le flux de données lui-même.

Les phases du handshake en un coup d'œil

Le handshake complet, décomposé par phase, paquet et primitive cryptographique à l'œuvre :

Phase Paquet Ce qui est transmis Primitive cryptographique
1. Initiation Initiateur → Répondeur (148 octets) Index expéditeur, clé publique éphémère, clé statique chiffrée, horodatage chiffré, MACs Curve25519 (ECDH), BLAKE2s (hash/MAC), ChaCha20-Poly1305 (AEAD), HKDF (dérivation de clé)
2. Réponse Répondeur → Initiateur (92 octets) Index expéditeur, index destinataire, clé publique éphémère, charge utile chiffrée vide (confirmation de clé), MACs Curve25519 (ECDH), BLAKE2s, ChaCha20-Poly1305, HKDF
3. Session de données Dans les deux sens, indéfiniment (32 octets de surcharge par paquet) Index destinataire, compteur, paquet IP chiffré ChaCha20-Poly1305 (AEAD)
4. Renouvellement (toutes les 2 min) Même échange en deux paquets que les phases 1+2 Nouvelles clés éphémères, dérivation de nouvelle clé de session Mêmes primitives

Cinq primitives cryptographiques sont utilisées tout au long, aucune n'étant négociable : Curve25519 pour l'accord de clé Diffie-Hellman sur courbe elliptique, ChaCha20 pour le chiffrement symétrique en flux, Poly1305 pour le tag d'authentification, BLAKE2s pour la fonction de hachage et le MAC, et HKDF pour la dérivation de clé. C'est le choix de conception « sans agilité » : en codant en dur les primitives, la surface du protocole se réduit considérablement et l'analyse devient beaucoup plus tractable. Le coût est que si une primitive venait à être compromise, le protocole entier nécessiterait une nouvelle version — il n'existe pas de mécanisme intrabande pour effectuer une mise à niveau. Le pari de WireGuard est que ces primitives sont suffisamment bien étudiées pour qu'une rupture soudaine soit peu probable.

Ce qui peut mal tourner

Les handshakes cryptographiques ont des modes d'échec connus. Certains s'appliquent à WireGuard, d'autres non. Il est utile de les comprendre :

Attaques par rejeu

L'horodatage chiffré dans le paquet d'initiation empêche les rejeux. Si un attaquant capture un paquet d'initiation valide et tente de le rejouer ultérieurement, le répondeur voit un horodatage qu'il a déjà accepté (ou un antérieur au dernier accepté) et rejette le paquet. C'est l'une des raisons pour lesquelles WireGuard maintient un état par pair concernant le dernier horodatage de handshake — le protocole en dépend.

Compromission de clé à long terme

Si un attaquant vole la clé privée à long terme d'un pair, il peut se faire passer pour ce pair dans les futurs handshakes. Il ne peut toutefois pas déchiffrer les sessions passées — les clés éphémères qui ont dérivé ces clés de session ont été détruites après chaque handshake. C'est la garantie de confidentialité persistante. Pour atténuer le risque continu, il faut renouveler la clé à long terme (générer une nouvelle paire, distribuer la nouvelle clé publique aux pairs) — il n'existe pas de mécanisme au niveau du protocole pour invalider une ancienne clé, ce qui doit donc se faire hors bande.

Expiration NAT et mort silencieuse de la connexion

WireGuard fonctionne sur UDP, qui est sans connexion. Les traducteurs d'adresses réseau (dans votre routeur domestique ou le réseau de votre FAI) suppriment parfois les entrées de flux UDP après quelques minutes d'inactivité. Lorsque cela se produit, les paquets de réponse du répondeur ne peuvent plus atteindre l'initiateur — le NAT a oublié le mappage. La solution est le paramètre keepalive (souvent réglé à 25 secondes), qui envoie un petit paquet de heartbeat de l'initiateur vers le répondeur pour maintenir le mappage NAT actif. Sans keepalive, les connexions inactives peuvent mourir silencieusement et nécessiter un nouveau handshake pour être rétablies.

Déni de service par inondation de handshakes

Un répondeur sous attaque intensive peut recevoir de nombreuses initiations de handshake fictives, chacune nécessitant des opérations Curve25519 à traiter. WireGuard atténue cela avec le mécanisme de réponse par cookie : lorsque le répondeur est sous charge, il peut exiger que l'initiateur effectue un petit calcul de type preuve de travail avant que le répondeur s'engage dans un handshake complet. Le champ mac2 dans les paquets de handshake porte ce mécanisme. La résistance au DoS n'est pas parfaite — aucun protocole ne peut l'être — mais il est substantiellement plus difficile de saturer qu'un service basé sur TCP non authentifié, par exemple.

Pourquoi cela importe concrètement pour les utilisateurs de VPN

L'architecture de handshake présente des avantages concrets visibles par les utilisateurs par rapport aux anciens protocoles VPN :

  • Pas de handshake TLS côté client — WireGuard ne valide pas les certificats, ne remonte pas jusqu'à une CA, ne dépend pas du magasin de confiance système. Cela élimine toute une classe d'attaques (CA compromises, certificats mal émis) qui affectent les VPN basés sur TLS.
  • Pas de connexion avec état — le protocole fonctionne sur UDP et est sans connexion. Il n'existe pas de machine à états de type TCP à briser lors d'un changement de réseau. Un appareil en itinérance qui passe du Wi-Fi au réseau cellulaire n'a rien à rétablir ; il commence simplement à envoyer des paquets depuis la nouvelle adresse IP et le répondeur les accepte.
  • Itinérance instantanée — parce que la connexion est identifiée par les clés cryptographiques plutôt que par l'adresse IP source, le répondeur acceptera les paquets de n'importe quelle IP source produisant la bonne authentification cryptographique. C'est pourquoi WireGuard gère les transitions de réseau mobile bien mieux qu'OpenVPN ou IPsec, qui doivent souvent renégocier lorsque l'IP sous-jacente change.
  • Surface d'attaque minuscule — l'implémentation de référence fait environ 4 000 lignes de code. OpenSSL en compte plus de 500 000. Ce n'est pas une comparaison équitable (ils font des quantités de travail différentes), mais l'implication est réelle : un code plus petit est plus facile à auditer, plus facile à analyser formellement et présente moins d'opportunités pour des bugs d'implémentation qui se transforment en vulnérabilités.
  • Performance prévisible — chaque handshake utilise les mêmes primitives aux mêmes tailles de clé. Il n'y a pas de divergence entre chemin rapide et chemin lent en fonction de la suite de chiffrement négociée. Le handshake prend à peu près le même temps sur le même matériel, quelle que soit la destination.

Pour la comparaison des compromis avec l'ancien protocole qu'il a remplacé pour la plupart des utilisateurs, consultez notre analyse sur WireGuard vs OpenVPN, qui couvre les différences pratiques de performance et de sécurité. Pour comprendre en quoi les choix de tunnelisation d'un VPN influencent ce que voient les applications, consultez qu'est-ce que le split tunneling.

Casper's Cloak utilise WireGuard pour toutes les connexions clientes, exécute l'implémentation officielle en mode noyau sur les points de terminaison Linux, et fournit le client userspace standard (basé sur la référence wireguard-go) sur iOS, Android et macOS. Le handshake décrit ci-dessus est exactement ce qui se produit lorsque vous activez l'application. Le même pattern Noise_IK, le même ensemble de primitives Curve25519/ChaCha20-Poly1305/BLAKE2s/HKDF, le même renouvellement toutes les 2 minutes, le même handshake de 240 octets. La fonctionnalité de protection contre les menaces ajoute un filtrage au niveau DNS par-dessus le tunnel WireGuard — le tunnel gère le transport, le filtre gère la politique de destination.

Pour la spécification complète du protocole, le livre blanc WireGuard original de Jason Donenfeld est la référence faisant autorité : wireguard.com/papers/wireguard.pdf. L'article couvre la construction cryptographique, le modèle de menace, l'analyse formelle et les justifications d'implémentation. C'est l'un des écrits les plus lisibles sur la conception de protocoles modernes — cela vaut l'heure de lecture pour comprendre les compromis de conception à la source.

En résumé : le handshake WireGuard est composé de deux paquets, prend moins de 100 millisecondes en pratique, authentifie mutuellement les deux pairs, dérive des clés de session avec confidentialité persistante et résiste par conception à tous les schémas d'attaque courants (rejeu, rétrogradation, divulgation d'identité, DoS). C'est un protocole précis, fixe et opinionated — et c'est précisément cette nature opinionated qui en fait sa force.

Vérifié par Casper's Cloak Security Team · Dernière mise à jour

WireGuard, correctement configuré, avec filtrage intégré

Casper's Cloak exécute un tunnel WireGuard standard avec le handshake décrit ci-dessus — plus un filtrage DNS des destinations malveillantes connues, une gestion automatique d'IPv6 et un kill switch appliqué au niveau du système d'exploitation pour éviter toute fuite entre les handshakes.