Volver al blog
Explicaciones·15 min de lectura

Qué es un handshake de WireGuard — el protocolo paso a paso

El "handshake" es la forma en que dos peers de WireGuard (tu teléfono y un servidor VPN) demuestran su identidad mutua y acuerdan las claves de cifrado que usarán durante los próximos 2-3 minutos. Ocurre en dos paquetes UDP, dura menos de 100 ms, usa Noise_IK + Curve25519 + ChaCha20-Poly1305, y es una de las piezas de ingeniería criptográfica más elegantes que existen hoy en día. Aquí te explicamos exactamente qué ocurre en su interior.

Por Casper's Cloak Security Team

La versión corta: WireGuard no usa TLS ni dispone de una negociación de múltiples roundtrips como OpenVPN o IPsec/IKEv2. Emplea un handshake criptográfico fijo y deliberado derivado del Noise Protocol Framework — concretamente el patrón Noise_IK — que se completa en exactamente dos mensajes. Ambos peers conocen de antemano las claves públicas a largo plazo del otro (configuradas de forma estática, igual que las claves SSH), así que el propósito del handshake no es descubrir identidades, sino demostrar mutuamente que cada parte posee la clave privada correspondiente y derivar claves de sesión simétricas nuevas con secreto hacia adelante. Toda la transacción cabe en dos datagramas UDP de unos pocos cientos de bytes cada uno. Finaliza más rápido que un handshake TLS habitual, y las claves de sesión resultantes rotan cada dos minutos durante la conexión.

Por qué existe un handshake

Dos equipos quieren comunicarse de forma privada a través de una red que no controlan. El problema criptográfico fundamental: antes de cifrar cualquier cosa, necesitan acordar un secreto compartido que un atacante que observe la red no pueda deducir. También necesitan verificar la identidad del otro, ya que de lo contrario un atacante podría suplantar al otro lado y engañar a uno de los peers para que cifre datos destinados al atacante.

Un handshake resuelve ambos problemas en un intercambio estructurado:

  • Autenticación mutua — cada peer demuestra que posee una clave privada correspondiente a una clave pública en la que el otro ya confía. Ningún peer transmite nunca la clave privada en sí; simplemente demuestra que la tiene mediante operaciones criptográficas que solo esa clave puede producir.
  • Acuerdo de claves con secreto hacia adelante — ambos peers generan pares de claves temporales («efímeras») para esta sesión específica, intercambian las mitades públicas y las combinan con sus claves a largo plazo para derivar una clave de sesión simétrica. Las claves efímeras se descartan tras el handshake; incluso si las claves a largo plazo se roban más adelante, las claves de sesión pasadas no pueden reconstruirse a partir de ellas. Esta propiedad se denomina secreto hacia adelante y es la razón por la que el tráfico pasado permanece protegido aunque se produzca una futura vulneración de claves.
  • Configuración de protección contra repetición — ambos peers inicializan contadores y nonces que impiden que un atacante capture y reproduzca tráfico anterior en un momento posterior.

Los diferentes protocolos VPN implementan esto de formas distintas. OpenVPN lo hace a través de TLS, con múltiples roundtrips, validación de certificados y muchos conjuntos de cifrado configurables. IPsec/IKEv2 tiene su propio protocolo de negociación con una complejidad similar. WireGuard lo hace en dos paquetes, sin configurabilidad, sin negociación de conjuntos de cifrado — cada handshake de WireGuard usa el mismo conjunto fijo de primitivas criptográficas. El compromiso es deliberado: menos complejidad significa menor superficie de ataque y mayor facilidad de auditoría, a costa de cero agilidad a nivel de protocolo.

El framework Noise — qué es y por qué WireGuard usa Noise_IK

El Noise Protocol Framework es una especificación para construir handshakes criptográficos. Es obra de Trevor Perrin, quien también diseñó el Signal Protocol que protege Signal, WhatsApp y la mayoría de los mensajeros modernos con cifrado de extremo a extremo. Noise no es un único protocolo — es un kit de bloques de construcción («patrones» de handshake, primitivas criptográficas, reglas de derivación) que permite a un diseñador de protocolos elegir exactamente la forma de handshake que necesita y obtener una especificación precisa de qué contienen los mensajes y qué garantías ofrecen.

Los patrones de handshake de Noise se nombran con dos letras que indican qué conoce cada parte de antemano:

  • N — sin clave estática para ese lado; solo se usan claves efímeras. Anónimo.
  • K — la clave estática es «conocida» por la otra parte de antemano.
  • X — la clave estática se envía durante el handshake.
  • I — la clave estática se transmite «inmediatamente» en el primer mensaje.

