Aperçu
NTCP2 est un protocole d’accord de clés authentifié qui améliore la résistance de NTCP à diverses formes d’identification automatisée et d’attaques.
NTCP2 est conçu pour la flexibilité et la coexistence avec NTCP. Il peut être pris en charge sur le même port que NTCP, ou sur un port différent, ou sans support NTCP simultané du tout. Voir la section Informations du routeur publiées ci-dessous pour plus de détails.
Comme pour les autres transports I2P, NTCP2 est défini uniquement pour le transport point-à-point (router à router) des messages I2NP. Ce n’est pas un canal de données à usage général.
NTCP2 est pris en charge à partir de la version 0.9.36. Voir Prop111 pour la proposition originale, incluant la discussion de contexte et des informations supplémentaires.
Framework de Protocole Noise
NTCP2 utilise le Noise Protocol Framework NOISE (Révision 33, 2017-10-04). Noise a des propriétés similaires au protocole Station-To-Station STS , qui est la base du protocole SSU . Dans le jargon de Noise, Alice est l’initiateur, et Bob est le répondeur.
NTCP2 est basé sur le protocole Noise Noise_XK_25519_ChaChaPoly_SHA256. (L’identifiant réel pour la fonction de dérivation de clé initiale est “Noise_XKaesobfse+hs2+hs3_25519_ChaChaPoly_SHA256” pour indiquer les extensions I2P - voir la section KDF 1 ci-dessous) Ce protocole Noise utilise les primitives suivantes :
- Modèle de négociation : XK Alice transmet sa clé à Bob (X) Alice connaît déjà la clé statique de Bob (K)
- Fonction DH : X25519 X25519 DH avec une longueur de clé de 32 octets comme spécifié dans RFC-7748 .
- Fonction de chiffrement : ChaChaPoly AEAD_CHACHA20_POLY1305 comme spécifié dans RFC-7539 section 2.8. Nonce de 12 octets, avec les 4 premiers octets définis à zéro.
- Fonction de hachage : SHA256 Hachage standard de 32 octets, déjà utilisé de manière extensive dans I2P.
Ajouts au Framework
NTCP2 définit les améliorations suivantes à Noise_XK_25519_ChaChaPoly_SHA256. Celles-ci suivent généralement les directives de la section 13 de NOISE .
- Les clés éphémères en clair sont obscurcies avec un chiffrement AES utilisant une clé et un IV connus. 2) Un remplissage aléatoire en clair est ajouté aux messages 1 et 2. Le remplissage en clair est inclus dans le calcul du hachage de la négociation (MixHash). Voir les sections KDF ci-dessous pour le message 2 et la partie 1 du message 3. Un remplissage AEAD aléatoire est ajouté au message 3 et aux messages de la phase de données. 3) Un champ de longueur de trame de deux octets est ajouté, comme requis pour Noise sur TCP, et comme dans obfs4. Ceci est utilisé uniquement dans les messages de la phase de données. Les trames AEAD des messages 1 et 2 ont une longueur fixe. La trame AEAD de la partie 1 du message 3 a une longueur fixe. La longueur de la trame AEAD de la partie 2 du message 3 est spécifiée dans le message 1. 4) Le champ de longueur de trame de deux octets est obscurci avec SipHash-2-4, comme dans obfs4. 5) Le format de la charge utile est défini pour les messages 1, 2, 3, et la phase de données. Bien sûr, ceux-ci ne sont pas définis dans le framework.
Messages
Tous les messages NTCP2 font 65537 octets ou moins en longueur. Le format de message est basé sur les messages Noise, avec des modifications pour l’encadrement et l’indiscernabilité. Les implémentations utilisant des bibliothèques Noise standard peuvent avoir besoin de pré-traiter les messages reçus vers/depuis le format de message Noise. Tous les champs chiffrés sont des textes chiffrés AEAD.
La séquence d’établissement est la suivante :
Alice Bob
SessionRequest -------------------> <------------------- SessionCreated SessionConfirmed ----------------->
En utilisant la terminologie Noise, la séquence d’établissement et de données est la suivante : (Propriétés de sécurité de la charge utile de Noise )
XK(s, rs): Authentication Confidentiality
<- s \... -> e, es 0 2 <- e, ee 2 1 -> s, se 2 5 <- 2 5
Une fois qu’une session a été établie, Alice et Bob peuvent échanger des messages Data.
Tous les types de messages (SessionRequest, SessionCreated, SessionConfirmed, Data et TimeSync) sont spécifiés dans cette section.
Quelques notations :
- RH_A = Router Hash for Alice (32 bytes)
- RH_B = Router Hash for Bob (32 bytes)
Chiffrement authentifié
Il y a trois instances de chiffrement authentifié séparées (CipherStates). Une pendant la phase de négociation, et deux (transmission et réception) pour la phase de données. Chacune a sa propre clé provenant d’une KDF.
Les données chiffrées/authentifiées seront représentées comme
+----+----+----+----+----+----+----+----+
| |
+ + | Encrypted and authenticated data | ~ . . . ~ | | +----+----+----+----+----+----+----+----+
ChaCha20/Poly1305
Format de données chiffré et authentifié.
Entrées des fonctions de chiffrement/déchiffrement :
k :: 32 byte cipher key, as generated from KDF
nonce :: Counter-based nonce, 12 bytes.
Starts at 0 and incremented for each message. First four bytes are always zero. Last eight bytes are the counter, little-endian encoded. Maximum value is 2**64 - 2. Connection must be dropped and restarted after it reaches that value. The value 2**64 - 1 must never be sent.
ad :: In handshake phase:
Associated data, 32 bytes. The SHA256 hash of all preceding data. In data phase: Zero bytes
data :: Plaintext data, 0 or more bytes
Sortie de la fonction de chiffrement, entrée de la fonction de déchiffrement :
+----+----+----+----+----+----+----+----+
[|Obfs Len |](##SUBST##|Obfs Len |) | +----+----+ + | ChaCha20 encrypted data | ~ . . . ~ | | +----+----+----+----+----+----+----+----+ | Poly1305 Message Authentication Code | + (MAC) + | 16 bytes | +----+----+----+----+----+----+----+----+
Obfs Len :: Length of (encrypted data + MAC) to follow, 16 - 65535
: Obfuscation using SipHash (see below) Not used in message 1 or 2, or message 3 part 1, where the length is fixed Not used in message 3 part 1, as the length is specified in message 1
encrypted data :: Same size as plaintext data, 0 - 65519 bytes
MAC :: Poly1305 message authentication code, 16 bytes
Pour ChaCha20, ce qui est décrit ici correspond à RFC-7539 , qui est également utilisé de manière similaire dans TLS RFC-7905 .
Notes
- Puisque ChaCha20 est un chiffrement par flot, les textes en clair n’ont pas besoin d’être complétés. Les octets de flux de clés supplémentaires sont supprimés.
- La clé pour le chiffrement (256 bits) est convenue au moyen du KDF SHA256. Les détails du KDF pour chaque message sont dans des sections séparées ci-dessous.
- Les trames ChaChaPoly pour les messages 1, 2, et la première partie du message 3, ont une taille connue. À partir de la deuxième partie du message 3, les trames ont une taille variable. La taille de la partie 1 du message 3 est spécifiée dans le message 1. À partir de la phase de données, les trames sont précédées d’une longueur de deux octets obscurcie avec SipHash comme dans obfs4.
- Le remplissage est en dehors de la trame de données authentifiée pour les messages 1 et 2. Le remplissage est utilisé dans le KDF pour le message suivant donc la manipulation sera détectée. À partir du message 3, le remplissage est à l’intérieur de la trame de données authentifiée.
Gestion des erreurs AEAD
- Dans les messages 1, 2, et les parties 1 et 2 du message 3, la taille du message AEAD est connue à l’avance. En cas d’échec d’authentification AEAD, le destinataire doit arrêter tout traitement ultérieur de message et fermer la connexion sans répondre. Cela devrait être une fermeture anormale (TCP RST).
- Pour la résistance au sondage, dans le message 1, après un échec AEAD, Bob devrait définir un délai d’attente aléatoire (plage à déterminer) puis lire un nombre aléatoire d’octets (plage à déterminer) avant de fermer le socket. Bob devrait maintenir une liste noire d’IP avec des échecs répétés.
- Dans la phase de données, la taille du message AEAD est “chiffrée” (obfusquée) avec SipHash. Il faut prendre soin d’éviter de créer un oracle de déchiffrement. En cas d’échec d’authentification AEAD en phase de données, le destinataire devrait définir un délai d’attente aléatoire (plage à déterminer) puis lire un nombre aléatoire d’octets (plage à déterminer). Après la lecture, ou en cas de dépassement du délai de lecture, le destinataire devrait envoyer une charge utile avec un bloc de terminaison contenant un code de raison “échec AEAD”, et fermer la connexion.
- Prendre la même action d’erreur pour une valeur de champ de longueur invalide dans la phase de données.
Fonction de dérivation de clé (KDF) (pour le message de handshake 1)
Le KDF génère une clé de chiffrement de phase de handshake k à partir du résultat DH, en utilisant HMAC-SHA256(key, data) tel que défini dans RFC-2104 . Il s’agit des fonctions InitializeSymmetric(), MixHash(), et MixKey(), exactement telles que définies dans la spécification Noise.
This is the "e" message pattern:
// Define protocol_name. Set protocol_name = "Noise_XKaesobfse+hs2+hs3_25519_ChaChaPoly_SHA256" (48 bytes, US-ASCII encoded, no NULL termination).
// Define Hash h = 32 bytes h = SHA256(protocol_name);
Define ck = 32 byte chaining key. Copy the h data to ck. Set ck = h
Define rs = Bob's 32-byte static key as published in the RouterInfo
// MixHash(null prologue) h = SHA256(h);
// up until here, can all be precalculated by Alice for all outgoing connections
// Alice must validate that Bob's static key is a valid point on the curve here.
// Bob static key // MixHash(rs) // || below means append h = SHA256(h || rs);
// up until here, can all be precalculated by Bob for all incoming connections
This is the "e" message pattern:
Alice generates her ephemeral DH key pair e.
// Alice ephemeral key X // MixHash(e.pubkey) // || below means append h = SHA256(h || e.pubkey);
// h is used as the associated data for the AEAD in message 1 // Retain the Hash h for the message 2 KDF
End of "e" message pattern.
This is the "es" message pattern:
// DH(e, rs) == DH(s, re) Define input_key_material = 32 byte DH result of Alice's ephemeral key and Bob's static key Set input_key_material = X25519 DH result
// MixKey(DH())
Define temp_key = 32 bytes Define HMAC-SHA256(key, data) as in [RFC-2104](https://tools.ietf.org/html/rfc2104) // Generate a temp key from the chaining key and DH result // ck is the chaining key, defined above temp_key = HMAC-SHA256(ck, input_key_material) // overwrite the DH result in memory, no longer needed input_key_material = (all zeros)
// Output 1 // Set a new chaining key from the temp key // byte() below means a single byte ck = HMAC-SHA256(temp_key, byte(0x01)).
// Output 2 // Generate the cipher key k Define k = 32 bytes // || below means append // byte() below means a single byte k = HMAC-SHA256(temp_key, ck || byte(0x02)). // overwrite the temp_key in memory, no longer needed temp_key = (all zeros)
// retain the chaining key ck for message 2 KDF
End of "es" message pattern.
1) SessionRequest
Alice envoie à Bob.
Contenu Noise : clé éphémère X d’Alice Charge utile Noise : bloc d’options de 16 octets Charge utile non-Noise : rembourrage aléatoire
(Propriétés de sécurité de la charge utile de Noise )
XK(s, rs): Authentication Confidentiality
-> e, es 0 2
Authentication: None (0). This payload may have been sent by any party, including an active attacker.
Confidentiality: 2. Encryption to a known recipient, forward secrecy for sender compromise only, vulnerable to replay. This payload is encrypted based only on DHs involving the recipient's static key pair. If the recipient's static private key is compromised, even at a later date, this payload can be decrypted. This message can also be replayed, since there's no ephemeral contribution from the recipient.
"e": Alice generates a new ephemeral key pair and stores it in the e
: variable, writes the ephemeral public key as cleartext into the message buffer, and hashes the public key along with the old h to derive a new h.
"es": A DH is performed between the Alice's ephemeral key pair and the
: Bob's static key pair. The result is hashed along with the old ck to derive a new ck and k, and n is set to zero.
La valeur X est chiffrée pour garantir l’indiscernabilité et l’unicité de la charge utile, qui sont des contre-mesures DPI nécessaires. Nous utilisons le chiffrement AES pour y parvenir, plutôt que des alternatives plus complexes et plus lentes comme elligator2. Le chiffrement asymétrique vers la clé publique du router de Bob serait beaucoup trop lent. Le chiffrement AES utilise le hash du router de Bob comme clé et l’IV de Bob tel que publié dans la base de données réseau.
Le chiffrement AES sert uniquement à la résistance contre l’inspection approfondie des paquets (DPI). Toute partie connaissant le hash du router de Bob et l’IV, qui sont publiés dans la base de données réseau, peut déchiffrer la valeur X de ce message.
Le remplissage n’est pas chiffré par Alice. Il peut être nécessaire pour Bob de déchiffrer le remplissage, pour empêcher les attaques temporelles.
Contenu brut :
+----+----+----+----+----+----+----+----+
| |
+ obfuscated with RH_B + | AES-CBC-256 encrypted X | + (32 bytes) + | | + + | | +----+----+----+----+----+----+----+----+ | | + + | ChaChaPoly frame | + (32 bytes) + | k defined in KDF for message 1 | + n = 0 + | see KDF for associated data | +----+----+----+----+----+----+----+----+ | unencrypted authenticated | ~ padding (optional) ~ | length defined in options block | +----+----+----+----+----+----+----+----+
X :: 32 bytes, AES-256-CBC encrypted X25519 ephemeral key, little endian
: key: RH_B iv: As published in Bobs network database entry
padding :: Random data, 0 or more bytes.
: Total message length must be 65535 bytes or less. Total message length must be 287 bytes or less if Bob is publishing his address as NTCP (see Version Detection section below). Alice and Bob will use the padding data in the KDF for message 2. It is authenticated so that any tampering will cause the next message to fail.
Données non chiffrées (tag d’authentification Poly1305 non affiché) :
+----+----+----+----+----+----+----+----+
| |
+ + | X | + (32 bytes) + | | + + | | +----+----+----+----+----+----+----+----+ | options | + (16 bytes) + | | +----+----+----+----+----+----+----+----+ | unencrypted authenticated | + padding (optional) + | length defined in options block | ~ . . . ~ | | +----+----+----+----+----+----+----+----+
X :: 32 bytes, X25519 ephemeral key, little endian
options :: options block, 16 bytes, see below
padding :: Random data, 0 or more bytes.
: Total message length must be 65535 bytes or less. Total message length must be 287 bytes or less if Bob is publishing his address as "NTCP" (see Version Detection section below) Alice and Bob will use the padding data in the KDF for message 2. It is authenticated so that any tampering will cause the next message to fail.
Bloc d’options : Note : Tous les champs sont en big-endian.
+----+----+----+----+----+----+----+----+
| id | ver| padLen | m3p2len | Rsvd(0) |
+-------------------------------+-------------------------------+
| > tsA | > Reserved (0) |
+-------------------------------+-------------------------------+
id :: 1 byte, the network ID (currently 2, except for test networks)
: As of 0.9.42. See proposal 147.
ver :: 1 byte, protocol version (currently 2)
padLen :: 2 bytes, length of the padding, 0 or more
: Min/max guidelines TBD. Random size from 0 to 31 bytes minimum? (Distribution is implementation-dependent)
m3p2Len :: 2 bytes, length of the the second AEAD frame in SessionConfirmed
: (message 3 part 2) See notes below
Rsvd :: 2 bytes, set to 0 for compatibility with future options
tsA :: 4 bytes, Unix timestamp, unsigned seconds.
: Wraps around in 2106
Reserved :: 4 bytes, set to 0 for compatibility with future options
Notes
Lorsque l’adresse publiée est “NTCP”, Bob prend en charge à la fois NTCP et NTCP2 sur le même port. Pour des raisons de compatibilité, lors de l’initiation d’une connexion vers une adresse publiée comme “NTCP”, Alice doit limiter la taille maximale de ce message, y compris le rembourrage, à 287 octets ou moins. Cela facilite l’identification automatique du protocole par Bob. Lorsqu’elle est publiée comme “NTCP2”, il n’y a pas de restriction de taille. Voir les sections Adresses Publiées et Détection de Version ci-dessous.
La valeur X unique dans le bloc AES initial garantit que le texte chiffré est différent pour chaque session.
Bob doit rejeter les connexions où la valeur de l’horodatage est trop éloignée de l’heure actuelle. Appelons le delta de temps maximum “D”. Bob doit maintenir un cache local des valeurs de handshake précédemment utilisées et rejeter les doublons, pour empêcher les attaques de rejeu. Les valeurs dans le cache doivent avoir une durée de vie d’au moins 2*D. Les valeurs du cache dépendent de l’implémentation, cependant la valeur X de 32 octets (ou son équivalent chiffré) peut être utilisée.
Les clés éphémères Diffie-Hellman ne doivent jamais être réutilisées, pour prévenir les attaques cryptographiques, et leur réutilisation sera rejetée comme une attaque par rejeu.
Les options “KE” et “auth” doivent être compatibles, c’est-à-dire que le secret partagé K doit être de la taille appropriée. Si davantage d’options “auth” sont ajoutées, cela pourrait implicitement changer la signification du flag “KE” pour utiliser un KDF différent ou une taille de troncature différente.
Bob doit valider que la clé éphémère d’Alice est un point valide sur la courbe ici.
Le padding devrait être limité à une quantité raisonnable. Bob peut rejeter les connexions avec un padding excessif. Bob spécifiera ses options de padding dans le message 2. Directives min/max à déterminer. Taille aléatoire de 0 à 31 octets minimum ? (La distribution dépend de l’implémentation) Les implémentations Java limitent actuellement le padding à 256 octets maximum.
En cas d’erreur, y compris échec AEAD, DH, horodatage, rejeu apparent, ou validation de clé, Bob doit arrêter tout traitement ultérieur de message et fermer la connexion sans répondre. Ceci devrait être une fermeture anormale (TCP RST). Pour la résistance au sondage, après un échec AEAD, Bob devrait définir un délai d’attente aléatoire (plage à déterminer) puis lire un nombre aléatoire d’octets (plage à déterminer), avant de fermer la socket.
Bob peut effectuer une vérification MSB rapide pour une clé valide (X[31] & 0x80 == 0) avant de tenter le déchiffrement. Si le bit de poids fort est défini, implémenter la résistance au sondage comme pour les échecs AEAD.
Atténuation DoS : DH est une opération relativement coûteuse. Comme avec le protocole NTCP précédent, les routers doivent prendre toutes les mesures nécessaires pour prévenir l’épuisement du CPU ou des connexions. Placer des limites sur le nombre maximum de connexions actives et le nombre maximum d’établissements de connexion en cours. Appliquer des timeouts de lecture (à la fois par lecture et total pour “slowloris”). Limiter les connexions répétées ou simultanées depuis la même source. Maintenir des listes noires pour les sources qui échouent de manière répétée. Ne pas répondre aux échecs AEAD.
Pour faciliter la détection rapide de version et la négociation, les implémentations doivent s’assurer qu’Alice met en mémoire tampon puis vide entièrement le contenu du premier message d’un coup, y compris le rembourrage. Cela augmente la probabilité que les données soient contenues dans un seul paquet TCP (sauf si segmentées par l’OS ou les middleboxes), et reçues entièrement d’un coup par Bob. De plus, les implémentations doivent s’assurer que Bob met en mémoire tampon puis vide entièrement le contenu du deuxième message d’un coup, y compris le rembourrage, et que Bob met en mémoire tampon puis vide entièrement le contenu du troisième message d’un coup. Ceci est également pour l’efficacité et pour assurer l’efficacité du rembourrage aléatoire.
Champ “ver” : Le protocole Noise global, les extensions, et le protocole NTCP incluant les spécifications de charge utile, indiquant NTCP2. Ce champ peut être utilisé pour indiquer la prise en charge de modifications futures.
Longueur de la partie 2 du message 3 : Il s’agit de la taille de la seconde trame AEAD (incluant le MAC de 16 octets) contenant les Router Info d’Alice et le rembourrage optionnel qui sera envoyé dans le message SessionConfirmed. Comme les routeurs régénèrent et republient périodiquement leurs Router Info, la taille des Router Info actuelles peut changer avant l’envoi du message 3. Les implémentations doivent choisir l’une des deux stratégies suivantes :
a) sauvegarder les informations du router actuelles à envoyer dans le message 3, afin que la taille soit connue, et optionnellement ajouter de l’espace pour le remplissage ;
b) augmenter la taille spécifiée suffisamment pour permettre une possible augmentation de la taille des Router Info, et toujours ajouter un remplissage lorsque le message 3 est effectivement envoyé. Dans les deux cas, la longueur “m3p2len” incluse dans le message 1 doit être exactement la taille de cette trame lorsqu’elle est envoyée dans le message 3.
Bob doit faire échouer la connexion si des données entrantes subsistent après avoir validé le message 1 et lu le padding. Il ne devrait pas y avoir de données supplémentaires d’Alice, car Bob n’a pas encore répondu avec le message 2.
Le champ ID de réseau est utilisé pour identifier rapidement les connexions inter-réseaux. Si ce champ est non nul et ne correspond pas à l’ID de réseau de Bob, Bob devrait se déconnecter et bloquer les futures connexions. Toute connexion provenant de réseaux de test devrait avoir un ID différent et échouera au test. À partir de la version 0.9.42. Voir la proposition 147 pour plus d’informations.
Fonction de dérivation de clé (KDF) (pour le message de négociation 2 et la partie 1 du message 3)
// take h saved from message 1 KDF
// MixHash(ciphertext)
h = SHA256(h || 32 byte encrypted payload from message 1)
// MixHash(padding)
// Only if padding length is nonzero
h = SHA256(h || random padding from message 1)
This is the "e" message pattern:
Bob generates his ephemeral DH key pair e.
// h is from KDF for handshake message 1
// Bob ephemeral key Y
// MixHash(e.pubkey)
// || below means append
h = SHA256(h || e.pubkey);
// h is used as the associated data for the AEAD in message 2
// Retain the Hash h for the message 3 KDF
End of "e" message pattern.
This is the "ee" message pattern:
// DH(e, re)
Define input_key_material = 32 byte DH result of Alice's ephemeral key and Bob's ephemeral key
Set input_key_material = X25519 DH result
// overwrite Alice's ephemeral key in memory, no longer needed
// Alice:
e(public and private) = (all zeros)
// Bob:
re = (all zeros)
// MixKey(DH())
Define temp_key = 32 bytes
Define HMAC-SHA256(key, data) as in [RFC-2104]_
// Generate a temp key from the chaining key and DH result
// ck is the chaining key, from the KDF for handshake message 1
temp_key = HMAC-SHA256(ck, input_key_material)
// overwrite the DH result in memory, no longer needed
input_key_material = (all zeros)
// Output 1
// Set a new chaining key from the temp key
// byte() below means a single byte
ck = HMAC-SHA256(temp_key, byte(0x01)).
// Output 2
// Generate the cipher key k
Define k = 32 bytes
// || below means append
// byte() below means a single byte
k = HMAC-SHA256(temp_key, ck || byte(0x02)).
// overwrite the temp_key in memory, no longer needed
temp_key = (all zeros)
// retain the chaining key ck for message 3 KDF
End of "ee" message pattern.
2) SessionCreated
Bob envoie à Alice.
Contenu Noise : clé éphémère Y de Bob Charge utile Noise : bloc d’options de 16 octets Charge utile non-Noise : remplissage aléatoire
(Propriétés de sécurité de la charge utile provenant de Noise )
XK(s, rs): Authentication Confidentiality
<- e, ee 2 1
Authentication: 2. Sender authentication resistant to key-compromise impersonation (KCI). The sender authentication is based on an ephemeral-static DH ("es" or "se") between the sender's static key pair and the recipient's ephemeral key pair. Assuming the corresponding private keys are secure, this authentication cannot be forged.
Confidentiality: 1. Encryption to an ephemeral recipient. This payload has forward secrecy, since encryption involves an ephemeral-ephemeral DH ("ee"). However, the sender has not authenticated the recipient, so this payload might be sent to any party, including an active attacker.
"e": Bob generates a new ephemeral key pair and stores it in the e variable, writes the ephemeral public key as cleartext into the message buffer, and hashes the public key along with the old h to derive a new h.
"ee": A DH is performed between the Bob's ephemeral key pair and the Alice's ephemeral key pair. The result is hashed along with the old ck to derive a new ck and k, and n is set to zero.
La valeur Y est chiffrée pour assurer l’indiscernabilité et l’unicité de la charge utile, qui sont des contre-mesures DPI nécessaires. Nous utilisons le chiffrement AES pour y parvenir, plutôt que des alternatives plus complexes et plus lentes telles qu’elligator2. Le chiffrement asymétrique vers la clé publique du router d’Alice serait beaucoup trop lent. Le chiffrement AES utilise le hash du router de Bob comme clé et l’état AES du message 1 (qui a été initialisé avec l’IV de Bob tel que publié dans la base de données réseau).
Le chiffrement AES est uniquement destiné à la résistance DPI. Toute partie connaissant le hachage du router de Bob et l’IV, qui sont publiés dans la base de données réseau, et ayant capturé les 32 premiers octets du message 1, peut déchiffrer la valeur Y dans ce message.
Contenu brut :
+----+----+----+----+----+----+----+----+
| |
+ obfuscated with RH_B + | AES-CBC-256 encrypted Y | + (32 bytes) + | | + + | | +----+----+----+----+----+----+----+----+ | ChaChaPoly frame | + Encrypted and authenticated data + | 32 bytes | + k defined in KDF for message 2 + | n = 0; see KDF for associated data | + + | | +----+----+----+----+----+----+----+----+ | unencrypted authenticated | + padding (optional) + | length defined in options block | ~ . . . ~ | | +----+----+----+----+----+----+----+----+
Y :: 32 bytes, AES-256-CBC encrypted X25519 ephemeral key, little endian
: key: RH_B iv: Using AES state from message 1
Données non chiffrées (étiquette d’authentification Poly1305 non affichée) :
+----+----+----+----+----+----+----+----+
| |
+ + | Y | + (32 bytes) + | | + + | | +----+----+----+----+----+----+----+----+ | options | + (16 bytes) + | | +----+----+----+----+----+----+----+----+ | unencrypted authenticated | + padding (optional) + | length defined in options block | ~ . . . ~ | | +----+----+----+----+----+----+----+----+
Y :: 32 bytes, X25519 ephemeral key, little endian
options :: options block, 16 bytes, see below
padding :: Random data, 0 or more bytes.
: Total message length must be 65535 bytes or less. Alice and Bob will use the padding data in the KDF for message 3 part 1. It is authenticated so that any tampering will cause the next message to fail.
Notes
- Alice doit valider que la clé éphémère de Bob est un point valide sur la courbe ici.
- Le padding devrait être limité à une quantité raisonnable. Alice peut rejeter les connexions avec un padding excessif. Alice spécifiera ses options de padding dans le message 3. Directives min/max à déterminer. Taille aléatoire de 0 à 31 octets minimum ? (La distribution dépend de l’implémentation)
- En cas d’erreur, y compris AEAD, DH, horodatage, replay apparent, ou échec de validation de clé, Alice doit arrêter le traitement ultérieur des messages et fermer la connexion sans répondre. Cela devrait être une fermeture anormale (TCP RST).
- Pour faciliter l’établissement de liaison rapide, les implémentations doivent s’assurer que Bob met en tampon puis vide tout le contenu du premier message en une fois, y compris le padding. Cela augmente la probabilité que les données soient contenues dans un seul paquet TCP (sauf si segmentées par l’OS ou les middleboxes), et reçues en une fois par Alice. C’est aussi pour l’efficacité et pour assurer l’efficacité du padding aléatoire.
- Alice doit faire échouer la connexion si des données entrantes restent après avoir validé le message 2 et lu le padding. Il ne devrait pas y avoir de données supplémentaires de Bob, car Alice n’a pas encore répondu avec le message 3.
Bloc d’options : Note : Tous les champs sont en big-endian.
+----+----+----+----+----+----+----+----+
| Rsvd(0) | padLen | Reserved (0) |
+-------------------------------+-------------------------------+
| > tsB | > Reserved (0) |
+-------------------------------+-------------------------------+
Reserved :: 10 bytes total, set to 0 for compatibility with future options
padLen :: 2 bytes, big endian, length of the padding, 0 or more
: Min/max guidelines TBD. Random size from 0 to 31 bytes minimum? (Distribution is implementation-dependent)
tsB :: 4 bytes, big endian, Unix timestamp, unsigned seconds.
: Wraps around in 2106
Notes
- Alice doit rejeter les connexions où la valeur d’horodatage est trop éloignée de l’heure actuelle. Appelons le delta de temps maximum “D”. Alice doit maintenir un cache local des valeurs de poignée de main précédemment utilisées et rejeter les doublons, pour empêcher les attaques par rejeu. Les valeurs dans le cache doivent avoir une durée de vie d’au moins 2*D. Les valeurs du cache dépendent de l’implémentation, cependant la valeur Y de 32 octets (ou son équivalent chiffré) peut être utilisée.
Problèmes
- Inclure les options de padding min/max ici ?
Chiffrement pour la partie 1 du message 3 de handshake, en utilisant le KDF du message 2)
// take h saved from message 2 KDF
// MixHash(ciphertext)
h = SHA256(h || 24 byte encrypted payload from message 2)
// MixHash(padding)
// Only if padding length is nonzero
h = SHA256(h || random padding from message 2)
// h is used as the associated data for the AEAD in message 3 part 1, below
This is the "s" message pattern:
Define s = Alice's static public key, 32 bytes
// EncryptAndHash(s.publickey)
// EncryptWithAd(h, s.publickey)
// AEAD_ChaCha20_Poly1305(key, nonce, associatedData, data)
// k is from handshake message 1
// n is 1
ciphertext = AEAD_ChaCha20_Poly1305(k, n++, h, s.publickey)
// MixHash(ciphertext)
// || below means append
h = SHA256(h || ciphertext);
// h is used as the associated data for the AEAD in message 3 part 2
End of "s" message pattern.
Fonction de dérivation de clé (KDF) (pour la partie 2 du message 3 de négociation)
This is the "se" message pattern:
// DH(s, re) == DH(e, rs) Define input_key_material = 32 byte DH result of Alice's static key and Bob's ephemeral key Set input_key_material = X25519 DH result // overwrite Bob's ephemeral key in memory, no longer needed // Alice: re = (all zeros) // Bob: e(public and private) = (all zeros)
// MixKey(DH())
Define temp_key = 32 bytes Define HMAC-SHA256(key, data) as in [RFC-2104](https://tools.ietf.org/html/rfc2104) // Generate a temp key from the chaining key and DH result // ck is the chaining key, from the KDF for handshake message 1 temp_key = HMAC-SHA256(ck, input_key_material) // overwrite the DH result in memory, no longer needed input_key_material = (all zeros)
// Output 1 // Set a new chaining key from the temp key // byte() below means a single byte ck = HMAC-SHA256(temp_key, byte(0x01)).
// Output 2 // Generate the cipher key k Define k = 32 bytes // || below means append // byte() below means a single byte k = HMAC-SHA256(temp_key, ck || byte(0x02)).
// h from message 3 part 1 is used as the associated data for the AEAD in message 3 part 2
// EncryptAndHash(payload) // EncryptWithAd(h, payload) // AEAD_ChaCha20_Poly1305(key, nonce, associatedData, data) // n is 0 ciphertext = AEAD_ChaCha20_Poly1305(k, n++, h, payload) // MixHash(ciphertext) // || below means append h = SHA256(h || ciphertext);
// retain the chaining key ck for the data phase KDF // retain the hash h for the data phase Additional Symmetric Key (SipHash) KDF
End of "se" message pattern.
// overwrite the temp_key in memory, no longer needed temp_key = (all zeros)
3) SessionConfirmed
Alice envoie à Bob.
Contenu Noise : clé statique d’Alice Charge utile Noise : RouterInfo d’Alice et remplissage aléatoire Charge utile non-noise : aucune
(Propriétés de sécurité du payload de Noise )
XK(s, rs): Authentication Confidentiality
-> s, se 2 5
Authentication: 2. Sender authentication resistant to key-compromise impersonation (KCI). The sender authentication is based on an ephemeral-static DH ("es" or "se") between the sender's static key pair and the recipient's ephemeral key pair. Assuming the corresponding private keys are secure, this authentication cannot be forged.
Confidentiality: 5. Encryption to a known recipient, strong forward secrecy. This payload is encrypted based on an ephemeral-ephemeral DH as well as an ephemeral-static DH with the recipient's static key pair. Assuming the ephemeral private keys are secure, and the recipient is not being actively impersonated by an attacker that has stolen its static private key, this payload cannot be decrypted.
"s": Alice writes her static public key from the s variable into the message buffer, encrypting it, and hashes the output along with the old h to derive a new h.
"se": A DH is performed between the Alice's static key pair and the Bob's ephemeral key pair. The result is hashed along with the old ck to derive a new ck and k, and n is set to zero.
Ceci contient deux trames ChaChaPoly. La première est la clé publique statique chiffrée d’Alice. La seconde est la charge utile Noise : le RouterInfo chiffré d’Alice, les options facultatives et le remplissage optionnel. Elles utilisent des clés différentes, car la fonction MixKey() est appelée entre les deux.
Contenu brut :
+----+----+----+----+----+----+----+----+
| |
+ ChaChaPoly frame (48 bytes) + | Encrypted and authenticated | + Alice static key S + | (32 bytes) | + + | k defined in KDF for message 2 | + n = 1 + | see KDF for associated data | + + | | +----+----+----+----+----+----+----+----+ | | + Length specified in message 1 + | | + ChaChaPoly frame + | Encrypted and authenticated | + + | Alice RouterInfo | + using block format 2 + | Alice Options (optional) | + using block format 1 + | Arbitrary padding | + using block format 254 + | | + + | k defined in KDF for message 3 part 2 | + n = 0 + | see KDF for associated data | ~ . . . ~ | | +----+----+----+----+----+----+----+----+
S :: 32 bytes, ChaChaPoly encrypted Alice's X25519 static key, little endian
: inside 48 byte ChaChaPoly frame
Données non chiffrées (tags d’authentification Poly1305 non affichés) :
+----+----+----+----+----+----+----+----+
| |
+ + | S | + Alice static key + | (32 bytes) | + + | | + + +----+----+----+----+----+----+----+----+ | | + + | | + + | Alice RouterInfo block | ~ . . . ~ | | +----+----+----+----+----+----+----+----+ | | + Optional Options block + | | ~ . . . ~ | | +----+----+----+----+----+----+----+----+ | | + Optional Padding block + | | ~ . . . ~ | | +----+----+----+----+----+----+----+----+
S :: 32 bytes, Alice's X25519 static key, little endian
Notes
Bob doit effectuer la validation habituelle des Router Info. S’assurer que le type de signature est pris en charge, vérifier la signature, vérifier que l’horodatage est dans les limites, et toute autre vérification nécessaire.
Bob doit vérifier que la clé statique d’Alice reçue dans la première trame correspond à la clé statique dans les informations du routeur. Bob doit d’abord rechercher dans les informations du routeur une adresse de routeur NTCP ou NTCP2 avec une option de version (v) correspondante. Voir les sections Informations de routeur publiées et Informations de routeur non publiées ci-dessous.
Si Bob a une version plus ancienne du RouterInfo d’Alice dans sa netDb, vérifier que la clé statique dans le router info est la même dans les deux, si présente, et si la version plus ancienne a moins de XXX d’ancienneté (voir le temps de rotation des clés ci-dessous)
Bob doit valider que la clé statique d’Alice est un point valide sur la courbe ici.
Les options doivent être incluses, pour spécifier les paramètres de remplissage.
En cas d’erreur, y compris un échec de validation AEAD, RI, DH, horodatage ou clé, Bob doit arrêter le traitement ultérieur des messages et fermer la connexion sans répondre. Cela devrait être une fermeture anormale (TCP RST).
Pour faciliter une négociation rapide, les implémentations doivent s’assurer qu’Alice met en mémoire tampon puis envoie l’intégralité du contenu du troisième message d’un coup, y compris les deux trames AEAD. Cela augmente la probabilité que les données soient contenues dans un seul paquet TCP (sauf segmentation par l’OS ou les middleboxes), et reçues d’un seul coup par Bob. C’est aussi pour l’efficacité et pour assurer l’efficacité du remplissage aléatoire.
Longueur de la trame de la partie 2 du message 3 : La longueur de cette trame (MAC inclus) est envoyée par Alice dans le message 1. Voir ce message pour des notes importantes sur la nécessité de prévoir suffisamment d’espace pour le remplissage.
Contenu de la trame de la partie 2 du message 3 : Le format de cette trame est identique au format des trames de la phase de données, excepté que la longueur de la trame est envoyée par Alice dans le message 1. Voir ci-dessous pour le format des trames de la phase de données. La trame doit contenir 1 à 3 blocs dans l’ordre suivant :
- Bloc Router Info d’Alice (requis) 2) Bloc d’options (optionnel)
3) Bloc de remplissage (optionnel) Cette trame ne doit jamais contenir d’autre type de bloc.
Le remplissage de la partie 2 du message 3 n’est pas requis si Alice ajoute une trame de phase de données (contenant éventuellement du remplissage) à la fin du message 3 et envoie les deux à la fois, car cela apparaîtra comme un grand flux d’octets à un observateur. Comme Alice aura généralement, mais pas toujours, un message I2NP à envoyer à Bob (c’est pourquoi elle s’est connectée à lui), c’est l’implémentation recommandée, pour l’efficacité et pour assurer l’efficacité du remplissage aléatoire.
La longueur totale des deux trames AEAD du Message 3 (parties 1 et 2) est de 65535 octets ; la partie 1 fait 48 octets donc la longueur maximale de trame de la partie 2 est de 65487 ; la longueur maximale de texte en clair de la partie 2 excluant le MAC est de 65471.
Fonction de dérivation de clé (KDF) (pour la phase de données)
La phase de données utilise une entrée de données associées de longueur zéro.
La KDF génère deux clés de chiffrement k_ab et k_ba à partir de la clé de chaînage ck, en utilisant HMAC-SHA256(key, data) tel que défini dans RFC-2104 . Il s’agit de la fonction Split(), exactement telle que définie dans la spécification Noise.
ck = from handshake phase
// k_ab, k_ba = HKDF(ck, zerolen) // ask_master = HKDF(ck, zerolen, info="ask")
// zerolen is a zero-length byte array temp_key = HMAC-SHA256(ck, zerolen) // overwrite the chaining key in memory, no longer needed ck = (all zeros)
// Output 1 // cipher key, for Alice transmits to Bob (Noise doesn't make clear which is which, but Java code does) k_ab = HMAC-SHA256(temp_key, byte(0x01)).
// Output 2 // cipher key, for Bob transmits to Alice (Noise doesn't make clear which is which, but Java code does) k_ba = HMAC-SHA256(temp_key, k_ab || byte(0x02)).
KDF for SipHash for length field: Generate an Additional Symmetric Key (ask) for SipHash SipHash uses two 8-byte keys (big endian) and 8 byte IV for first data.
// "ask" is 3 bytes, US-ASCII, no null termination ask_master = HMAC-SHA256(temp_key, "ask" || byte(0x01)) // sip_master = HKDF(ask_master, h || "siphash") // "siphash" is 7 bytes, US-ASCII, no null termination // overwrite previous temp_key in memory // h is from KDF for message 3 part 2 temp_key = HMAC-SHA256(ask_master, h || "siphash") // overwrite ask_master in memory, no longer needed ask_master = (all zeros) sip_master = HMAC-SHA256(temp_key, byte(0x01))
Alice to Bob SipHash k1, k2, IV: // sipkeys_ab, sipkeys_ba = HKDF(sip_master, zerolen) // overwrite previous temp_key in memory temp_key = HMAC-SHA256(sip_master, zerolen) // overwrite sip_master in memory, no longer needed sip_master = (all zeros)
sipkeys_ab = HMAC-SHA256(temp_key, byte(0x01)). sipk1_ab = sipkeys_ab[0:7], little endian sipk2_ab = sipkeys_ab[8:15], little endian sipiv_ab = sipkeys_ab[16:23]
Bob to Alice SipHash k1, k2, IV:
sipkeys_ba = HMAC-SHA256(temp_key, sipkeys_ab || byte(0x02)). sipk1_ba = sipkeys_ba[0:7], little endian sipk2_ba = sipkeys_ba[8:15], little endian sipiv_ba = sipkeys_ba[16:23]
// overwrite the temp_key in memory, no longer needed temp_key = (all zeros)
4) Phase de données
Charge utile Noise : Comme défini ci-dessous, incluant un remplissage aléatoire Charge utile non-noise : aucune
À partir de la 2ème partie du message 3, tous les messages sont à l’intérieur d’une “frame” ChaChaPoly authentifiée et chiffrée avec une longueur obfusquée de deux octets en préfixe. Tout le padding est à l’intérieur de la frame. À l’intérieur de la frame se trouve un format standard avec zéro ou plusieurs “blocs”. Chaque bloc a un type d’un octet et une longueur de deux octets. Les types incluent date/heure, message I2NP, options, terminaison et padding.
Note : Bob peut, mais n’est pas obligé d’envoyer ses RouterInfo à Alice comme premier message à Alice dans la phase de données.
(Propriétés de sécurité de la charge utile depuis Noise )
XK(s, rs): Authentication Confidentiality
<- 2 5 -> 2 5
Authentication: 2. Sender authentication resistant to key-compromise impersonation (KCI). The sender authentication is based on an ephemeral-static DH ("es" or "se") between the sender's static key pair and the recipient's ephemeral key pair. Assuming the corresponding private keys are secure, this authentication cannot be forged.
Confidentiality: 5. Encryption to a known recipient, strong forward secrecy. This payload is encrypted based on an ephemeral-ephemeral DH as well as an ephemeral-static DH with the recipient's static key pair. Assuming the ephemeral private keys are secure, and the recipient is not being actively impersonated by an attacker that has stolen its static private key, this payload cannot be decrypted.
Notes
- Pour l’efficacité et pour minimiser l’identification du champ de longueur, les implémentations doivent s’assurer que l’expéditeur met en mémoire tampon puis vide entièrement le contenu des messages de données d’un coup, y compris le champ de longueur et la trame AEAD. Cela augmente la probabilité que les données soient contenues dans un seul paquet TCP (sauf si segmentées par l’OS ou les middleboxes), et reçues d’un seul coup par l’autre partie. C’est aussi pour l’efficacité et pour assurer l’efficacité du bourrage aléatoire.
- Le router peut choisir de terminer la session en cas d’erreur AEAD, ou peut continuer à tenter des communications. S’il continue, le router devrait terminer après des erreurs répétées.
Longueur obfusquée SipHash
Référence : SipHash
Une fois que les deux parties ont terminé la négociation, elles transfèrent des charges utiles qui sont ensuite chiffrées et authentifiées dans des “trames” ChaChaPoly.
Chaque trame est précédée d’une longueur de deux octets, en big endian. Cette longueur spécifie le nombre d’octets de trame chiffrés qui suivent, y compris le MAC. Pour éviter de transmettre des champs de longueur identifiables dans le flux, la longueur de trame est obscurcie en appliquant un XOR avec un masque dérivé de SipHash, tel qu’initialisé à partir du KDF de la phase de données. Notez que les deux directions ont des clés SipHash et des IV uniques provenant du KDF.
sipk1, sipk2 = The SipHash keys from the KDF. (two 8-byte long integers)
IV[0] = sipiv = The SipHash IV from the KDF. (8 bytes)
length is big endian.
For each frame:
IV[n] = SipHash-2-4(sipk1, sipk2, IV[n-1])
Mask[n] = First 2 bytes of IV[n]
obfuscatedLength = length ^ Mask[n]
The first length output will be XORed with with IV[1].
Le récepteur possède les mêmes clés SipHash et IV. Le décodage de la longueur se fait en dérivant le masque utilisé pour obfusquer la longueur et en appliquant un XOR au digest tronqué pour obtenir la longueur de la trame. La longueur de la trame correspond à la longueur totale de la trame chiffrée incluant le MAC.
Notes
- Si vous utilisez une fonction de bibliothèque SipHash qui retourne un entier long non signé, utilisez les deux octets les moins significatifs comme Mask. Convertissez l’entier long vers le prochain IV en little endian.
Contenu brut
+----+----+----+----+----+----+----+----+
[|obf size |](##SUBST##|obf size |) | +----+----+ + | | + ChaChaPoly frame + | Encrypted and authenticated | + key is k_ab for Alice to Bob + | key is k_ba for Bob to Alice | + as defined in KDF for data phase + | n starts at 0 and increments | + for each frame in that direction + | no associated data | + 16 bytes minimum + | | ~ . . . ~ | | +----+----+----+----+----+----+----+----+
obf size :: 2 bytes length obfuscated with SipHash
: when de-obfuscated: 16 - 65535
Minimum size including length field is 18 bytes. Maximum size including length field is 65537 bytes. Obfuscated length is 2 bytes. Maximum ChaChaPoly frame is 65535 bytes.
Notes
- Comme le récepteur doit obtenir la trame entière pour vérifier le MAC, il est recommandé que l’expéditeur limite les trames à quelques Ko plutôt que de maximiser la taille de trame. Cela minimisera la latence au niveau du récepteur.
Données non chiffrées
Il y a zéro ou plusieurs blocs dans la trame chiffrée. Chaque bloc contient un identifiant d’un octet, une longueur de deux octets, et zéro ou plusieurs octets de données.
Pour des raisons d’extensibilité, les récepteurs doivent ignorer les blocs avec des identifiants inconnus et les traiter comme du remplissage.
Les données chiffrées font 65535 octets maximum, incluant un en-tête d’authentification de 16 octets, donc les données non chiffrées font 65519 octets maximum.
(Tag d’authentification Poly1305 non affiché) :
+----+----+----+----+----+----+----+----+
[|blk |](##SUBST##|blk |) size | data | +----+----+----+ + | | ~ . . . ~ | | +----+----+----+----+----+----+----+----+ [|blk |](##SUBST##|blk |) size | data | +----+----+----+ + | | ~ . . . ~ | | +----+----+----+----+----+----+----+----+ ~ . . . ~
blk :: 1 byte
: 0 for datetime 1 for options 2 for RouterInfo 3 for I2NP message 4 for termination 224-253 reserved for experimental features 254 for padding 255 reserved for future extension
size :: 2 bytes, big endian, size of data to follow, 0 - 65516 data :: the data
Maximum ChaChaPoly frame is 65535 bytes. Poly1305 tag is 16 bytes Maximum total block size is 65519 bytes Maximum single block size is 65519 bytes Block type is 1 byte Block length is 2 bytes Maximum single block data size is 65516 bytes.
Règles d’ordre des blocs
Dans le message de handshake 3 partie 2, l’ordre doit être : RouterInfo, suivi des Options si présentes, suivi du Padding si présent. Aucun autre bloc n’est autorisé.
Dans la phase de données, l’ordre n’est pas spécifié, sauf pour les exigences suivantes : le Padding, s’il est présent, doit être le dernier bloc. La Termination, si elle est présente, doit être le dernier bloc à l’exception du Padding.
Il peut y avoir plusieurs blocs I2NP dans une seule trame. Plusieurs blocs de remplissage ne sont pas autorisés dans une seule trame. Les autres types de blocs n’auront probablement pas plusieurs blocs dans une seule trame, mais ce n’est pas interdit.
DateTime
Cas particulier pour la synchronisation temporelle :
+----+----+----+----+----+----+----+
| 0 | 4 | timestamp |
+----+----+----+----+----+----+----+
blk :: 0 size :: 2 bytes, big endian, value = 4 timestamp :: Unix timestamp, unsigned seconds. Wraps around in 2106
NOTE : Les implémentations doivent arrondir à la seconde la plus proche pour éviter le biais d’horloge dans le réseau.
Options
Passer les options mises à jour. Les options incluent : Padding minimum et maximum.
Le bloc d’options aura une longueur variable.
+----+----+----+----+----+----+----+----+
| 1 | size [|tmin|](##SUBST##|tmin|)tmax[|rmin|](##SUBST##|rmin|)rmax[|tdmy|](##SUBST##|tdmy|)
+----+----+----+----+----+----+----+----+ [|tdmy|](##SUBST##|tdmy|) rdmy | tdelay | rdelay | | ~----+----+----+----+----+----+----+ ~ | more_options | ~ . . . ~ | | +----+----+----+----+----+----+----+----+
blk :: 1 size :: 2 bytes, big endian, size of options to follow, 12 bytes minimum
tmin, tmax, rmin, rmax :: requested padding limits
: tmin and rmin are for desired resistance to traffic analysis. tmax and rmax are for bandwidth limits. tmin and tmax are the transmit limits for the router sending this options block. rmin and rmax are the receive limits for the router sending this options block. Each is a 4.4 fixed-point float representing 0 to 15.9375 (or think of it as an unsigned 8-bit integer divided by 16.0). This is the ratio of padding to data. Examples: Value of 0x00 means no padding Value of 0x01 means add 6 percent padding Value of 0x10 means add 100 percent padding Value of 0x80 means add 800 percent (8x) padding Alice and Bob will negotiate the minimum and maximum in each direction. These are guidelines, there is no enforcement. Sender should honor receiver's maximum. Sender may or may not honor receiver's minimum, within bandwidth constraints.
tdmy: Max dummy traffic willing to send, 2 bytes big endian, bytes/sec average rdmy: Requested dummy traffic, 2 bytes big endian, bytes/sec average tdelay: Max intra-message delay willing to insert, 2 bytes big endian, msec average rdelay: Requested intra-message delay, 2 bytes big endian, msec average
Padding distribution specified as additional parameters? Random delay specified as additional parameters?
more_options :: Format TBD
Problèmes d’options
- Le format des options est à déterminer.
- La négociation des options est à déterminer.
RouterInfo
Transmettre les RouterInfo d’Alice à Bob. Utilisé dans la partie 2 du message 3 de l’établissement de connexion. Transmettre les RouterInfo d’Alice à Bob, ou ceux de Bob à Alice. Utilisé optionnellement pendant la phase de données.
+----+----+----+----+----+----+----+----+
| 2 | size [|flg |](##SUBST##|flg |) RouterInfo |
+----+----+----+----+ + | (Alice RI in handshake msg 3 part 2) | ~ (Alice, Bob, or third-party ~ | RI in data phase) | ~ . . . ~ | | +----+----+----+----+----+----+----+----+
blk :: 2 size :: 2 bytes, big endian, size of flag + router info to follow flg :: 1 byte flags bit order: 76543210 bit 0: 0 for local store, 1 for flood request bits 7-1: Unused, set to 0 for future compatibility routerinfo :: Alice's or Bob's RouterInfo
Notes
- Lorsqu’utilisé dans la phase de données, le destinataire (Alice ou Bob) doit valider que c’est le même Router Hash que celui envoyé initialement (pour Alice) ou envoyé vers (pour Bob). Ensuite, le traiter comme un message I2NP DatabaseStore local. Valider la signature, valider l’horodatage plus récent, et stocker dans la netDb locale. Si le bit de flag 0 est à 1, et que la partie réceptrice est floodfill, le traiter comme un message DatabaseStore avec un jeton de réponse non nul, et le diffuser vers les floodfills les plus proches.
- Le Router Info n’est PAS compressé avec gzip (contrairement à un message DatabaseStore, où il l’est)
- La diffusion ne doit pas être demandée à moins qu’il y ait des RouterAddresses publiées dans le RouterInfo. Le router récepteur ne doit pas diffuser le RouterInfo à moins qu’il contienne des RouterAddresses publiées.
- Les implémenteurs doivent s’assurer que lors de la lecture d’un bloc, des données malformées ou malveillantes ne provoqueront pas de débordement de lecture dans le bloc suivant.
- Ce protocole ne fournit pas d’accusé de réception que le RouterInfo a été reçu, stocké ou diffusé (ni dans la phase de handshake ni dans la phase de données). Si un accusé de réception est souhaité, et que le destinataire est floodfill, l’expéditeur devrait plutôt envoyer un message I2NP DatabaseStoreMessage standard avec un jeton de réponse.
Problèmes
- Pourrait également être utilisé dans la phase de données, au lieu d’un I2NP DatabaseStoreMessage. Par exemple, Bob pourrait l’utiliser pour démarrer la phase de données.
- Est-il autorisé que ceci contienne le RI pour des routeurs autres que l’expéditeur, comme remplacement général des DatabaseStoreMessages, par exemple pour le flooding par les floodfills ?
Message I2NP
Un seul message I2NP avec un en-tête modifié. Les messages I2NP ne peuvent pas être fragmentés entre les blocs ou entre les trames ChaChaPoly.
Ceci utilise les 9 premiers octets de l’en-tête I2NP NTCP standard, et supprime les 7 derniers octets de l’en-tête, comme suit : raccourcir l’expiration de 8 à 4 octets (secondes au lieu de millisecondes, comme pour SSU), supprimer la longueur de 2 octets (utiliser la taille du bloc - 9), et supprimer la somme de contrôle SHA256 d’un octet.
+----+----+----+----+----+----+----+----+
| 3 | size [|type|](##SUBST##|type|) msg id |
+-------------------------------+
| > short exp |
+-------------------------------+
~ . . . ~ | | +----+----+----+----+----+----+----+----+
blk :: 3 size :: 2 bytes, big endian, size of type + msg id + exp + message to follow I2NP message body size is (size - 9). type :: 1 byte, I2NP msg type, see I2NP spec msg id :: 4 bytes, big endian, I2NP message ID short exp :: 4 bytes, big endian, I2NP message expiration, Unix timestamp, unsigned seconds. Wraps around in 2106 message :: I2NP message body
Notes
- Les implémenteurs doivent s’assurer que lors de la lecture d’un bloc, des données malformées ou malveillantes ne provoqueront pas de débordement de lecture dans le bloc suivant.
Terminaison
Noise recommande un message de terminaison explicite. Le NTCP original n’en a pas. Abandonner la connexion. Ceci doit être le dernier bloc non-rembourrage dans la trame.
+----+----+----+----+----+----+----+----+
| 4 | size | valid data frames |
+----+----+----+----+----+----+----+----+
: received | rsn| addl data |
+----+----+----+----+ + ~ . . . ~ +----+----+----+----+----+----+----+----+
blk :: 4 size :: 2 bytes, big endian, value = 9 or more valid data frames received :: The number of valid AEAD data phase frames received (current receive nonce value) 0 if error occurs in handshake phase 8 bytes, big endian rsn :: reason, 1 byte: 0: normal close or unspecified 1: termination received 2: idle timeout 3: router shutdown 4: data phase AEAD failure 5: incompatible options 6: incompatible signature type 7: clock skew 8: padding violation 9: AEAD framing error 10: payload format error 11: message 1 error 12: message 2 error 13: message 3 error 14: intra-frame read timeout 15: RI signature verification fail 16: s parameter missing, invalid, or mismatched in RouterInfo 17: banned addl data :: optional, 0 or more bytes, for future expansion, debugging, or reason text. Format unspecified and may vary based on reason code.
Notes
Toutes les raisons ne sont pas nécessairement utilisées, cela dépend de l’implémentation. Les échecs de handshake résulteront généralement en une fermeture avec TCP RST à la place. Voir les notes dans les sections de messages de handshake ci-dessus. Les raisons supplémentaires listées sont pour la cohérence, la journalisation, le débogage, ou en cas de changements de politique.
Remplissage
Ceci est pour le remplissage à l’intérieur des trames AEAD. Le remplissage pour les messages 1 et 2 se trouve à l’extérieur des trames AEAD. Tout le remplissage pour le message 3 et la phase de données se trouve à l’intérieur des trames AEAD.
Le rembourrage à l’intérieur d’AEAD devrait approximativement respecter les paramètres négociés. Bob a envoyé ses paramètres min/max tx/rx demandés dans le message 2. Alice a envoyé ses paramètres min/max tx/rx demandés dans le message 3. Des options mises à jour peuvent être envoyées pendant la phase de données. Voir les informations du bloc d’options ci-dessus.
Si présent, ce doit être le dernier bloc dans la trame.
+----+----+----+----+----+----+----+----+
[|254 |](##SUBST##|254 |) size | padding | +----+----+----+ + | | ~ . . . ~ | | +----+----+----+----+----+----+----+----+
blk :: 254 size :: 2 bytes, big endian, size of padding to follow padding :: random data
Notes
- Taille = 0 est autorisée.
- Stratégies de remplissage à déterminer.
- Remplissage minimum à déterminer.
- Les trames contenant uniquement du remplissage sont autorisées.
- Valeurs par défaut du remplissage à déterminer.
- Voir le bloc d’options pour la négociation des paramètres de remplissage
- Voir le bloc d’options pour les paramètres de remplissage min/max
- Noise limite les messages à 64KB. Si plus de remplissage est nécessaire, envoyez plusieurs trames.
- La réponse du router en cas de violation du remplissage négocié dépend de l’implémentation.
Autres types de blocs
Les implémentations doivent ignorer les types de blocs inconnus pour la compatibilité ascendante, sauf dans la partie 2 du message 3, où les blocs inconnus ne sont pas autorisés.
Travaux futurs
- La longueur du bourrage (padding) doit être décidée soit sur une base par message et des estimations de la distribution de longueur, soit des délais aléatoires doivent être ajoutés. Ces contre-mesures doivent être incluses pour résister à la DPI (inspection approfondie de paquets), car les tailles de messages révéleraient autrement que le trafic I2P est transporté par le protocole de transport. Le schéma de bourrage exact constitue un domaine de travail futur.
5) Résiliation
Les connexions peuvent être terminées par une fermeture normale ou anormale de socket TCP, ou, comme Noise le recommande, par un message de terminaison explicite. Le message de terminaison explicite est défini dans la phase de données ci-dessus.
Lors de toute terminaison normale ou anormale, les routers doivent remettre à zéro toutes les données éphémères en mémoire, y compris les clés éphémères de négociation, les clés cryptographiques symétriques et les informations associées.
Informations de Router Publiées
Capacités
À partir de la version 0.9.50, l’option “caps” est prise en charge dans les adresses NTCP2, de manière similaire à SSU. Une ou plusieurs capacités peuvent être publiées dans l’option “caps”. Les capacités peuvent être dans n’importe quel ordre, mais “46” est l’ordre recommandé, pour la cohérence entre les implémentations. Il y a deux capacités définies :
4: Indique la capacité IPv4 sortante. Si une IP est publiée dans le champ host, cette capacité n’est pas nécessaire. Si le router est caché, ou si NTCP2 est uniquement sortant, ‘4’ et ‘6’ peuvent être combinés dans une seule adresse.
6: Indique une capacité IPv6 sortante. Si une IP est publiée dans le champ host, cette capacité n’est pas nécessaire. Si le router est caché, ou si NTCP2 est en sortie uniquement, ‘4’ et ‘6’ peuvent être combinés dans une seule adresse.
Adresses Publiées
La RouterAddress publiée (partie du RouterInfo) aura un identifiant de protocole soit “NTCP” soit “NTCP2”.
Le RouterAddress doit contenir les options “host” et “port”, comme dans le protocole NTCP actuel.
La RouterAddress doit contenir trois options pour indiquer la prise en charge de NTCP2 :
- s=(Clé Base64) La clé publique statique Noise actuelle (s) pour cette RouterAddress. Encodée en Base 64 utilisant l’alphabet I2P Base 64 standard. 32 octets en binaire, 44 octets encodés en Base 64, clé publique X25519 little-endian.
- i=(IV Base64) L’IV actuel pour chiffrer la valeur X dans le message 1 pour cette RouterAddress. Encodé en Base 64 utilisant l’alphabet I2P Base 64 standard. 16 octets en binaire, 24 octets encodés en Base 64, big-endian.
- v=2 La version actuelle (2). Lorsque publié comme “NTCP”, un support additionnel pour la version 1 est implicite. Le support pour les versions futures se fera avec des valeurs séparées par des virgules, par exemple v=2,3. L’implémentation doit vérifier la compatibilité, y compris les versions multiples si une virgule est présente. Les versions séparées par des virgules doivent être dans l’ordre numérique.
Alice doit vérifier que les trois options sont présentes et valides avant de se connecter en utilisant le protocole NTCP2.
Lorsqu’il est publié comme “NTCP” avec les options “s”, “i”, et “v”, le router doit accepter les connexions entrantes sur cet hôte et ce port pour les protocoles NTCP et NTCP2, et détecter automatiquement la version du protocole.
Lorsque publié comme “NTCP2” avec les options “s”, “i”, et “v”, le router accepte les connexions entrantes sur cet hôte et ce port pour le protocole NTCP2 uniquement.
Si un router prend en charge les connexions NTCP1 et NTCP2 mais n’implémente pas la détection automatique de version pour les connexions entrantes, il doit annoncer à la fois les adresses “NTCP” et “NTCP2”, et inclure les options NTCP2 uniquement dans l’adresse “NTCP2”. Le router devrait définir une valeur de coût plus faible (priorité plus élevée) dans l’adresse “NTCP2” que dans l’adresse “NTCP”, afin que NTCP2 soit privilégié.
Si plusieurs NTCP2 RouterAddresses (soit comme “NTCP” ou “NTCP2”) sont publiées dans le même RouterInfo (pour des adresses IP ou ports supplémentaires), toutes les adresses spécifiant le même port doivent contenir des options et valeurs NTCP2 identiques. En particulier, toutes doivent contenir la même clé statique et le même iv.
Adresse NTCP2 non publiée
Si Alice ne publie pas son adresse NTCP2 (comme “NTCP” ou “NTCP2”) pour les connexions entrantes, elle doit publier une adresse router “NTCP2” contenant uniquement sa clé statique et la version NTCP2, afin que Bob puisse valider la clé après avoir reçu le RouterInfo d’Alice dans la partie 2 du message 3.
- s=(clé Base64) Comme défini ci-dessus pour les adresses publiées.
- v=2 Comme défini ci-dessus pour les adresses publiées.
Cette adresse de router ne contiendra pas les options “i”, “host” ou “port”, car elles ne sont pas requises pour les connexions NTCP2 sortantes. Le coût publié pour cette adresse n’a pas d’importance stricte, car elle est uniquement entrante ; cependant, il peut être utile aux autres routers que le coût soit défini plus haut (priorité plus faible) que les autres adresses. La valeur suggérée est 14.
Alice peut également simplement ajouter les options “s” et “v” à une adresse “NTCP” publiée existante.
Rotation de la clé publique et du vecteur d’initialisation
En raison de la mise en cache des RouterInfos, les routers ne doivent pas faire de rotation de la clé publique statique ou de l’IV pendant que le router est en fonctionnement, que ce soit dans une adresse publiée ou non. Les routers doivent stocker de manière persistante cette clé et cet IV pour les réutiliser après un redémarrage immédiat, afin que les connexions entrantes continuent de fonctionner et que les temps de redémarrage ne soient pas exposés. Les routers doivent stocker de manière persistante, ou déterminer autrement, l’heure du dernier arrêt, afin que la durée d’arrêt précédente puisse être calculée au démarrage.
En raison des préoccupations concernant l’exposition des heures de redémarrage, les routeurs peuvent faire la rotation de cette clé ou de cet IV au démarrage si le routeur était précédemment hors ligne pendant un certain temps (au moins quelques heures).
Si le router a des RouterAddresses NTCP2 publiées (comme NTCP ou NTCP2), le temps d’arrêt minimum avant la rotation devrait être beaucoup plus long, par exemple un mois, sauf si l’adresse IP locale a changé ou si le router effectue un “rekeys”.
Si le router a des RouterAddresses SSU publiées, mais pas NTCP2 (comme NTCP ou NTCP2), le temps d’arrêt minimum avant la rotation devrait être plus long, par exemple une journée, sauf si l’adresse IP locale a changé ou si le router “rekeys”. Ceci s’applique même si l’adresse SSU publiée a des introducers.
Si le router n’a pas de RouterAddresses publiées (NTCP, NTCP2, ou SSU), le temps d’arrêt minimum avant la rotation peut être aussi court que deux heures, même si l’adresse IP change, à moins que le router ne “rekeys”.
Si le router “rekeys” vers un Router Hash différent, il devrait également générer une nouvelle clé noise et un nouvel IV.
Les implémentations doivent être conscientes que changer la clé publique statique ou l’IV empêchera les connexions NTCP2 entrantes provenant de routeurs qui ont mis en cache une RouterInfo plus ancienne. La publication de RouterInfo, la sélection des pairs de tunnel (y compris à la fois OBGW et le saut le plus proche IB), la sélection de tunnel à zéro saut, la sélection de transport, et d’autres stratégies d’implémentation doivent prendre cela en compte.
La rotation des IV est soumise aux mêmes règles que la rotation des clés, sauf que les IV ne sont présents que dans les RouterAddresses publiées, il n’y a donc pas d’IV pour les routeurs cachés ou derrière un pare-feu. Si quelque chose change (version, clé, options ?), il est recommandé que l’IV change également.
Note : Le temps d’arrêt minimum avant la regénération des clés peut être modifié pour assurer la santé du réseau et pour empêcher le reseeding par un router en panne pendant une durée modérée.
Détection de Version
Lorsque publié comme “NTCP”, le router doit automatiquement détecter la version du protocole pour les connexions entrantes.
Cette détection dépend de l’implémentation, mais voici quelques conseils généraux.
Pour détecter la version d’une connexion NTCP entrante, Bob procède comme suit :
Attendre au moins 64 octets (taille minimale du message NTCP2 1)
Si les données reçues initiales font 288 octets ou plus, la connexion entrante est en version 1.
Si moins de 288 octets, soit
- Attendre un court moment pour plus de données (bonne stratégie avant l’adoption généralisée de NTCP2) si au moins 288 octets ont été reçus au total, c’est NTCP 1. > > - Essayer les premières étapes de décodage en version 2, si cela échoue, attendre un court moment pour plus de données (bonne stratégie après l’adoption généralisée de NTCP2) > > > - Déchiffrer les 32 premiers octets (la clé X) du paquet SessionRequest en utilisant AES-256 avec la clé RH_B. > > - Vérifier un point valide sur la courbe. Si cela échoue, attendre un court moment pour plus de données pour NTCP 1 > > - Vérifier la trame AEAD. Si cela échoue, attendre un court moment pour plus de données pour NTCP 1
Notez que des changements ou des stratégies supplémentaires peuvent être recommandés si nous détectons des attaques actives de segmentation TCP sur NTCP 1.
Pour faciliter la détection rapide de version et l’établissement de liaison, les implémentations doivent s’assurer qu’Alice met en mémoire tampon puis vide l’intégralité du contenu du premier message d’un coup, y compris le remplissage. Cela augmente la probabilité que les données soient contenues dans un seul paquet TCP (sauf si segmentées par l’OS ou les middleboxes), et reçues d’un coup par Bob. C’est également pour l’efficacité et pour garantir l’efficacité du remplissage aléatoire. Ceci s’applique aux établissements de liaison NTCP et NTCP2.
Variantes, solutions de repli et problèmes généraux
- Si Alice et Bob supportent tous deux NTCP2, Alice devrait se connecter avec NTCP2.
- Si Alice échoue à se connecter à Bob en utilisant NTCP2 pour quelque raison que ce soit, la connexion échoue. Alice ne peut pas réessayer en utilisant NTCP 1.
Directives de décalage d’horloge
Les horodatages des pairs sont inclus dans les deux premiers messages de négociation, Session Request et Session Created. Un décalage d’horloge entre deux pairs supérieur à +/- 60 secondes est généralement fatal. Si Bob pense que son horloge locale est défaillante, il peut ajuster son horloge en utilisant le décalage calculé, ou une source externe. Sinon, Bob devrait répondre avec un Session Created même si le décalage maximal est dépassé, plutôt que de simplement fermer la connexion. Cela permet à Alice d’obtenir l’horodatage de Bob et de calculer le décalage, et de prendre des mesures si nécessaire. Bob n’a pas l’identité router d’Alice à ce moment-là, mais pour économiser les ressources, il peut être souhaitable pour Bob de bannir les connexions entrantes depuis l’IP d’Alice pendant une certaine période, ou après des tentatives de connexion répétées avec un décalage excessif.
Alice devrait ajuster le décalage d’horloge calculé en soustrayant la moitié du RTT. Si Alice pense que son horloge locale est défaillante, elle peut ajuster son horloge en utilisant le décalage calculé, ou une source externe. Si Alice pense que l’horloge de Bob est défaillante, elle peut bannir Bob pendant une certaine période de temps. Dans les deux cas, Alice devrait fermer la connexion.
Si Alice répond effectivement avec Session Confirmed (probablement parce que le décalage d’horloge est très proche de la limite de 60s, et que les calculs d’Alice et Bob ne sont pas exactement identiques en raison du RTT), Bob devrait ajuster le décalage d’horloge calculé en soustrayant la moitié du RTT. Si le décalage d’horloge ajusté dépasse le maximum, Bob devrait alors répondre avec un message Disconnect contenant un code de raison de décalage d’horloge, et fermer la connexion. À ce stade, Bob a l’identité du router d’Alice, et peut bannir Alice pendant une certaine période de temps.
Références
- Structures Communes
- I2NP
- Base de Données Réseau
- NOISE - Noise Protocol Framework
- NTCP
- Prop104
- Prop109
- Prop111
- RFC-2104 - HMAC
- RFC-3526 - Groupes DH
- RFC-6151
- RFC-7539 - ChaCha20-Poly1305
- RFC-7748 - X25519
- RFC-7905
- SipHash
- SSU
- [STS] Diffie, W.; van Oorschot P. C.; Wiener M. J., Authentification et Échanges de Clés Authentifiés