From b4f17d3ca0066b64eaf1480faf61b18cb5282f32 Mon Sep 17 00:00:00 2001 From: slumlord <slumlord@mail.i2p> Date: Wed, 4 Apr 2018 13:54:03 +0000 Subject: [PATCH] Proposal #111 - Improve formatting --- i2p2www/spec/proposals/111-ntcp-2.rst | 811 +++++++++++++------------- 1 file changed, 414 insertions(+), 397 deletions(-) diff --git a/i2p2www/spec/proposals/111-ntcp-2.rst b/i2p2www/spec/proposals/111-ntcp-2.rst index 1609f935e..2124b3846 100644 --- a/i2p2www/spec/proposals/111-ntcp-2.rst +++ b/i2p2www/spec/proposals/111-ntcp-2.rst @@ -6,7 +6,7 @@ NTCP 2 :editor: manas, str4d :created: 2014-02-13 :thread: http://zzz.i2p/topics/1577 - :lastupdated: 2018-04-02 + :lastupdated: 2018-04-04 :status: Open :supercedes: 106 @@ -15,8 +15,8 @@ NTCP 2 Note ==== -Major revisions in progress. For now, not necessarily complete or even consistent. -Not ready for implementation. +Major revisions in progress. For now, not necessarily complete or even +consistent. Not ready for implementation. Overview @@ -36,19 +36,19 @@ candidates for the authenticated cipher. Motivation ========== -[NTCP]_ data is encrypted after the first message (and the first message appears -to be random data), thus preventing protocol identification through "payload -analysis". It is still vulnerable to protocol identification through "flow -analysis". That's because the first 4 messages (i.e. the handshake) are fixed -length (288, 304, 448, and 48 bytes). +[NTCP]_ data is encrypted after the first message (and the first message +appears to be random data), thus preventing protocol identification through +"payload analysis". It is still vulnerable to protocol identification through +"flow analysis". That's because the first 4 messages (i.e. the handshake) are +fixed length (288, 304, 448, and 48 bytes). By adding random amounts of random data to each of the messages, we can make it a lot harder. -The authors acknowledge that standard security practices would suggest to use an -existing protocol such as TLS, but this is [Prop104]_ and it has problems of its -own. Wherever appropriate, "future work" paragraphs have been added to indicate -missing features or subjects of discussion. +The authors acknowledge that standard security practices would suggest to use +an existing protocol such as TLS, but this is [Prop104]_ and it has problems of +its own. Wherever appropriate, "future work" paragraphs have been added to +indicate missing features or subjects of discussion. Design Goals @@ -76,8 +76,8 @@ Design Goals Also ensure that the messages going to a single peer or set of peers do not have a similar pattern of bits. -- Fix loss of bits in DH due to Java format [Ticket1112]_, possibly - (probably?) by switching to X25519. +- Fix loss of bits in DH due to Java format [Ticket1112]_, possibly (probably?) + by switching to X25519. - Switch to a real key derivation function (KDF) rather than using the DH result as-is? @@ -88,9 +88,9 @@ Design Goals for our application. - Continue to use the variable-type, variable-length signatures (from the - published [RouterIdentity]_ signing key) as a part of authentication. - Rely on a static public key published in the RouterInfo as another - part of authentication. + published [RouterIdentity]_ signing key) as a part of authentication. Rely + on a static public key published in the RouterInfo as another part of + authentication. - Add options/version in handshake for future extensibility. @@ -99,8 +99,8 @@ Design Goals - Don't add significantly to CPU required for connection setup; if possible, reduce it significantly. -- Add message authentication (MAC), possibly HMAC-SHA256 and Poly1305, - and remove Adler checksum. +- Add message authentication (MAC), possibly HMAC-SHA256 and Poly1305, and + remove Adler checksum. - Shorten and simplify I2NP header: Shorten expiration to 4 bytes, as in SSU. @@ -131,7 +131,8 @@ Design Goals Non-Goals --------- -- Bullet-proof DPI resistance... that would be pluggable transports, [Prop109]_. +- Bullet-proof DPI resistance... that would be pluggable transports, + [Prop109]_. - A TLS-based (or HTTPS-lookalike) transport... that would be [Prop104]_. @@ -212,24 +213,24 @@ We assume two DPI components: 1) Online DPI ````````````` -Online DPI inspecting all flows in real-time. Connections may be blocked or otherwise -tampered with. Connection data or metadata may be identified and stored for offline analysis. -The online DPI does not have access to the I2P network database. -The online DPI has only limited real-time computational capability, including length -calculation, field inspection, and simple calculations such as XOR. -The online DPI does have the capability of fast real-time cryptographic functions -such as AES, AEAD, and hashing, but these would be too expensive to apply to -most or all flows. Any application of these cryptographic operations -would apply only to flows on IP/Port combinations previously identified by offline analysis. -The online DPI does not have the capability of high-overhead cryptographic functions -such as DH or elligator2. -The online DPI is not designed specifically to detect I2P, although it may have limited -classification rules for that purpose. +Online DPI inspecting all flows in real-time. Connections may be blocked or +otherwise tampered with. Connection data or metadata may be identified and +stored for offline analysis. The online DPI does not have access to the I2P +network database. The online DPI has only limited real-time computational +capability, including length calculation, field inspection, and simple +calculations such as XOR. The online DPI does have the capability of fast +real-time cryptographic functions such as AES, AEAD, and hashing, but these +would be too expensive to apply to most or all flows. Any application of these +cryptographic operations would apply only to flows on IP/Port combinations +previously identified by offline analysis. The online DPI does not have the +capability of high-overhead cryptographic functions such as DH or elligator2. +The online DPI is not designed specifically to detect I2P, although it may have +limited classification rules for that purpose. It is a goal to prevent protocol identification by an online DPI. -The notion of online or "straightforward" DPI is here taken to include the following -adversary capabilities: +The notion of online or "straightforward" DPI is here taken to include the +following adversary capabilities: 1) The ability to inspect all data sent or received by the target. @@ -248,11 +249,11 @@ However, the online DPI is assumed to have the following restrictions: 6) The inability to use timing information to detect the protocol. -7) Generally speaking, the online DPI toolbox does not contain any built-in tools - that are specifically designed for I2P detection. This includes creating - "honeypots", which would for example include nonrandom padding in their - messages. Note that this does not exclude machine learning systems or highly - configurable DPI tools as long as they meet the other requirements. +7) Generally speaking, the online DPI toolbox does not contain any built-in + tools that are specifically designed for I2P detection. This includes + creating "honeypots", which would for example include nonrandom padding in + their messages. Note that this does not exclude machine learning systems or + highly configurable DPI tools as long as they meet the other requirements. To counter payload analysis, it is ensured that all messages are indistinguishable from random. This also requires their length to be random, @@ -280,11 +281,11 @@ The offline DPI does have access to this and other I2P specifications. The offline DPI has unlimited computational capability, including all cryptographic functions defined in this specification. -The offline DPI does not have the ability to block existing connections. -The offline DPI does have the capability to do near-realtime (within minutes of setup) -sending to host/port of parties, for example TCP RST. -The offline DPI does have the capability to do near-realtime (within minutes of setup) -replay of previous messages (modified or not) for "probing" or other reasons. +The offline DPI does not have the ability to block existing connections. The +offline DPI does have the capability to do near-realtime (within minutes of +setup) sending to host/port of parties, for example TCP RST. The offline DPI +does have the capability to do near-realtime (within minutes of setup) replay +of previous messages (modified or not) for "probing" or other reasons. It is not a goal to prevent protocol identification by an offline DPI. All decoding of obfuscated data in the first two messages, which @@ -310,10 +311,10 @@ Future work Noise Protocol Framework ======================== -This proposal provides the requirements based on the -Noise Protocol Framework [NOISE]_. Noise has similar properties to the -Station-To-Station protocol [STS]_, which is the basis for the [SSU]_ protocol. -In Noise parlance, Alice is the initiator, and Bob is the responder. +This proposal provides the requirements based on the Noise Protocol Framework +[NOISE]_. Noise has similar properties to the Station-To-Station protocol +[STS]_, which is the basis for the [SSU]_ protocol. In Noise parlance, Alice +is the initiator, and Bob is the responder. The Noise Protocol Identifier for NTCP2 is Noise_XK_25519_ChaChaPoly_SHA256. This uses the following primitives: @@ -336,11 +337,12 @@ This uses the following primitives: Additions to the Framework ========================== -This proposal defines the following enhancements to Noise_XK_25519_ChaChaPoly_SHA256. -These generally follow the guidelines in [NOISE]_ section 13. +This proposal defines the following enhancements to +Noise_XK_25519_ChaChaPoly_SHA256. These generally follow the guidelines in +[NOISE]_ section 13. -1) Cleartext ephemeral keys are obfuscated with AES encryption using a known key and IV. - This is quicker than elligator2. +1) Cleartext ephemeral keys are obfuscated with AES encryption using a known + key and IV. This is quicker than elligator2. 2) Random cleartext padding is added to messages 1 and 2. The cleartext padding is included in the handshake hash calculation. @@ -357,16 +359,16 @@ These generally follow the guidelines in [NOISE]_ section 13. It of course is not defined in Noise. - Processing overhead estimate ============================ Message sizes for the 3 messages: -- 1) 64 bytes + padding (NTCP was 288 bytes) -- 2) 56 bytes + padding (NTCP was 304 bytes) -- 3) 66 bytes + Alice router info + padding Average router info is about 750 bytes Total average 816 bytes (NTCP was 448 bytes) -- 4) not required in NTCP2 (NTCP was 48 bytes) +1) 64 bytes + padding (NTCP was 288 bytes) +2) 56 bytes + padding (NTCP was 304 bytes) +3) 66 bytes + Alice router info + padding Average router info is about 750 + bytes Total average 816 bytes (NTCP was 448 bytes) +4) not required in NTCP2 (NTCP was 48 bytes) Total before padding: NTCP2: 936 bytes @@ -379,12 +381,14 @@ The following crypto operations are required by each party to complete the handshake and start the data phase: - AES: 2 -- SHA256: 8 (Alice), 6 (Bob) (not including 4 Alice, 6 Bob precalculated for all connections) (not including HMAC-SHA256) +- SHA256: 8 (Alice), 6 (Bob) (not including 4 Alice, 6 Bob precalculated for + all connections) (not including HMAC-SHA256) - HMAC-SHA256: 15 - ChaCha/Poly: 4 - X25519 DH: 3 - SipHash: 1 -- Signature verification: 1 (Bob) (Alice previously signed when generating her RI) Presumably Ed25519 (dependent on RI sigtype) +- Signature verification: 1 (Bob) (Alice previously signed when generating her + RI) Presumably Ed25519 (dependent on RI sigtype) The following crypto operations are required by each party for each data phase message: @@ -476,8 +480,7 @@ Inputs to the encryption/decryption functions: {% highlight lang='dataspec' %} - - k :: 32 byte cipher key, as generated from KDF +k :: 32 byte cipher key, as generated from KDF nonce :: Counter-based nonce, 12 bytes. Starts at 0 and incremented for each message. @@ -523,8 +526,6 @@ Output of the encryption function, input to the decryption function: encrypted data :: Same size as plaintext data - - {% endhighlight %} For ChaCha20, what is described here corresponds to [RFC-7539]_, which is also @@ -570,89 +571,90 @@ exactly as defined in the Noise spec. This is the "e" message pattern: -Define protocol_name. -Set protocol_name = "Noise_XK_25519_ChaChaPoly_SHA256" which is 32 bytes (US-ASCII encoded, no NULL termination). + Define protocol_name. + Set protocol_name = "Noise_XK_25519_ChaChaPoly_SHA256" which is 32 bytes + (US-ASCII encoded, no NULL termination). -Define Hash h = 32 bytes -h = SHA256(protocol_name); + Define Hash h = 32 bytes + h = SHA256(protocol_name); -Define ck = 32 byte chaining key. -Set ck = h + Define ck = 32 byte chaining key. + Set ck = h -Define rs = Bob's 32-byte static key as published in the RouterInfo + Define rs = Bob's 32-byte static key as published in the RouterInfo -// MixHash(null prologue) -h = SHA256(h); -// No Alice static key -// MixHash(null s) -h = SHA256(h); -// No Alice ephemeral key -// MixHash(null e) -h = SHA256(h); + // MixHash(null prologue) + h = SHA256(h); + // No Alice static key + // MixHash(null s) + h = SHA256(h); + // No Alice ephemeral key + // MixHash(null e) + h = SHA256(h); -// up until here, can all be precalculated by Alice for all outgoing connnections + // up until here, can all be precalculated by Alice for all outgoing connnections -// Alice must validate that Bob's static key is a valid point on the curve here. + // 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); -// No Bob ephemeral key -// MixHash(null re) -h = SHA256(h); + // Bob static key + // MixHash(rs) + // || below means append + h = SHA256(h || rs); + // No Bob ephemeral key + // MixHash(null re) + h = SHA256(h); -// up until here, can all be precalculated by Bob for all incoming connnections + // up until here, can all be precalculated by Bob for all incoming connnections -This is the "e" message pattern: + This is the "e" message pattern: -Alice generates her ephemeral DH keypair e. + Alice generates her ephemeral DH keypair e. -// Alice ephemeral key X -// MixHash(e.pubkey) -// || below means append -h = SHA256(h || e.pubkey); + // 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 + // 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. + End of "e" message pattern. -This is the "es" 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 + // 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()) + // 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, which is the hash of the noise name, defined above -temp_key = HMAC-SHA256(ck, input_key_material) -// overwrite the DH result in memory, no longer needed -input_key_material = (all zeros) + 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, which is the hash of the noise name, 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 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) + // 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 + // retain the chaining key ck for message 2 KDF -End of "es" message pattern. + End of "es" message pattern. {% endhighlight %} @@ -680,17 +682,21 @@ XK(s, rs): Authentication Confidentiality 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. + 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. + "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. + "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. {% endhighlight %} @@ -835,22 +841,21 @@ Note: All fields are big-endian. Notes ````` -- When the published address is "NTCP", Bob supports both NTCP and NTCP2 - on the same port. For compatibility, when initiating a connection - to an address published as "NTCP", Alice must limit the maximum - size of this message, including padding, to 287 bytes or less. - This facilitates automatic protocol identification by Bob. - When published as "NTCP2", there is no size restriction. - See the Published Addresses and Version Detection sections below. - -- The unique X value in the initial AES block ensure that the - ciphertext is different for every session. - -- Bob must reject connections where the timestamp value is too far off - from the current time. Call the maximum delta time "D". - Bob must maintain a local cache of previously-used handshake values - and reject duplicates, to prevent replay attacks. Values in the - cache must have a lifetime of at least 2*D. +- When the published address is "NTCP", Bob supports both NTCP and NTCP2 on the + same port. For compatibility, when initiating a connection to an address + published as "NTCP", Alice must limit the maximum size of this message, + including padding, to 287 bytes or less. This facilitates automatic protocol + identification by Bob. When published as "NTCP2", there is no size + restriction. See the Published Addresses and Version Detection sections + below. + +- The unique X value in the initial AES block ensure that the ciphertext is + different for every session. + +- Bob must reject connections where the timestamp value is too far off from the + current time. Call the maximum delta time "D". Bob must maintain a local + cache of previously-used handshake values and reject duplicates, to prevent + replay attacks. Values in the cache must have a lifetime of at least 2*D. The cache values are implementation-dependent, however the 32-byte X value (or its encrypted equivalent) may be used. @@ -864,28 +869,28 @@ Notes implicitly change the meaning of the "KE" flag to use a different KDF or a different truncation size. -- Bob must validate that Alice's ephemeral key is a valid point on the curve here. +- Bob must validate that Alice's ephemeral key is a valid point on the curve + here. -- Padding should be limited to a reasonable amount. - Bob may reject connections with excessive padding. - Bob will specify his padding options in message 2. +- Padding should be limited to a reasonable amount. Bob may reject connections + with excessive padding. Bob will specify his padding options in message 2. Min/max guidelines TBD. Random size from 0 to 31 bytes minimum? (Distribution to be determined, see Appendix A.) -- On any error, including AEAD, DH, timestamp, apparent replay, or key validation failure, - Bob must halt further message processing and close the connection without responding. - This should be an abnormal close (TCP RST). +- On any error, including AEAD, DH, timestamp, apparent replay, or key + validation failure, Bob must halt further message processing and close the + connection without responding. This should be an abnormal close (TCP RST). -- To facilitate rapid version detection and handshaking, implementations must ensure - that Alice buffers and then flushes the entire contents of the first message at once, - including the padding. - This increases the likelihood that the data will be contained in a single TCP packet - (unless segmented by the OS or middleboxes), and received all at once by Bob. - Additionally, implementations must ensure - that Bob buffers and then flushes the entire contents of the second message at once, - including the padding. - and that Bob buffers and then flushes the entire contents of the third message at once. - This is also for efficiency and to ensure the effectiveness of the random padding. +- To facilitate rapid version detection and handshaking, implementations must + ensure that Alice buffers and then flushes the entire contents of the first + message at once, including the padding. This increases the likelihood that + the data will be contained in a single TCP packet (unless segmented by the OS + or middleboxes), and received all at once by Bob. Additionally, + implementations must ensure that Bob buffers and then flushes the entire + contents of the second message at once, including the padding. and that Bob + buffers and then flushes the entire contents of the third message at once. + This is also for efficiency and to ensure the effectiveness of the random + padding. Issues @@ -905,61 +910,61 @@ Key Derivation Function (KDF) (for handshake message 2) {% highlight lang='text' %} // probably do this also: -h = SHA256(h || random padding from message 1) + h = SHA256(h || random padding from message 1) -This is the "e" message pattern: + This is the "e" message pattern: -Bob generates his ephemeral DH keypair e. + Bob generates his ephemeral DH keypair 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 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 + // 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. + End of "e" message pattern. -This is the "ee" 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) + // 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()) + // 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) + 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 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) + // 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 + // retain the chaining key ck for message 3 KDF -End of "es" message pattern. + End of "es" message pattern. {% endhighlight %} @@ -1003,19 +1008,16 @@ XK(s, rs): Authentication Confidentiality {% endhighlight %} -The Y value is encrypted to ensure payload indistinguishably -and uniqueness, which are necessary DPI countermeasures. -We use AES encryption to achieve this, -rather than more complex and slower alternatives such as elligator2. -Asymmetric encryption to Alice's router public key would be far too slow. -AES encryption uses Bob's router hash as the key and -the AES state from message 1 (which was initialized with -Bob's IV as published in the network database). +The Y value is encrypted to ensure payload indistinguishably and uniqueness, +which are necessary DPI countermeasures. We use AES encryption to achieve +this, rather than more complex and slower alternatives such as elligator2. +Asymmetric encryption to Alice's router public key would be far too slow. AES +encryption uses Bob's router hash as the key and the AES state from message 1 +(which was initialized with Bob's IV as published in the network database). -AES encryption is for DPI resistance only. -Any party knowing Bob's router hash and IV, which are published in the network database, -and captured the first 32 bytes of message 1, -may decrypt the Y value in this message. +AES encryption is for DPI resistance only. Any party knowing Bob's router hash +and IV, which are published in the network database, and captured the first 32 +bytes of message 1, may decrypt the Y value in this message. Raw contents: @@ -1094,15 +1096,15 @@ Unencrypted data: Notes ````` -- Alice must reject connections where the timestamp value is too far off - from the current time. Call the maximum delta time "D". - Alice must maintain a local cache of previously-used handshake values - and reject duplicates, to prevent replay attacks. Values in the - cache must have a lifetime of at least 2*D. - The cache values are implementation-dependent, however the 32-byte Y value - (or its encrypted equivalent) may be used. +- Alice must reject connections where the timestamp value is too far off from + the current time. Call the maximum delta time "D". Alice must maintain a + local cache of previously-used handshake values and reject duplicates, to + prevent replay attacks. Values in the cache must have a lifetime of at least + 2*D. The cache values are implementation-dependent, however the 32-byte Y + value (or its encrypted equivalent) may be used. -- Alice must validate that Bob's ephemeral key is a valid point on the curve here. +- Alice must validate that Bob's ephemeral key is a valid point on the curve + here. - Padding should be limited to a reasonable amount. Alice may reject connections with excessive padding. @@ -1110,16 +1112,16 @@ Notes Min/max guidelines TBD. Random size from 0 to 31 bytes minimum? (Distribution to be determined, see Appendix A.) -- On any error, including AEAD, DH, timestamp, apparent replay, or key validation failure, - Alice must halt further message processing and close the connection without responding. - This should be an abnormal close (TCP RST). +- On any error, including AEAD, DH, timestamp, apparent replay, or key + validation failure, Alice must halt further message processing and close the + connection without responding. This should be an abnormal close (TCP RST). -- To facilitate rapid handshaking, implementations must ensure - that Bob buffers and then flushes the entire contents of the first message at once, - including the padding. - This increases the likelihood that the data will be contained in a single TCP packet - (unless segmented by the OS or middleboxes), and received all at once by Alice. - This is also for efficiency and to ensure the effectiveness of the random padding. +- To facilitate rapid handshaking, implementations must ensure that Bob buffers + and then flushes the entire contents of the first message at once, including + the padding. This increases the likelihood that the data will be contained + in a single TCP packet (unless segmented by the OS or middleboxes), and + received all at once by Alice. This is also for efficiency and to ensure the + effectiveness of the random padding. Issues @@ -1154,25 +1156,25 @@ Encryption for for handshake message 3 part 1, using message 1 KDF) {% highlight lang='text' %} // probably do this also: -h = SHA256(h || random padding from message 2) -// h is used as the associated data for the AEAD in message 3 part 1, below + 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: + This is the "s" message pattern: -Define s = Alice's static public key, 32 bytes + Define s = Alice's static public key, 32 bytes -// EncryptAndHash(s.publickey) -// EncryptWithAd(h, s.publickey) -// k is from handshake message 1 -// n is 1 -ciphertext = ENCRYPT(k, n++, h, s.publickey) -// MixHash(ciphertext) -// || below means append -h = SHA256(h || ciphertext); + // EncryptAndHash(s.publickey) + // EncryptWithAd(h, s.publickey) + // k is from handshake message 1 + // n is 1 + ciphertext = ENCRYPT(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 + // h is used as the associated data for the AEAD in message 3 part 2 -End of "s" message pattern. + End of "s" message pattern. {% endhighlight %} @@ -1186,53 +1188,53 @@ Key Derivation Function (KDF) (for handshake message 3 part 2) 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) + // 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()) + // 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) + 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 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)). + // 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)). -// retain the chaining key ck for the data phase KDF + // retain the chaining key ck for the data phase KDF -End of "se" message pattern. + End of "se" message pattern. -KDF for SipHash for length field: -SipHash uses two 8-byte keys (big endian) and 8 byte IV for first data. + KDF for SipHash for length field: + SipHash uses two 8-byte keys (big endian) and 8 byte IV for first data. -Alice to Bob SipHash k1, k2, IV: + Alice to Bob SipHash k1, k2, IV: -sipkeys_ab = HMAC-SHA256(temp_key, k_ba || byte(0x03)). -sipk1_ab = sipkeys[0:7] -sipk2_ab = sipkeys[8:15] -sipiv_ab = sipkeys[16:23] + sipkeys_ab = HMAC-SHA256(temp_key, k_ba || byte(0x03)). + sipk1_ab = sipkeys[0:7] + sipk2_ab = sipkeys[8:15] + sipiv_ab = sipkeys[16:23] -// overwrite the temp_key in memory, no longer needed -temp_key = (all zeros) + // overwrite the temp_key in memory, no longer needed + temp_key = (all zeros) {% endhighlight %} @@ -1255,30 +1257,35 @@ 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. + 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. + 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. + "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. + "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. {% endhighlight %} This contains two ChaCha/Poly frames. The first is Alice's encrypted static public key. -The second is the Noise payload: Alice's encrypted RouterInfo, optional options, and optional padding. -They use different keys, because the MixKey() function is called in between. +The second is the Noise payload: Alice's encrypted RouterInfo, optional +options, and optional padding. They use different keys, because the MixKey() +function is called in between. Raw contents: @@ -1391,15 +1398,16 @@ Notes - Options should be included, to specify padding parameters. - On any error, including AEAD, RI, DH, timestamp, or key validation failure, - Bob must halt further message processing and close the connection without responding. - This should be an abnormal close (TCP RST). + Bob must halt further message processing and close the connection without + responding. This should be an abnormal close (TCP RST). -- To facilitate rapid handshaking, implementations must ensure - that Alice buffers and then flushes the entire contents of the third message at once, +- To facilitate rapid handshaking, implementations must ensure that Alice + buffers and then flushes the entire contents of the third message at once, including both AEAD blocks. - This increases the likelihood that the data will be contained in a single TCP packet - (unless segmented by the OS or middleboxes), and received all at once by Bob. - This is also for efficiency and to ensure the effectiveness of the random padding. + This increases the likelihood that the data will be contained in a single TCP + packet (unless segmented by the OS or middleboxes), and received all at once + by Bob. This is also for efficiency and to ensure the effectiveness of the + random padding. @@ -1419,38 +1427,38 @@ This is the Split() function, exactly as defined in the Noise spec. ck = from handshake phase -// 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) + // 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 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)). + // 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: -SipHash uses two 8-byte keys (big endian) and 8 byte IV for first data. + KDF for SipHash for length field: + SipHash uses two 8-byte keys (big endian) and 8 byte IV for first data. -Alice to Bob SipHash k1, k2, IV: + Alice to Bob SipHash k1, k2, IV: -sipkeys_ab = HMAC-SHA256(temp_key, k_ba || byte(0x03)). -sipk1_ab = sipkeys[0:7] -sipk2_ab = sipkeys[8:15] -sipiv_ab = sipkeys[16:23] + sipkeys_ab = HMAC-SHA256(temp_key, k_ba || byte(0x03)). + sipk1_ab = sipkeys[0:7] + sipk2_ab = sipkeys[8:15] + sipiv_ab = sipkeys[16:23] -Bob to Alice SipHash k1, k2, IV: + Bob to Alice SipHash k1, k2, IV: -sipkeys_ba = HMAC-SHA256(temp_key, sipkeys_ab || byte(0x04)). -sipk1_ba = sipkeys[0:7] -sipk2_ba = sipkeys[8:15] -sipiv_ba = sipkeys[16:23] + sipkeys_ba = HMAC-SHA256(temp_key, sipkeys_ab || byte(0x04)). + sipk1_ba = sipkeys[0:7] + sipk2_ba = sipkeys[8:15] + sipiv_ba = sipkeys[16:23] -// overwrite the temp_key in memory, no longer needed -temp_key = (all zeros) + // overwrite the temp_key in memory, no longer needed + temp_key = (all zeros) {% endhighlight %} @@ -1525,7 +1533,7 @@ Following is from obfs4: {% highlight lang='text' %} - Once both sides have completed the handshake, they transfer application + Once both sides have completed the handshake, they transfer application data broken up into "packets", that are then encrypted and authenticated in NaCl crypto_secretbox_xsalsa20poly1305 [5] "frames". @@ -1960,7 +1968,8 @@ before connecting using the NTCP2 protocol. When published as "NTCP" with "n", "s", "i", and "v" options, the router must accept incoming connections on that host and port -for both NTCP and NTCP2 protocols, and automatically detect the protocol version. +for both NTCP and NTCP2 protocols, and automatically detect the protocol +version. When published as "NTCP2" with "n", "s", "i", and "v" options, the router accepts incoming connections on that host and port @@ -1984,7 +1993,8 @@ she must include her Noise static public key in her RouterInfo options. The option name is N(shortened Noise name)(NTCP2 Version)s. - NNXK2CS2s=(Base64 key) - Name shortened from (N)TCP2 (N)oise_(XK)_(2)5519_(C)haChaPoly_(S)HA256 version (2) (s)tatic key. + Name shortened from (N)TCP2 (N)oise_(XK)_(2)5519_(C)haChaPoly_(S)HA256 + version (2) (s)tatic key. Future options will be named similarly, with 6 chars to represent the 5 Noise name fields. The current Noise static public key (s) for this Router. @@ -1998,43 +2008,45 @@ Public Key and IV Rotation -------------------------- Due to caching of RouterInfos, routers must not rotate the static public key -while the router is up, whether in a published address or not. Routers must persistently store this key -for reuse after an immediate restart, so incoming connections will -continue to work, and restart times are not exposed. -Routers must persistently store, or otherwise determine, -last-shutdown time, so that the previous downtime may be calculated at startup. - -Subject to concerns about exposing restart times, -routers may rotate this key at startup if the router was previously down -for some time (a couple hours at least). - -If the router has any published NTCP2 RouterAddresses (as NTCP or NTCP2), -the minimum downtime before rotation should be much longer, for example one month, +while the router is up, whether in a published address or not. Routers must +persistently store this key for reuse after an immediate restart, so incoming +connections will continue to work, and restart times are not exposed. Routers +must persistently store, or otherwise determine, last-shutdown time, so that +the previous downtime may be calculated at startup. + +Subject to concerns about exposing restart times, routers may rotate this key +at startup if the router was previously down for some time (a couple hours at +least). + +If the router has any published NTCP2 RouterAddresses (as NTCP or NTCP2), the +minimum downtime before rotation should be much longer, for example one month, unless the local IP address has changed or the router "rekeys". -If the router has any published SSU RouterAddresses, but not NTCP2 (as NTCP or NTCP2) -the minimum downtime before rotation should be longer, for example one day, -unless the local IP address has changed or the router "rekeys". -This applies even if the published SSU address has introducers. +If the router has any published SSU RouterAddresses, but not NTCP2 (as NTCP or +NTCP2) the minimum downtime before rotation should be longer, for example one +day, unless the local IP address has changed or the router "rekeys". This +applies even if the published SSU address has introducers. -If the router does not have any published RouterAddresses (NTCP, NTCP2, or SSU), -the minimum downtime before rotation may be as short as two hours, -even if the IP address changes, unless the router "rekeys". +If the router does not have any published RouterAddresses (NTCP, NTCP2, or +SSU), the minimum downtime before rotation may be as short as two hours, even +if the IP address changes, unless the router "rekeys". -If the router "rekeys" to a different Router Hash, it should generate -a new noise key as well. +If the router "rekeys" to a different Router Hash, it should generate a new +noise key as well. Implementations must be aware that changing the static public key will prohibit incoming NTCP2 connections from routers that have cached an older RouterInfo. -RouterInfo publishing, tunnel peer selection (including both OBGW and IB closest hop), -zero-hop tunnel selection, transport selection, and other implementation strategies -must take this into account. +RouterInfo publishing, tunnel peer selection (including both OBGW and IB +closest hop), zero-hop tunnel selection, transport selection, and other +implementation strategies must take this into account. -IV rotation is subject to identical rules, except that IVs are not present except in -published RouterAddresses, so there is no IV for hidden or firewalled routers. +IV rotation is subject to identical rules, except that IVs are not present +except in published RouterAddresses, so there is no IV for hidden or firewalled +routers. -Note: The minimum downtime before rekeying may be modified to ensure network health, -and to prevent reseeding by a router down for a moderate amount of time. +Note: The minimum downtime before rekeying may be modified to ensure network +health, and to prevent reseeding by a router down for a moderate amount of +time. @@ -2043,19 +2055,21 @@ Identity Hiding ``````````````` Deniability is not a goal. See overview above. -Each pattern is assigned properties describing the confidentiality supplied to the initiator's static public key, -and to the responder's static public key. -The underlying assumptions are that ephemeral private keys are secure, -and that parties abort the handshake if they receive a static public key from the other party which they don't trust. +Each pattern is assigned properties describing the confidentiality supplied to +the initiator's static public key, and to the responder's static public key. +The underlying assumptions are that ephemeral private keys are secure, and that +parties abort the handshake if they receive a static public key from the other +party which they don't trust. -This section only considers identity leakage through static public key fields in handshakes. -Of course, the identities of Noise participants might be exposed through other means, -including payload fields, traffic analysis, or metadata such as IP addresses. +This section only considers identity leakage through static public key fields +in handshakes. Of course, the identities of Noise participants might be +exposed through other means, including payload fields, traffic analysis, or +metadata such as IP addresses. Alice: (8) Encrypted with forward secrecy to an authenticated party. -Bob: (3) Not transmitted, but a passive attacker can check candidates for the responder's private key -and determine whether the candidate is correct. +Bob: (3) Not transmitted, but a passive attacker can check candidates for the +responder's private key and determine whether the candidate is correct. Bob publishes his static public key in the netdb. Alice may or may not? @@ -2069,8 +2083,9 @@ Issues Version Detection ================= -When published as "NTCP", the router must automatically detect -the protocol version for incoming connections. +When published as "NTCP", the router must automatically detect the protocol +version for incoming connections. + This detection is implementation-dependent, but here is some general guidance. To detect the version of an incoming NTCP connection, Bob proceeds as follows: @@ -2080,12 +2095,11 @@ To detect the version of an incoming NTCP connection, Bob proceeds as follows: is version 1. - If less than 288 bytes, either - - Wait for a short time for more data - (good strategy before widespread NTCP2 adoption) - if at least 288 total received, it's NTCP 1. + - Wait for a short time for more data (good strategy before widespread NTCP2 + adoption) if at least 288 total received, it's NTCP 1. - - Try the first stages of decoding as version 2, if it fails, wait a short time for more data - (good strategy after widespread NTCP2 adoption) + - Try the first stages of decoding as version 2, if it fails, wait a short + time for more data (good strategy after widespread NTCP2 adoption) - Decrypt the first 32 bytes (the X key) of the SessionRequest packet using AES-256 with key RH_B. @@ -2099,12 +2113,13 @@ To detect the version of an incoming NTCP connection, Bob proceeds as follows: Note that changes or additional strategies may be recommended if we detect active TCP segmentation attacks on NTCP 1. -To facilitate rapid version detection and handshaking, implementations must ensure -that Alice buffers and then flushes the entire contents of the first message at once, -including the padding. -This increases the likelihood that the data will be contained in a single TCP packet -(unless segmented by the OS or middleboxes), and received all at once by Bob. -This is also for efficiency and to ensure the effectiveness of the random padding. +To facilitate rapid version detection and handshaking, implementations must +ensure that Alice buffers and then flushes the entire contents of the first +message at once, including the padding. +This increases the likelihood that the data will be contained in a single TCP +packet (unless segmented by the OS or middleboxes), and received all at once by +Bob. This is also for efficiency and to ensure the effectiveness of the random +padding. This applies to both NTCP and NTCP2 handshakes. @@ -2113,14 +2128,16 @@ Variants, Fallbacks, and General Issues - If Alice and Bob both support NTCP2, Alice should connect with NTCP2. -- If Alice fails to connect to Bob using NTCP2 for any reason, the connection fails. +- If Alice fails to connect to Bob using NTCP2 for any reason, the connection + fails. Alice may not retry using old NTCP 1. -- Fallback to XX pattern if Bob changes his keys? This would require a type byte prepended? +- Fallback to XX pattern if Bob changes his keys? This would require a type + byte prepended? -- "Fall forward" to KK pattern if Alice reconnects, assuming Bob still has her static key? - This doesn't save any round trips and uses 4 DH rounds compared to 3 for XK. - Probably not. +- "Fall forward" to KK pattern if Alice reconnects, assuming Bob still has her + static key? This doesn't save any round trips and uses 4 DH rounds compared + to 3 for XK. Probably not. .. raw:: html @@ -2137,11 +2154,11 @@ Variants, Fallbacks, and General Issues Appendix A: Padding Scheme ========================== -This section discusses an attack on typical padding schemes that allows attackers to -discover the probability distribution of the length of the unpadded messages, by -only observing the length of the padded messages. Let N be a random variable -describing the number of unpadded bytes, and P likewise for the number of -padding bytes. The total message size is then N + P. +This section discusses an attack on typical padding schemes that allows +attackers to discover the probability distribution of the length of the +unpadded messages, by only observing the length of the padded messages. Let N +be a random variable describing the number of unpadded bytes, and P likewise +for the number of padding bytes. The total message size is then N + P. Assume that for an unpadded size of n, at least ``P_min(n) >= 0`` and at most ``P_max(n) >= P_min(n)`` bytes of padding are added in a padding scheme. The -- GitLab