Noise_IK significa: el iniciador envía su clave estática Inmediatamente (en el primer mensaje) y la clave estática del respondedor es Conocida por el iniciador de antemano. Este patrón es ideal para el caso de uso de WireGuard porque ambos peers genuinamente conocen las claves estáticas del otro de antemano — están configuradas en el archivo de configuración de WireGuard. La elección «IK» permite que el handshake completo se lleve a cabo en dos mensajes, que es el mínimo posible para un intercambio de claves con autenticación mutua y secreto hacia adelante.

La especificación completa del framework Noise está publicada en noiseprotocol.org y es una de las piezas más limpias de ingeniería criptográfica pública — escrita para ser auditable, con verificación formal de los propios patrones. La adopción de Noise_IK por parte de WireGuard fue una decisión de diseño deliberada para heredar el análisis del framework.

Paquete 1: Iniciador → Respondedor

El handshake comienza cuando el iniciador (tu teléfono, tu portátil, el lado cliente) decide comunicarse con el respondedor (el servidor VPN). Esto ocurre porque hay tráfico encolado esperando el túnel, o porque la clave de sesión ha expirado y se necesita un rekey. El iniciador construye un único paquete UDP que contiene:

  • Índice del emisor — un entero de 32 bits elegido aleatoriamente que identifica esta sesión de handshake. Se usa para diferenciar handshakes concurrentes entre los mismos peers.
  • Clave pública efímera — una clave pública Curve25519 recién generada. La clave privada correspondiente la guarda en memoria el iniciador. Esta es la «E» en el patrón Noise — la nueva clave efímera que se introduce.
  • Clave pública estática (cifrada) — la clave pública Curve25519 a largo plazo del iniciador, pero cifrada con una clave derivada del intercambio efímero. Esta es la parte de la «I» en IK — la clave estática del iniciador se envía en el primer mensaje, pero está protegida contra observadores pasivos.
  • Marca de tiempo (cifrada) — una marca de tiempo en formato TAI64N, cifrada. Es el ancla de protección contra repetición: el respondedor rechazará cualquier handshake con una marca de tiempo anterior a la que ya ha aceptado de este peer. Impide que un atacante capture y reproduzca un mensaje de handshake válido posteriormente.
  • Campos MAC — dos autenticadores cortos (mac1, mac2) que demuestran que el emisor conoce la clave pública del respondedor. El campo mac2 también se usa para el mecanismo de mitigación de DoS mediante cookie-reply descrito en el paper de WireGuard.

Lo que demuestra y logra este paquete: al incluir una clave efímera nueva, el iniciador se compromete con la mitad de la clave de sesión final. Al incluir la marca de tiempo y el MAC vinculado a la clave estática del respondedor, el iniciador demuestra «tengo al menos la clave pública del respondedor» — lo que significa que un atacante externo aleatorio no puede enviar trivialmente iniciaciones de handshake falsas y desperdiciar recursos del servidor. El paquete completo ocupa 148 bytes, cabe cómodamente en un solo datagrama UDP y nunca se fragmenta.

Hay una sutileza que vale la pena señalar: la clave pública estática del iniciador se incluye pero está cifrada, por lo que un observador pasivo que monitorice la red no puede identificar qué cliente se está conectando. Puede ver que alguien está iniciando un handshake WireGuard con este servidor, pero no quién. Esta es una propiedad de privacidad llamada ocultamiento de identidad del iniciador, y es más sólida que lo que TLS proporciona por defecto.

Paquete 2: Respondedor → Iniciador

El respondedor recibe el paquete de iniciación, descifra la clave pública estática del iniciador y la busca en su tabla de peers. Si el peer es conocido y la marca de tiempo es aceptable (más reciente que la última aceptada), el respondedor genera su propio par de claves efímeras y construye un paquete de respuesta:

  • Índice del emisor — el identificador de 32 bits elegido por el respondedor para esta sesión.
  • Índice del receptor — devuelto del iniciador, para que ambas partes acuerden de qué sesión se trata.
  • Clave pública efímera — la clave pública efímera recién generada por el respondedor.
  • Payload cifrado vacío — un texto cifrado autenticado pero vacío que demuestra que el respondedor puede derivar la clave de sesión. Esta es la señal criptográfica de «leí tu mensaje y calculé la clave correcta».
  • Campos MAC — mismo patrón que el paquete de iniciación.

