Nota
La fase de propuesta está cerrada. Consulte SPEC para la especificación oficial. Esta propuesta aún puede ser referenciada para obtener información de fondo.
Visión general
Esta propuesta describe un protocolo de acuerdo de clave autenticado para mejorar la resistencia de NTCP a diversas formas de identificación automática y ataques.
La propuesta se organiza de la siguiente manera: se presentan los objetivos de seguridad, seguidos de una discusión del protocolo básico. A continuación, se proporciona una especificación completa de todos los mensajes del protocolo. Finalmente, se discuten las direcciones del router y la identificación de la versión. También se incluye un apéndice que analiza un ataque genérico a esquemas de relleno comunes, así como un apéndice que contiene varios candidatos para el cifrado autenticado.
Al igual que con otros transportes I2P, NTCP2 se define únicamente para el transporte punto a punto (router a router) de mensajes I2NP. No es un tubería de datos de propósito general.
Motivación
Los datos NTCP se cifran después del primer mensaje (y el primer mensaje parece ser datos aleatorios), lo que evita la identificación del protocolo a través del “análisis de carga”. Sin embargo, todavía es vulnerable a la identificación del protocolo a través del “análisis de flujo”. Esto se debe a que los primeros 4 mensajes (es decir, el apretón de manos) tienen una longitud fija (288, 304, 448 y 48 bytes).
Al agregar cantidades aleatorias de datos aleatorios a cada uno de los mensajes, podemos hacer que sea mucho más difícil.
Los autores reconocen que las prácticas de seguridad estándar sugerirían utilizar un protocolo existente como TLS, pero este es Prop104 y tiene sus propios problemas. Donde sea apropiado, se han agregado párrafos de “trabajo futuro” para indicar características o temas de discusión que faltan.
Objetivos de diseño
Soportar NTCP 1 y 2 en un solo puerto, autodetectar y publicar como un solo “transporte” (es decir, RouterAddress) en el NetDB .
Publicar soporte para la versión 1 solo, 2 solo o 1+2 en el NetDB en un campo separado y establecer la versión 1 solo por defecto (no vincular el soporte de la versión a una versión del router en particular)
Asegurarse de que todas las implementaciones (Java/i2pd/Kovri/go) puedan agregar soporte para la versión 2 (o no) según sus propios horarios
Agregar relleno aleatorio a todos los mensajes NTCP, incluidos los mensajes de apretón de manos y los mensajes de datos (es decir, ofuscamiento de longitud para que todos los mensajes no sean múltiplos de 16 bytes) Proporcionar un mecanismo de opciones para que ambas partes soliciten relleno mínimo y máximo y/o distribución de relleno. Los detalles de la distribución de relleno son dependientes de la implementación y pueden o no estar especificados en el protocolo en sí.
Ofuscar el contenido de los mensajes que no están cifrados (1 y 2), lo suficiente como para que los cuadros de inspección de paquetes (DPI) y las firmas de antivirus no puedan clasificarlos fácilmente. También asegurarse de que los mensajes dirigidos a un solo peer o conjunto de pares no tengan un patrón de bits similar.
Corregir la pérdida de bits en DH debido al formato Java Ticket1112 , posiblemente (probablemente) cambiando a X25519.
Cambiar a una función de derivación de claves (KDF) real en lugar de usar el resultado de DH tal como está?
Agregar “resistencia a la exploración” (como lo llama Tor); esto incluye resistencia a la reproducción.
Mantener el intercambio de claves autenticado de dos vías (2W-AKE). 1W-AKE no es suficiente para nuestra aplicación.
Continuar utilizando las firmas de tipo variable y longitud variable (del RouterIdentity de firma de clave publicada) como parte de la autenticación. Confíe en una clave pública estática publicada en el RouterInfo como otra parte de la autenticación.
Agregar opciones/versión en el apretón de manos para la extensibilidad futura.
Agregar resistencia a la segmentación TCP maliciosa si es posible.
No agregar significativamente a la CPU requerida para la configuración de la conexión; si es posible, reducirla significativamente.
Agregar autenticación de mensaje (MAC), posiblemente HMAC-SHA256 y Poly1305, y eliminar el checksum de Adler.
Acortar y simplificar el encabezado I2NP: Acortar la expiración a 4 bytes, como en SSU. Quitar el checksum de SHA256 truncado de 1 byte.
Si es posible, reducir el apretón de manos de 4 mensajes y dos viajes de ida y vuelta a un apretón de manos de 3 mensajes y un viaje de ida y vuelta, como en SSU . Esto requeriría mover la firma de Bob en el mensaje 4 al mensaje 2. Investigar la razón de los 4 mensajes en el correo electrónico de diez años de antigüedad/estado/reunión de archivos.
Minimizar la sobrecarga del protocolo antes del relleno. Si bien se agregará relleno, y posiblemente mucho, la sobrecarga antes del relleno sigue siendo sobrecarga. Los nodos de baja banda deben poder utilizar NTCP2.
Mantener los timestamps para la detección de reproducción y desviación.
Evitar cualquier problema de año 2038 en los timestamps, debe funcionar hasta al menos 2106.
Aumentar el tamaño máximo de mensaje de 16K a 32K o 64K.
Cualquier primitiva criptográfica nueva debe estar disponible en bibliotecas para su uso en implementaciones de router Java (1.7), C++ y Go.
Incluir representantes de los desarrolladores de routers Java, C++ y Go en el diseño.
Minimizar los cambios (pero todavía habrá muchos).
Soportar ambas versiones en un conjunto común de código (esto puede que no sea posible y es dependiente de la implementación en cualquier caso).
No objetivos
Resistencia a la inspección de paquetes profunda… eso serían transportes conmutable, Prop109 .
Un transporte basado en TLS (o similar a HTTPS)… eso sería Prop104 .
Está bien cambiar la criptografía de flujo simétrica.
Resistencia a la inspección de paquetes basada en temporización (la temporización entre mensajes/demoras puede ser dependiente de la implementación; las demoras intra-mensaje pueden introducirse en cualquier punto, incluido antes de enviar el relleno aleatorio, por ejemplo). Las demoras artificiales (lo que obfs4 llama IAT o tiempo de llegada entre mensajes) son independientes del protocolo en sí.
Negabilidad de la participación en una sesión (hay firmas allí).
No objetivos que pueden reconsiderarse o discutirse parcialmente:
El grado de protección contra la inspección de paquetes profunda (DPI)
Seguridad post-cuántica (PQ)
Negabilidad
Objetivos relacionados
- Implementar un conjunto de pruebas NTCP 1/2
Objetivos de seguridad
Consideramos tres partes:
- Alice, que desea establecer una nueva sesión.
- Bob, con quien Alice desea establecer una sesión.
- Mallory, el “hombre en el medio” entre Alice y Bob.
Como máximo, dos participantes pueden participar en ataques activos.
Alice y Bob están en posesión de un par de claves estáticas, que se contiene en su RouterIdentity.
El protocolo propuesto intenta permitir que Alice y Bob acuerden una clave secreta compartida (K) bajo los siguientes requisitos:
Seguridad de la clave privada: ni Bob ni Mallory aprenden nada sobre la clave privada estática de Alice. Simétricamente, Alice no aprende nada sobre la clave privada estática de Bob.
La clave de sesión K es conocida solo por Alice y Bob.
Confidencialidad perfecta hacia adelante: la clave de sesión acordada permanece secreta en el futuro, incluso cuando las claves privadas estáticas de Alice y/o Bob se revelan después de que se ha acordado la clave.
Autenticación de dos vías: Alice está segura de que ha establecido una sesión con Bob, y viceversa.
Protección contra la inspección de paquetes en línea: asegurarse de que no sea trivial detectar que Alice y Bob están participando en el protocolo utilizando solo técnicas de inspección de paquetes en línea (DPI) directas. Consulte a continuación.
Negabilidad limitada: ni Alice ni Bob pueden negar la participación en el protocolo, pero si alguno de ellos filtra la clave compartida, la otra parte puede negar la autenticidad del contenido de los datos transmitidos.
La presente propuesta intenta proporcionar los cinco requisitos anteriores basándose en el protocolo de Estación a Estación (STS). Tenga en cuenta que este protocolo también es la base para el protocolo SSU .
Discusión adicional de DPI
Asumimos dos componentes de DPI:
1) DPI en línea
DPI en línea que inspecciona todos los flujos en tiempo real. Las conexiones pueden bloquearse u obstaculizarse de otra manera. Los datos o metadatos de la conexión pueden identificarse y almacenarse para análisis fuera de línea. El DPI en línea no tiene acceso a la base de datos de la red I2P. El DPI en línea tiene capacidad computacional en tiempo real limitada, incluida la calculación de longitud, la inspección de campos y cálculos simples como XOR. El DPI en línea tiene la capacidad de funciones criptográficas en tiempo real rápidas como AES, AEAD y hashing, pero estas serían demasiado costosas para aplicar a la mayoría o a todos los flujos. Cualquier aplicación de estas operaciones criptográficas se aplicaría solo a flujos en combinaciones de IP/Puerto identificadas previamente por análisis fuera de línea. El DPI en línea no tiene la capacidad de funciones criptográficas de alta sobrecarga como DH o elligator2. El DPI en línea no está diseñado específicamente para detectar I2P, aunque puede tener reglas de clasificación limitadas para ese propósito.
Es un objetivo evitar la identificación del protocolo por un DPI en línea.
La noción de DPI en línea o “directa” se toma aquí para incluir las siguientes capacidades del adversario:
La capacidad de inspeccionar todos los datos enviados o recibidos por el objetivo.
La capacidad de realizar operaciones en los datos observados, como aplicar cifrado de bloques o funciones de hash.
La capacidad de almacenar y comparar con mensajes enviados previamente.
La capacidad de modificar, retrasar o fragmentar paquetes.
Sin embargo, el DPI en línea se supone que tiene las siguientes restricciones:
La incapacidad de asignar direcciones IP a hashes de router. Si bien esto es trivial con acceso en tiempo real a la base de datos de la red, requeriría un sistema de DPI específicamente diseñado para apuntar a I2P.
La incapacidad de utilizar información de temporización para detectar el protocolo.
En general, la caja de herramientas del DPI en línea no contiene herramientas incorporadas que estén específicamente diseñadas para la detección de I2P. Esto incluye la creación de “trampas” que, por ejemplo, incluirían relleno no aleatorio en sus mensajes. Tenga en cuenta que esto no excluye sistemas de aprendizaje automático o herramientas de DPI altamente configurables, siempre que cumplan con los demás requisitos.
Para contrarrestar el análisis de carga, se garantiza que todos los mensajes sean indistinguibles de los datos aleatorios. Esto también requiere que su longitud sea aleatoria, lo que es más complicado que simplemente agregar relleno aleatorio. De hecho, en el Apéndice A, los autores argumentan que un esquema de relleno ingenuo (es decir, uniforme) no resuelve el problema. El Apéndice A propone incluir retrasos aleatorios o desarrollar un esquema de relleno alternativo que pueda proporcionar una protección razonable para el ataque propuesto.
Para protegerse contra la entrada número seis anterior, las implementaciones deben incluir retrasos aleatorios en el protocolo. Estas técnicas no están cubiertas por esta propuesta, pero también podrían resolver los problemas de longitud de relleno. En resumen, la propuesta proporciona una buena protección contra el análisis de carga (cuando se tienen en cuenta las consideraciones del Apéndice A), pero solo una protección limitada contra el análisis de flujo.
2) DPI fuera de línea
DPI fuera de línea que inspecciona los datos almacenados por el DPI en línea para análisis posterior. El DPI fuera de línea puede estar diseñado específicamente para detectar I2P. El DPI fuera de línea tiene acceso en tiempo real a la base de datos de la red I2P. El DPI fuera de línea tiene acceso a esta y otras especificaciones de I2P. El DPI fuera de línea tiene capacidad computacional ilimitada, incluidas todas las funciones criptográficas definidas en esta especificación.
El DPI fuera de línea no tiene la capacidad de bloquear conexiones existentes. El DPI fuera de línea tiene la capacidad de enviar (dentro de minutos de la configuración) a la dirección IP/puerto de las partes, por ejemplo, TCP RST. El DPI fuera de línea tiene la capacidad de reproducir (dentro de minutos de la configuración) mensajes anteriores (modificados o no) para “exploración” u otros motivos.
No es un objetivo evitar la identificación del protocolo por un DPI fuera de línea. Todos los decodificadores de datos ofuscados en los dos primeros mensajes, implementados por los routers I2P, también pueden implementarse por el DPI fuera de línea.
Es un objetivo rechazar las conexiones intentadas mediante la reproducción de mensajes anteriores.
Trabajo futuro
Considerar el comportamiento del protocolo cuando los paquetes se pierden o reordenan por un atacante. Un trabajo interesante reciente en este área se puede encontrar en IACR-1150 .
Proporcionar una clasificación más precisa de los sistemas de DPI, teniendo en cuenta la literatura existente relacionada con el tema.
Discutir la seguridad formal del protocolo propuesto, idealmente teniendo en cuenta el modelo de atacante de DPI.
Marco de protocolo de ruido
Esta propuesta proporciona los requisitos basados en el Marco de protocolo de ruido NOISE (Revisión 33, 2017-10-04). El ruido tiene propiedades similares al protocolo de Estación a Estación, que es la base para el protocolo SSU . En la jerga de Noise, Alice es el iniciador y Bob es el respondedor.
NTCP2 se basa en el protocolo de ruido Noise_XK_25519_ChaChaPoly_SHA256. (El identificador real de la función de derivación de claves inicial es “Noise_XKaesobfse+hs2+hs3_25519_ChaChaPoly_SHA256” para indicar extensiones de I2P: consulte la sección KDF 1 a continuación) Este protocolo de ruido utiliza los siguientes primitivos:
Patrón de apretón de manos: XK Alice transmite su clave a Bob (X) Alice ya conoce la clave estática de Bob (K)
Función DH: X25519 X25519 DH con una longitud de clave de 32 bytes como se especifica en RFC-7748 .
Función de cifrado: ChaChaPoly AEAD_CHACHA20_POLY1305 como se especifica en RFC-7539 sección 2.8. 12 bytes de nonce, con los primeros 4 bytes establecidos en cero.
Función de hash: SHA256 Hash estándar de 32 bytes, ya utilizado ampliamente en I2P.
Adiciones al marco
Esta propuesta define las siguientes mejoras al Noise_XK_25519_ChaChaPoly_SHA256. Estas mejoras siguen en general las directrices de NOISE sección 13.
Las claves efímeras de texto plano se ofuscan con cifrado AES utilizando una clave conocida y un IV. Esto es más rápido que elligator2.
Se agrega relleno aleatorio de texto plano a los mensajes 1 y 2. El relleno de texto plano se incluye en el cálculo del hash de apretón de manos (MixHash). Consulte las secciones KDF para el mensaje 2 y el mensaje 3 parte 1. Se agrega relleno AEAD aleatorio a los mensajes 3 y a los mensajes de la fase de datos.
Se agrega un campo de longitud de trama de dos bytes, como se requiere para Noise sobre TCP, y como en obfs4. Esto se utiliza en los mensajes de la fase de datos solo. Los marcos AEAD de los mensajes 1 y 2 tienen una longitud fija. El marco AEAD de la parte 1 del mensaje 3 tiene una longitud fija. La longitud del marco AEAD de la parte 2 del mensaje 3 se especifica en el mensaje 1.
El campo de longitud de la trama de dos bytes se ofusca con SipHash-2-4, como en obfs4.
Se define el formato de carga útil para los mensajes 1, 2, 3 y la fase de datos. Por supuesto, esto no está definido en Noise.
Nuevos primitivos criptográficos para I2P
Las implementaciones de router I2P existentes requerirán implementaciones para los siguientes primitivos criptográficos estándar, que no son necesarios para los protocolos I2P actuales:
Generación de claves y DH X25519
AEAD_ChaCha20_Poly1305 (abreviado como ChaChaPoly a continuación)
SipHash-2-4
Estimación de la sobrecarga de procesamiento
Tamaños de mensaje para los 3 mensajes:
- 64 bytes + relleno (NTCP era 288 bytes)
- 64 bytes + relleno (NTCP era 304 bytes)
- aproximadamente 64 bytes + información del router de Alice + relleno. La información del router promedio es de aproximadamente 750 bytes. Longitud total promedio 814 bytes antes del relleno (NTCP era 448 bytes)
- no es necesario en NTCP2 (NTCP era 48 bytes)
Total antes del relleno: NTCP2: 942 bytes NTCP: 1088 bytes Tenga en cuenta que si Alice se conectó a Bob con el propósito de enviar un mensaje de DatabaseStore de su RouterInfo, ese mensaje no es necesario, ahorrando aproximadamente 800 bytes.
Las siguientes operaciones criptográficas son necesarias para cada parte para completar el apretón de manos y comenzar la fase de datos:
- AES: 2
- SHA256: 7 (Alice), 6 (Bob) (no incluyendo 1 Alice, 2 Bob precalculados para todas las conexiones) (no incluyendo HMAC-SHA256)
- HMAC-SHA256: 19
- ChaChaPoly: 4
- Generación de claves X25519: 1
- DH X25519: 3
- Verificación de firma: 1 (Bob) (Alice firmó previamente cuando generó su RI) Presumiblemente Ed25519 (dependiente del tipo de firma de RI)
Las siguientes operaciones criptográficas son necesarias para cada parte para cada mensaje de la fase de datos:
- SipHash: 1
- ChaChaPoly: 1
Mensajes
Todos los mensajes NTCP2 son de 65537 bytes o menos de longitud. El formato de mensaje se basa en los mensajes de Noise, con modificaciones para enmarcado e indistinguibilidad. Las implementaciones que utilizan bibliotecas de Noise estándar pueden necesitar preprocesar los mensajes recibidos para/from el formato de mensaje de Noise. Todos los campos cifrados son cifradatos AEAD.
La secuencia de establecimiento es la siguiente:
Alice Bob
SessionRequest ------------------->
<------------------- SessionCreated
SessionConfirmed ----------------->
Utilizando la terminología de Noise, la secuencia de establecimiento y datos es la siguiente: (Propiedades de seguridad de carga)
XK(s, rs): Autenticación Confidencialidad
<- s
...
-> e, es 0 2
<- e, ee 2 1
-> s, se 2 5
<- 2 5
Una vez que se ha establecido una sesión, Alice y Bob pueden intercambiar mensajes de datos.
Todos los tipos de mensaje (SessionRequest, SessionCreated, SessionConfirmed, Data y TimeSync) están especificados en esta sección.
Algunas notaciones:
- RH_A = Hash del router para Alice (32 bytes)
- RH_B = Hash del router para Bob (32 bytes)
Cifrado autenticado
Hay tres instancias de cifrado autenticado separadas (CipherStates). Una durante la fase de apretón de manos y dos (transmitir y recibir) para la fase de datos. Cada una tiene su propia clave desde un KDF.
Los datos cifrados y autenticados se representarán como
+----+----+----+----+----+----+----+----+
| |
+ +
| Datos cifrados y autenticados |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
ChaCha20/Poly1305
Formato de datos cifrados y autenticados.
Entradas para las funciones de cifrado y descifrado:
k :: 32 bytes de clave de cifrado, como se genera desde el KDF
nonce :: Nonce basado en contador, 12 bytes.
Comienza en 0 e incrementa para cada mensaje.
Los primeros cuatro bytes siempre son cero.
Los últimos ocho bytes son el contador, codificados en little-endian.
El valor máximo es 2**64 - 2.
La conexión debe cerrarse y reiniciarse después de que se alcance ese valor.
El valor 2**64 - 1 nunca debe enviarse.
ad :: En la fase de apretón de manos:
Datos asociados, 32 bytes.
El hash SHA256 de todos los datos anteriores.
En la fase de datos:
Bytes cero
datos :: Datos de texto plano, 0 o más bytes
Salida de la función de cifrado, entrada para la función de descifrado:
+----+----+----+----+----+----+----+----+
|Obfs Len | |
+----+----+ +
| Datos de ChaCha20 cifrados |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
| Poly1305 Código de autenticación de mensaje (MAC) |
+ (16 bytes) +
| 16 bytes |
+----+----+----+----+----+----+----+----+
Obfs Len :: Longitud de (datos cifrados + MAC) a seguir, 16 - 65535
Ofuscación utilizando SipHash (consulte a continuación)
No se utiliza en el mensaje 1 o 2, o en la parte 1 del mensaje 3, donde la longitud es fija
No se utiliza en la parte 1 del mensaje 3, ya que la longitud se especifica en el mensaje 1
datos cifrados :: Tamaño igual que los datos de texto plano, 0 - 65519 bytes
MAC :: Código de autenticación de mensaje Poly1305, 16 bytes
Para ChaCha20, lo que se describe aquí corresponde a RFC-7539 , que también se utiliza de manera similar en TLS RFC-7905 .
Notas
Dado que ChaCha20 es un cifrado de flujo, los textos planos no necesitan relleno. Se descartan los bytes adicionales de keystream.
La clave del cifrado (256 bits) se acuerda mediante el KDF SHA256. Los detalles del KDF para cada mensaje están en secciones separadas a continuación.
Los marcos ChaChaPoly para los mensajes 1, 2 y la primera parte del mensaje 3 son de tamaño conocido. A partir de la segunda parte del mensaje 3, los marcos son de tamaño variable. La longitud del marco del mensaje 3 parte 1 se especifica en el mensaje 1. A partir de la fase de datos, los marcos están precedidos por una longitud de dos bytes obfuscada con SipHash.
El relleno está fuera del marco de datos autenticados para los mensajes 1 y 2. El relleno se utiliza en el KDF para el siguiente mensaje, por lo que cualquier manipulación se detectará. A partir del mensaje 3, el relleno está dentro del marco de datos autenticados.
Manejo de errores AEAD
En los mensajes 1, 2 y partes 1 y 2 del mensaje 3, el tamaño del mensaje AEAD es conocido de antemano. En caso de fallo de autenticación AEAD, el destinatario debe detener el procesamiento de mensajes adicionales y cerrar la conexión sin responder. Esto debe ser un cierre anormal (TCP RST).
Para la resistencia a la exploración, en el mensaje 1, después de un fallo AEAD, Bob debe establecer un tiempo de espera aleatorio (rango TBD) y luego leer una cantidad aleatoria de bytes (rango TBD) antes de cerrar el socket. Bob debe mantener una lista negra de IPs con fallos repetidos.
En la fase de datos, el tamaño del mensaje AEAD es “cifrado” (ofuscado) con SipHash. Se debe tener cuidado para evitar crear un oráculo de descifrado. En caso de fallo de autenticación AEAD en la fase de datos, el destinatario debe establecer un tiempo de espera aleatorio (rango TBD) y luego leer una cantidad aleatoria de bytes (rango TBD). Después de la lectura o en el tiempo de espera de la lectura, el destinatario debe enviar una carga útil con un bloque de terminación que contenga un código de razón “Fallo AEAD” y cerrar la conexión.
Tome la misma acción de error para un valor de campo de longitud no válido en la fase de datos.
Función de derivación de claves (KDF) (para el mensaje de apretón de manos 1)
El KDF genera una clave de cifrado de fase de apretón de manos k desde el resultado de DH, utilizando HMAC-SHA256(clave, datos) como se define en RFC-2104 . Estas son las funciones InitializeSymmetric(), MixHash() y MixKey(), exactamente como se definen en la especificación de Noise.
Este es el patrón de mensaje "e":
// Defina el nombre del protocolo.
Establezca el nombre del protocolo = "Noise_XKaesobfse+hs2+hs3_25519_ChaChaPoly_SHA256"
(48 bytes, codificación US-ASCII, sin terminación NULL).
// Defina Hash h = 32 bytes
h = SHA256(nombre del protocolo);
Defina ck = clave de enlace de 32 bytes. Copie los datos de h en ck.
Establezca ck = h
Defina rs = clave estática de 32 bytes de Bob como publicada en el RouterInfo
// MixHash(prologo nulo)
h = SHA256(h);
// hasta aquí, todo puede precalcularse por Alice para todas las conexiones salientes
// Alice debe validar que la clave estática de Bob es un punto válido en la curva aquí.
// Clave estática de Bob
// MixHash(rs)
// || a continuación significa append
h = SHA256(h || rs);
// hasta aquí, todo puede precalcularse por Bob para todas las conexiones entrantes
Este es el patrón de mensaje "e":
Alice genera un nuevo par de claves efímeras e.
// Clave pública efímera X
// MixHash(e.pubkey)
// || a continuación significa append
h = SHA256(h || e.pubkey);
// h se utiliza como los datos asociados para el AEAD en el mensaje 1
// Retener el hash h para el KDF del mensaje 2
Fin del patrón de mensaje "e".
Este es el patrón de mensaje "es":
// DH(e, rs) == DH(s, re)
Defina el material de clave de entrada = resultado de DH de 32 bytes de la clave efímera de Alice y la clave estática de Bob
Establezca el material de clave de entrada = resultado de DH X25519
// MixKey(DH())
Defina temp_key = 32 bytes
Defina HMAC-SHA256(clave, datos) como en [RFC-2104](https://tools.ietf.org/html/rfc2104)
// Generar una clave temporal desde la clave de enlace y el resultado de DH
// ck es la clave de enlace, definida anteriormente
temp_key = HMAC-SHA256(ck, material de clave de entrada)
// sobrescribir el resultado de DH en la memoria, ya no es necesario
material de clave de entrada = (todos ceros)
// Salida 1
// Establecer una nueva clave de enlace desde la clave temporal
// byte() a continuación significa un byte único
ck = HMAC-SHA256(temp_key, byte(0x01)).
// Salida 2
// Generar la clave de cifrado k
Defina k = 32 bytes
// || a continuación significa append
// byte() a continuación significa un byte único
k = HMAC-SHA256(temp_key, ck || byte(0x02)).
// sobrescribir la clave temporal en la memoria, ya no es necesaria
temp_key = (todos ceros)
// retener la clave de enlace ck para el KDF del mensaje 2
Fin del patrón de mensaje "es".
1) SessionRequest
Alice envía a Bob.
Contenido de Noise: clave efímera X de Alice Carga útil de Noise: bloque de opciones de 16 bytes Carga útil no Noise: relleno aleatorio
(Propiedades de seguridad de carga)
XK(s, rs): Autenticación Confidencialidad
-> e, es 0 2
Autenticación: Ninguna (0).
Esta carga útil puede haber sido enviada por cualquier parte, incluido un atacante activo.
Confidencialidad: 2.
Cifrado para un destinatario conocido, confidencialidad perfecta hacia adelante para la comprometición del remitente solo, vulnerable a reproducción. Esta carga útil está cifrada en función solo de los DH que involucran la clave estática del destinatario. Si la clave privada estática del destinatario se compromete, incluso en una fecha posterior, esta carga útil puede descifrarse. Esta carga útil también puede reproducirse, ya que no hay contribución efímera del destinatario.
"e": Alice genera un nuevo par de claves efímeras y almacena el público en la variable e,
escribe la clave pública efímera en el búfer de mensaje como texto plano y hash la clave pública junto con el antiguo h para derivar un nuevo h.
"es": Se realiza un DH entre el par de claves efímeras de Alice y la clave estática de Bob.
El resultado se hash junto con el antiguo ck para derivar un nuevo ck y k, y n se establece en cero.
El valor X se cifra para garantizar la indistinguibilidad de la carga útil y la unicidad, que son medidas de contra-DPI necesarias. Utilizamos cifrado AES para lograr esto, en lugar de alternativas más complejas y lentas como elligator2. El cifrado asimétrico a la clave pública del router de Bob sería demasiado lento. El cifrado AES utiliza el hash del router de Bob como clave y el IV de Bob como publicado en la base de datos de la red.
El cifrado AES es solo para la resistencia a DPI. Cualquier parte que conozca el hash del router de Bob y el IV, que se publican en la base de datos de la red, puede descifrar el valor X en este mensaje.
Contenido sin procesar:
+----+----+----+----+----+----+----+----+
| |
+ ofuscado con RH_B +
| Clave X X25519 efímera AES-256-CBC cifrada |
+ (32 bytes) +
| |
+ +
| |
+----+----+----+----+----+----+----+----+
| Marco ChaChaPoly |
+ Datos cifrados y autenticados +
| 32 bytes +
+ k definido en KDF para mensaje 1 +
| n = 0; consulte KDF para datos asociados |
+ +
| |
+----+----+----+----+----+----+----+----+
| relleno autenticado sin cifrar |
~ (opcional) ~
| longitud definida en bloque de opciones |
+----+----+----+----+----+----+----+----+
X :: 32 bytes, clave X X25519 efímera AES-256-CBC cifrada, little-endian
clave: RH_B
iv: como publicado en la entrada de la base de datos de la red de Bob
relleno :: Datos aleatorios, 0 o más bytes.
La longitud total del mensaje debe ser de 65535 bytes o menos.
La longitud total del mensaje debe ser de 287 bytes o menos si
Bob está publicando su dirección como "NTCP"
(consulte la sección de detección de versión a continuación).
Alice y Bob utilizarán los datos de relleno en el KDF para el mensaje 2.
Está autenticado para que cualquier manipulación cause que el siguiente mensaje falle.
Datos sin cifrar (etiqueta de autenticación Poly1305 no mostrada):
+----+----+----+----+----+----+----+----+
| |
+ +
| X |
+ (32 bytes) +
| |
+ +
| |
+----+----+----+----+----+----+----+----+
| opciones |
+ (16 bytes) +
| |
+----+----+----+----+----+----+----+----+
| relleno autenticado sin cifrar |
+ (opcional) +
| longitud definida en bloque de opciones |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
X :: 32 bytes, clave X X25519 efímera, little-endian
opciones :: bloque de opciones, 16 bytes, consulte a continuación
relleno :: Datos aleatorios, 0 o más bytes.
La longitud total del mensaje debe ser de 65535 bytes o menos.
La longitud total del mensaje debe ser de 287 bytes o menos si
Bob está publicando su dirección como "NTCP"
(consulte la sección de detección de versión a continuación).
Alice y Bob utilizarán los datos de relleno en el KDF para el mensaje 2.
Está autenticado para que cualquier manipulación cause que el siguiente mensaje falle.
Bloque de opciones: Nota: Todos los campos son big-endian.
+----+----+----+----+----+----+----+----+
| id | ver| padLen | m3p2len | Rsvd(0) |
+----+----+----+----+----+----+----+----+
| tsA | Reserved (0) |
+----+----+----+----+----+----+----+----+
id :: 1 byte, el ID de la red (actualmente 2, excepto para redes de prueba)
A partir de 0.9.42. Consulte la propuesta 147.
ver :: 1 byte, versión del protocolo (actualmente 2)
padLen :: 2 bytes, longitud del relleno, 0 o más
Pautas de mínimo/máximo TBD. Tamaño de relleno aleatorio de 0 a 31 bytes mínimo?
(Distribución por determinar, consulte el Apéndice A.)
m3p2Len :: 2 bytes, longitud del segundo marco AEAD en SessionConfirmed
(mensaje 3 parte 2) Consulte las notas a continuación
Rsvd :: 2 bytes, establecido en 0 para la compatibilidad con opciones futuras
tsA :: 4 bytes, timestamp Unix, segundos sin firmar.
Se vuelve a wrap en 2106
Reserved :: 4 bytes, establecido en 0 para la compatibilidad con opciones futuras
Notas
Cuando la dirección publicada es “NTCP”, Bob admite NTCP y NTCP2 en el mismo puerto. Para la compatibilidad, cuando se inicia una conexión a una dirección publicada como “NTCP”, Alice debe limitar el tamaño máximo de este mensaje, incluido el relleno, a 287 bytes o menos. Esto facilita la detección automática del protocolo por parte de Bob. Cuando se publica como “NTCP2”, no hay restricción de tamaño. Consulte las secciones de direcciones publicadas y detección de versión a continuación.
El valor X único en el bloque AES inicial garantiza que el texto cifrado sea diferente para cada sesión.
Bob debe rechazar las conexiones donde el valor del timestamp esté demasiado alejado del tiempo actual. Llame al máximo tiempo delta “D”. Bob debe mantener una caché local de valores de apretón de manos utilizados previamente y rechazar duplicados, para prevenir ataques de reproducción. Los valores de la caché son dependientes de la implementación, sin embargo, el valor X de 32 bytes (o su equivalente cifrado) puede utilizarse.
Las claves efímeras de Diffie-Hellman nunca deben reutilizarse, para prevenir ataques criptográficos, y el reuso se rechazará como un ataque de reproducción. El “KE” y las opciones “auth” deben ser compatibles, es decir, el secreto compartido K debe ser del tamaño apropiado. Si se agregan más opciones “auth”, esto podría cambiar implícitamente el significado de la bandera “KE” para usar un KDF o un tamaño de truncamiento diferente.
Bob debe validar que la clave efímera de Alice es un punto válido en la curva aquí.
El relleno debe limitarse a una cantidad razonable. Bob puede rechazar conexiones con relleno excesivo. Bob especificará sus opciones de relleno en el mensaje 2. Pautas de mínimo/máximo TBD. Tamaño de relleno aleatorio de 0 a 31 bytes mínimo? (Distribución por determinar, consulte el Apéndice A.)
En caso de error, incluido el error AEAD, DH, timestamp, reproducción aparente o fallo de validación de clave, Bob debe detener el procesamiento de mensajes adicionales y cerrar la conexión sin responder. Esto debe ser un cierre anormal (TCP RST). Para la resistencia a la exploración, después de un fallo AEAD, Bob debe establecer un tiempo de espera aleatorio (rango TBD) y luego leer una cantidad aleatoria de bytes (rango TBD), antes de cerrar el socket.
Mitigación de DoS: el DH es una operación relativamente costosa. Como en el protocolo NTCP anterior, los routers deben tomar todas las medidas necesarias para prevenir el agotamiento de CPU o conexiones. Establezca límites en el número máximo de conexiones activas y en el número máximo de configuraciones de conexión en curso. Haga cumplir los tiempos de espera de lectura (tanto por lectura como total para “slowloris”). Limitar las conexiones repetidas o simultáneas desde la misma fuente. Mantener listas negras para fuentes que fallen repetidamente.
Para facilitar la detección rápida de versión y el apretón de manos, las implementaciones deben asegurarse de que Alice bufferice y luego envíe todo el contenido del primer mensaje de una vez, incluido el relleno. Esto aumenta la probabilidad de que los datos estén contenidos en un solo paquete TCP (a menos que se segmente por el OS o los intermediarios), y se reciban de una vez por Bob. Esto también es para la eficiencia y para asegurarse de la efectividad del relleno aleatorio.
“ver” campo: el protocolo Noise general, extensiones y especificaciones de protocolo NTCP, incluida la especificación de carga útil, que indica NTCP2. Este campo puede utilizarse para indicar el soporte para cambios futuros.
Longitud del mensaje 3 parte 2: esta es el tamaño del segundo marco AEAD (incluido el MAC de 16 bytes) que contendrá la información del router de Alice y el relleno opcional que se enviará en el mensaje SessionConfirmed. Como los routers generan y publican periódicamente su información del router, el tamaño de la información del router actual puede cambiar antes de que se envíe el mensaje 3. Las implementaciones deben elegir una de dos estrategias: a) guardar la información del router actual para enviarla en el mensaje 3, para que se conozca el tamaño; b) aumentar el tamaño especificado lo suficiente como para permitir un posible aumento en el tamaño de la información del router, y siempre agregar relleno cuando se envíe el mensaje 3. En cualquier caso, la longitud “m3p2len” incluida en el mensaje 1 debe ser exactamente el tamaño de ese marco cuando se envíe en el mensaje 3.
Bob debe fallar la conexión si queda algún dato entrante después de validar el mensaje 1 y leer el relleno. No debe haber datos adicionales de Alice, ya que Bob no ha respondido con el mensaje 2 aún.
El campo ID de la red se utiliza para identificar rápidamente las conexiones entre redes. Si este campo es distinto de cero y no coincide con el ID de la red de Bob, Bob debe desconectar y bloquear futuras conexiones. A partir de 0.9.42. Consulte la propuesta 147 para más información.
Función de derivación de claves (KDF) (para el mensaje de apretón de manos 2 y mensaje 3 parte 1)
// tome h guardado desde el KDF del mensaje 1
// MixHash(ciphertext)
h = SHA256(h || 32 bytes de carga útil cifrada del mensaje 1)
// MixHash(padding)
// Solo si la longitud del relleno es distinta de cero
h = SHA256(h || relleno aleatorio del mensaje 1)
// h se utiliza como los datos asociados para el AEAD en el mensaje 2
// Retener el hash h para el KDF del mensaje 3
Este es el patrón de mensaje "e":
Bob genera un nuevo par de claves efímeras e.
// h es desde el KDF del mensaje 1
// Clave pública efímera Y
// MixHash(e.pubkey)
// || a continuación significa append
h = SHA256(h || e.pubkey);
// h se utiliza como los datos asociados para el AEAD en el mensaje 2
// Retener el hash h para el KDF del mensaje 3
Fin del patrón de mensaje "e".
Este es el patrón de mensaje "ee":
// DH(e, re)
Defina el material de clave de entrada = resultado de DH de 32 bytes de la clave efímera de Alice y la clave efímera de Bob
Establezca el material de clave de entrada = resultado de DH X25519
// sobrescribir la clave efímera de Alice en la memoria, ya no es necesaria
// Alice:
e(público y privado) = (todos ceros)
// Bob:
re = (todos ceros)
// MixKey(DH())
Defina temp_key = 32 bytes
Defina HMAC-SHA256(clave, datos) como en [RFC-2104](https://tools.ietf.org/html/rfc2104)
// Generar una clave temporal desde la clave de enlace y el resultado de DH
// ck es la clave de enlace, desde el KDF del mensaje 1
temp_key = HMAC-SHA256(ck, material de clave de entrada)
// sobrescribir el resultado de DH en la memoria, ya no es necesario
material de clave de entrada = (todos ceros)
// Salida 1
// Establecer una nueva clave de enlace desde la clave temporal
// byte() a continuación significa un byte único
ck = HMAC-SHA256(temp_key, byte(0x01)).
// Salida 2
// Generar la clave de cifrado k
Defina k = 32 bytes
// || a continuación significa append
// byte() a continuación significa un byte único
k = HMAC-SHA256(temp_key, ck || byte(0x02)).
// sobrescribir la clave temporal en la memoria, ya no es necesaria
temp_key = (todos ceros)
// retener la clave de enlace ck para el KDF del mensaje 3
Fin del patrón de mensaje "ee".
2) SessionCreated
Bob envía a Alice.
Contenido de Noise: clave efímera Y de Bob Carga útil de Noise: bloque de opciones de 16 bytes Carga útil no Noise: relleno aleatorio
(Propiedades de seguridad de carga)
XK(s, rs): Autenticación Confidencialidad
<- e, ee 2 1
Autenticación: 2.
Autenticación del remitente resistente a la impersonación por comprometimiento de clave (KCI).
La autenticación del remitente se basa en un DH efímero-estático ("es" o "se")
entre el par de claves estáticas del remitente y el par de claves efímeras del destinatario.
Asumiendo que las claves privadas correspondientes son seguras, esta autenticación no puede ser falsificada.
Confidencialidad: 1.
Cifrado para un destinatario efímero.
Esta carga útil tiene confidencialidad perfecta hacia adelante, ya que el cifrado involucra un DH efímero-efímero ("ee").
Sin embargo, el remitente no ha autenticado al destinatario,
por lo que esta carga útil podría enviarse a cualquier parte, incluido un atacante activo.
"e": Bob genera un nuevo par de claves efímeras y almacena el público en la variable e,
escribe la clave pública efímera en el búfer de mensaje como texto plano y hash la clave pública junto con el antiguo h para derivar un nuevo h.
"ee": Se realiza un DH entre el par de claves efímeras de Bob y el par de claves efímeras de Alice.
El resultado se hash junto con el antiguo ck para derivar un nuevo ck y k, y n se establece en cero.
El valor Y se cifra para garantizar la indistinguibilidad de la carga útil y la unicidad, que son medidas de contra-DPI necesarias. Utilizamos cifrado AES para lograr esto, en lugar de alternativas más complejas y lentas como elligator2. El cifrado asimétrico a la clave pública del router de Alice sería demasiado lento. El cifrado AES utiliza el hash del router de Bob como clave y el estado AES del mensaje 1 (que se inicializó con el IV de Bob como publicado en la base de datos de la red).
El cifrado AES es solo para la resistencia a DPI. Cualquier parte que conozca el hash del router de Bob y el IV, que se publican en la base de datos de la red, y capturó los primeros 32 bytes del mensaje 1, puede descifrar el valor Y en este mensaje.
Contenido sin procesar:
+----+----+----+----+----+----+----+----+
| |
+ ofuscado con RH_B +
| Clave Y X25519 efímera AES-256-CBC cifrada |
+ (32 bytes) +
| |
+ +
| |
+----+----+----+----+----+----+----+----+
| Marco ChaChaPoly |
+ Datos cifrados y autenticados +
| 32 bytes +
+ k definido en KDF para mensaje 2 +
| n = 0; consulte KDF para datos asociados |
+ +
| |
+----+----+----+----+----+----+----+----+
| relleno autenticado sin cifrar |
+ (opcional) +
| longitud definida en bloque de opciones |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
Y :: 32 bytes, clave Y X25519 efímera AES-256-CBC cifrada, little-endian
clave: RH_B
iv: Utilizando el estado AES del mensaje 1
Datos sin cifrar (etiqueta de autenticación Poly1305 no mostrada):
+----+----+----+----+----+----+----+----+
| |
+ +
| Y |
+ (32 bytes) +
| |
+ +
| |
+----+----+----+----+----+----+----+----+
| opciones |
+ (16 bytes) +
| |
+----+----+----+----+----+----+----+----+
| relleno autenticado sin cifrar |
+ (opcional) +
| longitud definida en bloque de opciones |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
Y :: 32 bytes, clave Y X25519 efímera, little-endian
opciones :: bloque de opciones, 16 bytes, consulte a continuación
relleno :: Datos aleatorios, 0 o más bytes.
La longitud total del mensaje debe ser de 65535 bytes o menos.
Alice y Bob utilizarán los datos de relleno en el KDF para el mensaje 3 parte 1.
Está autenticado para que cualquier manipulación cause que el siguiente mensaje falle.
Notas
Alice debe validar que la clave efímera de Bob es un punto válido en la curva aquí.
El relleno debe limitarse a una cantidad razonable. Alice puede rechazar conexiones con relleno excesivo. Alice especificará sus opciones de relleno en el mensaje 3. Pautas de mínimo/máximo TBD. Tamaño de relleno aleatorio de 0 a 31 bytes mínimo? (Distribución por determinar, consulte el Apéndice A.)
En caso de error, incluido el error AEAD, DH, timestamp, reproducción aparente o fallo de validación de clave, Alice debe detener el procesamiento de mensajes adicionales y cerrar la conexión sin responder. Esto debe ser un cierre anormal (TCP RST).
Para facilitar el apretón de manos rápido, las implementaciones deben asegurarse de que Bob bufferice y luego envíe todo el contenido del primer mensaje de una vez, incluido el relleno. Esto aumenta la probabilidad de que los datos estén contenidos en un solo paquete TCP (a menos que se segmente por el OS o los intermediarios), y se reciban de una vez por Alice. Esto también es para la eficiencia y para asegurarse de la efectividad del relleno aleatorio.
Alice debe fallar la conexión si queda algún dato entrante después de validar el mensaje 2 y leer el relleno. No debe haber datos adicionales de Bob, ya que Alice no ha respondido con el mensaje 3 aún.
Bloque de opciones: Nota: Todos los campos son big-endian.
+----+----+----+----+----+----+----+----+
| Rsvd(0) | padLen | Reserved (0) |
+----+----+----+----+----+----+----+----+
| tsB | Reserved (0) |
+----+----+----+----+----+----+----+----+
Reserved :: 10 bytes total, establecido en 0 para la compatibilidad con opciones futuras
padLen :: 2 bytes, big-endian, longitud del relleno, 0 o más
Pautas de mínimo/máximo TBD. Tamaño de relleno aleatorio de 0 a 31 bytes mínimo? (Distribución por determinar, consulte el Apéndice A.)
tsB :: 4 bytes, big-endian, timestamp Unix, segundos sin firmar.
Se vuelve a wrap en 2106
Notas
- Alice debe rechazar conexiones donde el valor del timestamp esté demasiado alejado del tiempo actual. Llame al máximo tiempo delta “D”. Alice debe mantener una caché local de valores de apretón de manos utilizados previamente y rechazar duplicados, para prevenir ataques de reproducción. Los valores de la caché deben tener una duración de al menos 2*D. Los valores de la caché son dependientes de la implementación, sin embargo, el valor Y de 32 bytes (o su equivalente cifrado) puede utilizarse.
Problemas
- ¿Incluir opciones de relleno mínimo/máximo aquí?
Cifrado para el mensaje de apretón de manos 3 parte 1, utilizando el KDF del mensaje 2)
// tome h guardado desde el KDF del mensaje 2
// MixHash(ciphertext)
h = SHA256(h || 24 bytes de carga útil cifrada del mensaje 2)
// MixHash(padding)
// Solo si la longitud del relleno es distinta de cero
h = SHA256(h || relleno aleatorio del mensaje 2)
// h se utiliza como los datos asociados para el AEAD en el mensaje 3 parte 1, a continuación
Este es el patrón de mensaje "s":
Defina s = clave pública estática de Alice, 32 bytes
// EncryptAndHash(s.publickey)
// EncryptWithAd(h, s.publickey)
// AEAD_ChaCha20_Poly1305(key, nonce, associatedData, data)
// k es desde el mensaje 1
// n es 1
ciphertext = AEAD_ChaCha20_Poly1305(k, n++, h, s.publickey)
// MixHash(ciphertext)
// || a continuación significa append
h = SHA256(h || ciphertext);
// h se utiliza como los datos asociados para el AEAD en el mensaje 3 parte 2
Fin del patrón de mensaje "s".
Función de derivación de claves (KDF) (para el mensaje de apretón de manos 3 parte 2)
Este es el patrón de mensaje "se":
// DH(s, re) == DH(e, rs)
Defina el material de clave de entrada = resultado de DH de 32 bytes de la clave estática de Alice y la clave efímera de Bob
Establezca el material de clave de entrada = resultado de DH X25519
// sobrescribir la clave efímera de Bob en la memoria, ya no es necesaria
// Alice:
re = (todos ceros)
// Bob:
e(público y privado) = (todos ceros)
// MixKey(DH())
Defina temp_key = 32 bytes
Defina HMAC-SHA256(clave, datos) como en [RFC-2104](https://tools.ietf.org/html/rfc2104)
// Generar una clave temporal desde la clave de enlace y el resultado de DH
// ck es la clave de enlace, desde el KDF del mensaje 1
temp_key = HMAC-SHA256(ck, material de clave de entrada)
// sobrescribir el resultado de DH en la memoria, ya no es necesario
material de clave de entrada = (todos ceros)
// Salida 1
// Establecer una nueva clave de enlace desde la clave temporal
// byte() a continuación significa un byte único
ck = HMAC-SHA256(temp_key, byte(0x01)).
// Salida 2
// Generar la clave de cifrado k
Defina k = 32 bytes
// || a continuación significa append
// byte() a continuación significa un byte único
k = HMAC-SHA256(temp_key, ck || byte(0x02)).
// h desde el mensaje 3 parte 1 se utiliza como los datos asociados para el AEAD en el mensaje 3 parte 2
// EncryptAndHash(payload)
// EncryptWithAd(h, payload)
// AEAD_ChaCha20_Poly1305(key, nonce, associatedData, data)
// n es 0
ciphertext = AEAD_ChaCha20_Poly1305(k, n++, h, payload)
// MixHash(ciphertext)
// || a continuación significa append
h = SHA256(h || ciphertext);
// retener la clave de enlace ck para el KDF de la fase de datos
// retener el hash h para el KDF de la clave simétrica adicional (SipHash) de la fase de datos
Fin del patrón de mensaje "se".
// sobrescribir la clave temporal en la memoria, ya no es necesaria
temp_key = (todos ceros)
3) SessionConfirmed
Alice envía a Bob.
Contenido de Noise: clave estática de Alice Carga útil de Noise: información del router de Alice y relleno aleatorio Carga útil no Noise: none
(Propiedades de seguridad de carga)
XK(s, rs): Autenticación Confidencialidad
-> s, se 2 5
Autenticación: 2.
Autenticación del remitente resistente a la impersonación por comprometimiento de clave (KCI). La autenticación del remitente se basa en un DH efímero-estático ("es" o "se") entre el par de claves estáticas del remitente y el par de claves efímeras del destinatario. Asumiendo que las claves privadas correspondientes son seguras, esta autenticación no puede ser falsificada.
Confidencialidad: 5.
Cifrado para un destinatario conocido, confidencialidad perfecta hacia adelante. Esta carga útil está cifrada en función de un DH efímero-efímero, así como de un DH efímero-estático con el par de claves estáticas del destinatario. Asumiendo que las claves privadas efímeras son seguras, y el destinatario no está siendo activamente impersonado por un atacante que ha robado su clave privada estática, esta carga útil no puede ser descifrada.
"s": Alice escribe su clave pública estática en el búfer de mensaje, cifrándola, y hash la salida junto con el antiguo h para derivar un nuevo h.
"se": Se realiza un DH entre el par de claves estáticas de Alice y el par de claves efímeras de Bob. El resultado se hash junto con el antiguo ck para derivar un nuevo ck y k, y n se establece en cero.
Este contiene dos marcos ChaChaPoly. El primero es la clave pública estática de Alice cifrada. El segundo es la carga útil de Noise: la información del router de Alice cifrada, opciones opcionales y relleno opcional. Utilizan claves diferentes, porque la función MixKey() se llama entre ellas.
Contenido sin procesar:
+----+----+----+----+----+----+----+----+
| |
+ Marco ChaChaPoly (48 bytes) +
| Datos cifrados y autenticados |
+ Clave estática S de Alice +
| (32 bytes) |
+ +
| k definido en KDF para mensaje 2 |
+ n = 1 +
| consulte KDF para datos asociados |
+ +
| |
+----+----+----+----+----+----+----+----+
| |
+ Longitud especificada en mensaje 1 +
| |
+ Marco ChaChaPoly +
| Datos cifrados y autenticados +
| Información del router de Alice |
+ utilizando formato de bloque 2 +
| Opciones de Alice (opcional) |
+ utilizando formato de bloque 1 +
| Relleno aleatorio |
+ utilizando formato de bloque 254 +
| |
+ +
| k definido en KDF para mensaje 3 parte 2 |
+ n = 0 +
| consulte KDF para datos asociados |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
S :: 32 bytes, clave estática de Alice X25519 ChaChaPoly cifrada, little-endian
dentro de marco ChaChaPoly de 48 bytes
Datos sin cifrar (etiquetas de autenticación Poly1305 no mostradas):
+----+----+----+----+----+----+----+----+
| |
+ +
| S |
+ Clave estática de Alice +
| (32 bytes) |
+ +
| +
+----+----+----+----+----+----+----+----+
| |
+ +
| |
+ +
| Bloque de información del router de Alice |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
| |
+ Bloque de opciones de Alice (opcional) +
| |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
| |
+ Bloque de relleno aleatorio (opcional) +
| |
~ . . . ~
| |
+----+----+----+----+----+----+----+----+
S :: 32 bytes, clave estática de Alice X25519, little-endian
Notas
Bob debe realizar la validación habitual de la información del router. Asegurarse de que el tipo de firma sea compatible, verificar la firma, verificar que el timestamp esté dentro de los límites y cualquier otra verificación necesaria.
Bob debe verificar que la clave estática de Alice recibida en el primer marco coincida con la clave estática en la información del router. Bob debe buscar primero la información del router para una dirección del router NTCP o NTCP2 con una versión (v) de opción coincidente. Consulte las secciones de información del router publicada y no publicada a continuación.
Si Bob tiene una versión anterior de la información del router de Alice en su netdb, verificar que la clave estática en la información del router sea la misma en ambos, si está presente, y si la versión anterior es menos antigua que XXX (consulte el tiempo de rotación de claves a continuación)
Bob debe validar que la clave estática de Alice es un punto válido en la curva aquí.
Debe incluirse opciones para especificar parámetros de relleno.
En caso de error, incluido el error AEAD, RI, DH, timestamp o fallo de validación de clave, Bob debe detener el procesamiento de mensajes adicionales y cerrar la conexión sin responder. Esto debe ser un cierre anormal (TCP RST).
Para facilitar el apretón de manos rápido, las implementaciones deben asegurarse de que Alice bufferice y luego envíe todo el contenido del tercer mensaje de una vez, incluidos ambos marcos AEAD. Esto aumenta la probabilidad de que los datos estén contenidos en un solo paquete TCP (a menos que se segmente por el OS o los intermediarios), y se reciban de una vez por Bob. Esto también es para la eficiencia y para asegurarse de la efectividad del relleno aleatorio.
Longitud del marco del mensaje 3 parte 2: la longitud de este marco (incluido el MAC) que se enviará en el mensaje SessionConfirmed. Como los routers generan y publican periódicamente su información del router, el tamaño de la información del router actual puede cambiar antes de que se envíe el mensaje 3. Las implementaciones deben elegir una de dos estrategias: a) guardar la información del router actual para enviarla en el mensaje 3, para que se conozca el tamaño; b) aumentar el tamaño especificado lo suficiente como para permitir un posible aumento en el tamaño de la información del router, y siempre agregar relleno cuando se envíe el mensaje 3. En cualquier caso, la longitud “m3p2len” incluida en el mensaje 1 debe ser exactamente el tamaño de ese marco cuando se envíe en el mensaje 3.
El mensaje 3 parte 2 debe contener 1 a 3 bloques en el siguiente orden:
- Bloque de información del router de Alice (obligatorio)
- Bloque de opciones (opcional)
- Bloque de relleno (opcional) Este marco nunca debe contener ningún otro tipo de bloque.
El relleno del mensaje 3 parte 2 no es necesario si Alice adjunta un marco de la fase de datos (que opcionalmente contiene relleno) al final del mensaje 3 y envía ambos al mismo tiempo, ya que aparecerá como un gran flujo de bytes para un observador. Como Alice generalmente, pero no siempre, tiene un mensaje I2NP para enviar a Bob (eso es por lo que se conectó a él), esta es la implementación recomendada, para la eficiencia y para asegurarse de la efectividad del relleno aleatorio.
La longitud total de ambos marcos AEAD del mensaje 3 (partes 1 y 2) es de 65535 bytes; la parte 1 es de 48 bytes, por lo que la longitud máxima del marco de la parte 2 es de 65487; la longitud máxima de texto plano de la parte 2, excluyendo el MAC, es de 65471.
Función de derivación de claves (KDF) (para la fase de datos)
La fase de datos utiliza una entrada de datos asociados de longitud cero.
El KDF genera dos claves de cifrado k_ab y k_ba desde la clave de enlace ck, utilizando HMAC-SHA256(clave, datos) como se define en RFC-2104 . Esto es la función Split(), exactamente como se define en la especificación de Noise.
ck = desde la fase de apretón de manos
// k_ab, k_ba = HKDF(ck, zerolen)
// ask_master = HKDF(ck, zerolen, info="ask")
// zerolen es un array de bytes de longitud cero
temp_key = HMAC-SHA256(ck, zerolen)
// sobrescribir la clave de enlace en la memoria, ya no es necesaria
ck = (todos ceros)
// Salida 1
// clave de cifrado,