Cuando el iniciador recibe esta respuesta, realiza la derivación de claves correspondiente, verifica que el payload cifrado vacío autenticado se descifre correctamente con la clave derivada, y ahora ambas partes han llegado a la misma clave de sesión simétrica — de forma independiente, sin que esa clave haya cruzado nunca la red. La clave de sesión tiene secreto perfecto hacia adelante porque depende de ambas claves efímeras (que están a punto de destruirse) y de ambas claves estáticas.

El paquete de respuesta ocupa 92 bytes. El handshake completo — ambos paquetes combinados — es de 240 bytes más encabezados IP/UDP, cabe en dos intercambios UDP de roundtrip que se completan en aproximadamente un RTT de red (un paquete en cada dirección), y produce una sesión totalmente autenticada con secreto hacia adelante, lista para cifrar tráfico de aplicación. No hay validación de cadena de certificados, ni negociación de conjuntos de cifrado, ni comparación de versiones, ni lista de extensiones — nada de lo que hace complicados los handshakes TLS.

La sesión que sigue

Una vez completado el handshake, los dos peers intercambian paquetes de datos en un formato mucho más sencillo. Cada paquete de datos contiene:

  • Índice del receptor — el ID de sesión de 32 bits asignado por el receptor durante el handshake.
  • Contador — un nonce de 64 bits que se incrementa con cada paquete enviado. Se usa tanto como nonce AEAD como para la detección de repetición.
  • Payload cifrado — el paquete IP original, cifrado con ChaCha20-Poly1305 usando la clave de sesión y el contador como nonce.

ChaCha20-Poly1305 es una construcción AEAD (Cifrado Autenticado con Datos Asociados): cifra el payload y produce una etiqueta de autenticación que detecta cualquier manipulación. Si se altera un solo bit del texto cifrado, el descifrado falla y el receptor descarta el paquete. No hay modo de fallo «suave» — los paquetes modificados se descartan silenciosamente, igual que los paquetes con el contador incorrecto o el índice de receptor incorrecto.

El receptor mantiene una ventana deslizante de valores de contador aceptados. Los paquetes con contadores que caen dentro de la ventana y no se han visto antes son aceptados; los paquetes que caen por debajo de la ventana (demasiado antiguos) o que ya se han visto son rechazados. Esto proporciona protección anti-repetición sin necesidad de que el receptor recuerde todos los contadores vistos — solo los más recientes, en un pequeño mapa de bits.

Desde la perspectiva de la red, los paquetes de datos parecen idénticos independientemente del contenido del payload. Son todos paquetes UDP hacia la misma IP y puerto del servidor, con tamaños similares (el payload cifrado conserva el tamaño del paquete IP subyacente más 32 bytes de sobrecarga) y sin ningún patrón observable que los distinga. No hay SNI, ni intercambio de certificados, ni estructura TLS-handshake-luego-datos — solo UDP opaco tras el handshake inicial de dos paquetes.

Comportamiento de rekey — cada 2 minutos O cada 2^60 paquetes

WireGuard rota las claves de sesión de forma agresiva. La política de rekey por defecto: se inicia un nuevo handshake cuando la sesión actual ha estado activa durante 2 minutos o ha transmitido 2^60 paquetes, lo que ocurra primero. En la práctica, el límite temporal es lo que desencadena el rekey en la mayoría de sesiones — 2^60 paquetes es un número astronómicamente grande que ninguna conexión real alcanza jamás.

¿Por qué 2 minutos? Dos razones. En primer lugar, el rekey frecuente mejora el secreto hacia adelante. Cada sesión se cifra con una clave derivada de un par específico de claves efímeras. Cuanto más corta sea la sesión, menos datos fluyen por una única clave, por lo que incluso ataques criptanalíticos futuros teóricos tendrían que comprometer muchas claves para leer una cantidad significativa de tráfico. En segundo lugar, el rekey es invisible para la aplicación — el nuevo handshake ocurre en segundo plano mientras las antiguas claves de sesión continúan cifrando datos, y el cambio es transparente. Ambos peers mantienen una pequeña ventana de solapamiento en la que aceptan paquetes cifrados con la clave antigua o la nueva.

El rekey lo inicia el peer que primero nota que ha expirado el temporizador — normalmente el lado iniciador. El mensaje del protocolo es el mismo handshake de dos paquetes descrito anteriormente. Desde la perspectiva de un observador externo, se ven un pequeño conjunto de paquetes UDP adicionales cada dos minutos, pero ningún cambio observable en el propio flujo de datos.

Fases del handshake de un vistazo

El handshake completo, desglosado por fase, paquete y la primitiva criptográfica que realiza el trabajo:

Fase Paquete Qué se transmite Primitiva criptográfica
1. Iniciación Iniciador → Respondedor (148 bytes) Índice del emisor, clave pública efímera, clave estática cifrada, marca de tiempo cifrada, MACs Curve25519 (ECDH), BLAKE2s (hash/MAC), ChaCha20-Poly1305 (AEAD), HKDF (derivación de claves)
2. Respuesta Respondedor → Iniciador (92 bytes) Índice del emisor, índice del receptor, clave pública efímera, payload cifrado vacío (confirmación de clave), MACs Curve25519 (ECDH), BLAKE2s, ChaCha20-Poly1305, HKDF
3. Sesión de datos Ambas direcciones, indefinidamente (32 bytes de sobrecarga por paquete) Índice del receptor, contador, paquete IP cifrado ChaCha20-Poly1305 (AEAD)
4. Rekey (cada 2 min) El mismo intercambio de dos paquetes que las fases 1+2 Claves efímeras nuevas, nueva derivación de clave de sesión Las mismas primitivas

A lo largo del proceso se usan cinco primitivas criptográficas, ninguna de ellas negociable: Curve25519 para el acuerdo de claves mediante curva elíptica Diffie-Hellman, ChaCha20 para el cifrado de flujo simétrico, Poly1305 para la etiqueta de autenticación, BLAKE2s para la función hash y MAC, y HKDF para la derivación de claves. Esta es la elección de diseño de «sin agilidad»: al fijar las primitivas, la superficie del protocolo se reduce drásticamente y el análisis se vuelve mucho más manejable. El coste es que si alguna primitiva quedara algún día comprometida, el protocolo entero necesitaría una nueva versión — no hay forma integrada de actualizar. La apuesta de WireGuard es que estas primitivas están suficientemente estudiadas como para que una rotura repentina sea improbable.

Qué puede salir mal

Los handshakes criptográficos tienen modos de fallo conocidos. Algunos aplican a WireGuard; otros no. Vale la pena entenderlos:

Ataques de repetición

La marca de tiempo cifrada en el paquete de iniciación previene las repeticiones. Si un atacante captura un paquete de iniciación válido e intenta reproducirlo más tarde, el respondedor ve una marca de tiempo que ya ha aceptado (o una más antigua que la última aceptada) y rechaza el paquete. Esta es una de las razones por las que WireGuard mantiene estado por peer sobre la última marca de tiempo del handshake — el protocolo depende de ello.

Compromiso de clave a largo plazo

Si un atacante roba la clave privada a largo plazo de un peer, puede suplantar a ese peer en handshakes futuros. Sin embargo, no puede descifrar sesiones pasadas — las claves efímeras que derivaron esas claves de sesión fueron destruidas tras cada handshake. Esta es la garantía de secreto hacia adelante. La mitigación para el riesgo continuo es rotar la clave a largo plazo (generar un nuevo par, distribuir la nueva clave pública a los peers) — no existe un mecanismo a nivel de protocolo para invalidar una clave antigua, por lo que esto debe hacerse fuera de banda.

Tiempo de espera NAT y muerte silenciosa de la conexión

WireGuard funciona sobre UDP, que no tiene estado de conexión. Los traductores de direcciones de red (en tu router doméstico o la red de tu ISP) a veces eliminan las entradas de flujo UDP tras unos minutos de inactividad. Cuando esto ocurre, los paquetes de respuesta del respondedor ya no pueden llegar al iniciador — el NAT ha olvidado la asignación. La mitigación es la configuración de keepalive (a menudo establecida en 25 segundos), que envía un pequeño paquete de heartbeat del iniciador al respondedor para mantener activa la asignación NAT. Sin keepalive, las conexiones inactivas pueden morir silenciosamente y requerir un nuevo handshake para restaurarse.

Denegación de servicio mediante inundación de handshakes

Un respondedor bajo un ataque intenso puede recibir muchas iniciaciones de handshake falsas, cada una de las cuales requiere operaciones Curve25519 para procesarse. WireGuard mitiga esto con el mecanismo de cookie-reply: cuando el respondedor está bajo carga, puede exigir que el iniciador realice un pequeño cálculo estilo prueba de trabajo antes de que el respondedor se comprometa con un handshake completo. El campo mac2 en los paquetes de handshake lleva este mecanismo. La resistencia a DoS no es perfecta — ningún protocolo puede serlo — pero es sustancialmente más difícil de inundar que, por ejemplo, un servicio basado en TCP sin autenticación.

Por qué esto importa para los usuarios de VPN en la práctica

La arquitectura del handshake tiene beneficios concretos visibles para el usuario en comparación con protocolos VPN más antiguos:

  • Sin handshake TLS en el cliente — WireGuard no valida certificados, no encadena a una CA ni depende del almacén de confianza del sistema. Esto elimina toda una clase de ataques (CAs comprometidas, certificados emitidos incorrectamente) que afectan a las VPN basadas en TLS.
  • Sin conexión con estado — el protocolo funciona sobre UDP y no tiene estado. No hay máquina de estados de tipo TCP que se rompa cuando cambia la red. Un dispositivo itinerante que cambia de Wi-Fi a datos móviles no necesita reestablecer nada; simplemente empieza a enviar paquetes desde la nueva dirección IP y el respondedor los acepta.
  • Itinerancia instantánea — como la conexión se identifica por las claves criptográficas y no por la dirección IP de origen, el respondedor aceptará paquetes de cualquier IP de origen que produzca la autenticación criptográfica correcta. Por eso WireGuard gestiona mucho mejor las transiciones de red móvil que OpenVPN o IPsec, que a menudo necesitan renegociar cuando cambia la IP subyacente.
  • Superficie de ataque mínima — la implementación de referencia tiene unas 4.000 líneas de código. OpenSSL tiene más de 500.000. No es una comparación justa (hacen cantidades de trabajo diferentes), pero la implicación es real: el código más pequeño es más fácil de auditar, más fácil de analizar formalmente y presenta menos oportunidades de errores de implementación que se conviertan en vulnerabilidades.
  • Rendimiento predecible — cada handshake usa las mismas primitivas con los mismos tamaños de clave. No hay divergencia de ruta rápida/lenta según el conjunto de cifrado negociado. El handshake tarda aproximadamente el mismo tiempo en el mismo hardware independientemente de con quién te conectes.

Para la comparación de compensaciones con el protocolo anterior que reemplazó para la mayoría de usuarios, consulta nuestro artículo sobre WireGuard vs OpenVPN, que cubre las diferencias prácticas de rendimiento y seguridad. Para entender por qué las opciones de tunelización de una VPN importan en lo que ven las aplicaciones, consulta qué es el split tunneling.

Casper's Cloak usa WireGuard para todas las conexiones de clientes, ejecuta la implementación oficial en modo kernel en los endpoints Linux, y distribuye el cliente estándar en espacio de usuario (basado en la referencia wireguard-go) en iOS, Android y macOS. El handshake descrito anteriormente es exactamente lo que ocurre cuando activas la app. El mismo patrón Noise_IK, el mismo conjunto de primitivas Curve25519/ChaCha20-Poly1305/BLAKE2s/HKDF, el mismo rekey de 2 minutos, el mismo handshake de 240 bytes. La función de protección frente a amenazas añade filtrado a nivel DNS sobre el túnel WireGuard — el túnel gestiona el transporte, el filtro gestiona la política de destino.

Para la especificación completa del protocolo, el whitepaper original de WireGuard de Jason Donenfeld es la referencia autorizada: wireguard.com/papers/wireguard.pdf. El paper cubre la construcción criptográfica, el modelo de amenazas, el análisis formal y la justificación de implementación. Es uno de los escritos más legibles sobre diseño de protocolos modernos — merece la pena dedicarle una hora si quieres entender las compensaciones de diseño en la fuente.

Conclusión: el handshake de WireGuard consiste en dos paquetes, tarda menos de 100 milisegundos en la práctica, autentica mutuamente a ambos peers, deriva claves de sesión con secreto hacia adelante y resiste por diseño todos los patrones de ataque habituales (repetición, degradación, divulgación de identidad, DoS). Es un protocolo ajustado, fijo y deliberado, y precisamente esa deliberación es su punto fuerte.

Revisado por Casper's Cloak Security Team · Última actualización

WireGuard, correctamente configurado, con filtrado integrado

Casper's Cloak ejecuta un túnel WireGuard estándar con el handshake descrito anteriormente — más filtrado a nivel DNS para destinos maliciosos conocidos, gestión automática de IPv6 y un kill switch aplicado a nivel de sistema operativo para que nada se filtre entre handshakes.