forked from I2P_Developers/i2p.www
prop. 159: updates
- Switch from AES to ChaCha20 for header encryption - Switch from router hash to intro key for header encryption - Extend the receiver loop section
This commit is contained in:
@ -2,10 +2,10 @@
|
||||
SSU2
|
||||
======
|
||||
.. meta::
|
||||
:author: orignal, zlatinb, zzz
|
||||
:author: eyedeekay, orignal, zlatinb, zzz
|
||||
:created: 2021-09-12
|
||||
:thread: http://zzz.i2p/topics/2612
|
||||
:lastupdated: 2021-10-24
|
||||
:lastupdated: 2021-10-26
|
||||
:status: Open
|
||||
:target: 0.9.55
|
||||
|
||||
@ -223,7 +223,7 @@ 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
|
||||
real-time cryptographic functions such as ChaCha20, 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
|
||||
@ -2418,7 +2418,7 @@ is the initiator, and Bob is the responder.
|
||||
|
||||
SSU2 is based on the Noise protocol Noise_XK_25519_ChaChaPoly_SHA256.
|
||||
(The actual identifier for the initial key derivation function
|
||||
is "Noise_XKaesobfse+hs1+hs2+hs3_25519_ChaChaPoly_SHA256"
|
||||
is "Noise_XKchaobfse+hs1+hs2+hs3_25519_ChaChaPoly_SHA256"
|
||||
to indicate I2P extensions - see KDF 1 section below)
|
||||
|
||||
NOTE: This identifier is different than that used for NTCP2, because
|
||||
@ -2448,7 +2448,7 @@ 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
|
||||
1) Cleartext ephemeral keys are obfuscated with ChaCha20 encryption using a known
|
||||
key and IV. This is quicker than elligator2.
|
||||
|
||||
|
||||
@ -2634,11 +2634,6 @@ XK(s, rs): Authentication Confidentiality
|
||||
|
||||
Once a session has been established, Alice and Bob can exchange Data messages.
|
||||
|
||||
Some notations::
|
||||
|
||||
- RH_A = Router Hash for Alice (32 bytes)
|
||||
- RH_B = Router Hash for Bob (32 bytes)
|
||||
|
||||
|
||||
Packet Header
|
||||
---------------
|
||||
@ -2791,25 +2786,39 @@ The header (before obfuscation and protection) is always included in the associa
|
||||
data for the AEAD function, to cryptographically bind the header to the data.
|
||||
|
||||
|
||||
Header Obfuscation
|
||||
Header Decryption
|
||||
```````````````````
|
||||
Both the long and short headers are always obfuscated with AES-CBC using
|
||||
(generally) the destination router hash and IV.
|
||||
|
||||
For SessionCreated, where the destination router hash and IV are not yet known,
|
||||
the source router hash and IV are used.
|
||||
Headers are encrypted with a known key published in the network database.
|
||||
This is for DPI resistance only, as the key is public and the
|
||||
key and nonces are reused, so it is effectively just obfuscation.
|
||||
Note that the header encryption is also used to obfuscate
|
||||
the ephemeral keys X (in Session Request) and Y (in Session Created).
|
||||
|
||||
TODO ChaCha20 instead?
|
||||
The short header is always encrypted (obfuscated) with ChaCha20 using
|
||||
the destination's intro key and n=0.
|
||||
|
||||
The first 16 bytes of the long header is usually encrypted (obfuscated) with ChaCha20 using
|
||||
the destination's intro key and n=0.
|
||||
For Session Request, the same key is used with n=1 for the next 48 bytes (covering X as well).
|
||||
For other messages, the same key is used with n=1 for the next 16 bytes.
|
||||
|
||||
For Session Created and Retry, where the destination router hash and IV are not yet known,
|
||||
the source intro key is used to decrypt the long header,
|
||||
with n=0 for the first 16 bytes.
|
||||
For Session Created, n=1 is used for the next 48 bytes (covering Y as well).
|
||||
For Retry, n=1 is used for the next 16 bytes.
|
||||
|
||||
See the Inbound Packet Handling section below for additional guidance.
|
||||
|
||||
|
||||
Header Protection
|
||||
```````````````````
|
||||
In addition to obfuscation, bytes 8-15 of the long header and bytes 8-12 of the short header
|
||||
In addition to obfuscation, bytes 8-15 of the header
|
||||
are encrypted by XORing with a known key, as in QUIC [RFC-9001]_ and [Nonces]_.
|
||||
|
||||
For SessionCreated, where the destination router hash and IV are not yet known,
|
||||
the source router hash and IV are used.
|
||||
For SessionCreated, where the destination (Alice's) intro key is not yet known,
|
||||
the source (Bob's) intro key is used.
|
||||
|
||||
There are four header protection key phases:
|
||||
|
||||
@ -2975,7 +2984,7 @@ KDF for Initial ChainKey
|
||||
{% highlight lang='text' %}
|
||||
|
||||
// Define protocol_name.
|
||||
Set protocol_name = "Noise_XKaesobfse+hs1+hs2+hs3_25519_ChaChaPoly_SHA256"
|
||||
Set protocol_name = "Noise_XKchaobfse+hs1+hs2+hs3_25519_ChaChaPoly_SHA256"
|
||||
(52 bytes, US-ASCII encoded, no NULL termination).
|
||||
|
||||
// Define Hash h = 32 bytes
|
||||
@ -3104,13 +3113,13 @@ XK(s, rs): Authentication Confidentiality
|
||||
|
||||
The X value is encrypted to ensure payload indistinguishably
|
||||
and uniqueness, which are necessary DPI countermeasures.
|
||||
We use AES encryption to achieve this,
|
||||
We use ChaCha20 encryption to achieve this,
|
||||
rather than more complex and slower alternatives such as elligator2.
|
||||
Asymmetric encryption to Bob's router public key would be far too slow.
|
||||
AES encryption uses Bob's router hash as the key and Bob's IV as published
|
||||
ChaCha20 encryption uses Bob's intro key as published
|
||||
in the network database.
|
||||
|
||||
AES encryption is for DPI resistance only.
|
||||
ChaCha20 encryption is for DPI resistance only.
|
||||
Any party knowing Bob's router hash, and IV, which are published in the network database,
|
||||
may decrypt the X value in this message.
|
||||
|
||||
@ -3121,18 +3130,18 @@ Raw contents:
|
||||
|
||||
{% highlight lang='dataspec' %}
|
||||
+----+----+----+----+----+----+----+----+
|
||||
| |
|
||||
+ obfuscated with RH_B +
|
||||
| AES-CBC-256 encrypted |
|
||||
+ bytes 8-15 header protected +
|
||||
| Long Header |
|
||||
+ (32 bytes) +
|
||||
| Long Header bytes 0-15, ChaCha20 |
|
||||
+ encrypted with Bob intro key n=0 +
|
||||
| bytes 8-15 header protected |
|
||||
+----+----+----+----+----+----+----+----+
|
||||
| Long Header bytes 16-31, ChaCha20 |
|
||||
+ encrypted with Bob intro key n=1 +
|
||||
| |
|
||||
+----+----+----+----+----+----+----+----+
|
||||
| |
|
||||
+ obfuscated with RH_B +
|
||||
| AES-CBC-256 encrypted X |
|
||||
+ (32 bytes) +
|
||||
+ X, ChaCha20 encrypted +
|
||||
| with Bob intro key n=1 |
|
||||
+ (32 bytes) +
|
||||
| |
|
||||
+ +
|
||||
| |
|
||||
@ -3150,9 +3159,10 @@ Raw contents:
|
||||
| |
|
||||
+----+----+----+----+----+----+----+----+
|
||||
|
||||
X :: 32 bytes, AES-256-CBC encrypted X25519 ephemeral key, little endian
|
||||
key: RH_B
|
||||
iv: As published in Bobs network database entry
|
||||
X :: 32 bytes, ChaCha20 encrypted X25519 ephemeral key, little endian
|
||||
key: Bob's intro key
|
||||
n: 1
|
||||
data: 48 bytes (bytes 16-31 of the header, followed by encrypted X)
|
||||
|
||||
{% endhighlight %}
|
||||
|
||||
@ -3215,7 +3225,7 @@ Notes
|
||||
restriction. See the Published Addresses and Version Detection sections
|
||||
below.
|
||||
|
||||
- The unique X value in the initial AES block ensure that the ciphertext is
|
||||
- The unique X value in the initial ChaCha20 block ensure that the ciphertext is
|
||||
different for every session.
|
||||
|
||||
- Bob must reject connections where the timestamp value is too far off from the
|
||||
@ -3364,14 +3374,14 @@ 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
|
||||
which are necessary DPI countermeasures. We use ChaCha20 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 Session Request
|
||||
(which was initialized with Bob's IV as published in the network database).
|
||||
Asymmetric encryption to Alice's router public key would be far too slow. ChaCha20
|
||||
encryption uses Bob's intro key,
|
||||
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
|
||||
ChaCha20 encryption is for DPI resistance only. Any party knowing Bob's intro key,
|
||||
which is published in the network database, and captured the first 32
|
||||
bytes of Session Request, may decrypt the Y value in this message.
|
||||
|
||||
|
||||
@ -3381,17 +3391,17 @@ Raw contents:
|
||||
|
||||
{% highlight lang='dataspec' %}
|
||||
+----+----+----+----+----+----+----+----+
|
||||
| |
|
||||
+ obfuscated with RH_B +
|
||||
| AES-CBC-256 encrypted |
|
||||
+ bytes 8-15 header protected +
|
||||
| Long Header |
|
||||
+ (32 bytes) +
|
||||
| Long Header bytes 0-15, ChaCha20 |
|
||||
+ encrypted with Bob intro key n=0 +
|
||||
| bytes 8-15 header protected |
|
||||
+----+----+----+----+----+----+----+----+
|
||||
| Long Header bytes 16-31, ChaCha20 |
|
||||
+ encrypted with Bob intro key n=1 +
|
||||
| |
|
||||
+----+----+----+----+----+----+----+----+
|
||||
| |
|
||||
+ obfuscated with RH_B +
|
||||
| AES-CBC-256 encrypted Y |
|
||||
+ Y, ChaCha20 encrypted +
|
||||
| with Bob intro key n=1 |
|
||||
+ (32 bytes) +
|
||||
| |
|
||||
+ +
|
||||
@ -3410,9 +3420,10 @@ Raw contents:
|
||||
| |
|
||||
+----+----+----+----+----+----+----+----+
|
||||
|
||||
Y :: 32 bytes, AES-256-CBC encrypted X25519 ephemeral key, little endian
|
||||
key: RH_B
|
||||
iv: Using AES state from Session Request
|
||||
Y :: 32 bytes, ChaCha20 encrypted X25519 ephemeral key, little endian
|
||||
key: Bob's intro key
|
||||
n: 1
|
||||
data: 48 bytes (bytes 16-31 of the header, followed by encrypted Y)
|
||||
|
||||
{% endhighlight %}
|
||||
|
||||
@ -3933,12 +3944,12 @@ Raw contents:
|
||||
|
||||
{% highlight lang='dataspec' %}
|
||||
+----+----+----+----+----+----+----+----+
|
||||
| |
|
||||
+ obfuscated with RH_B +
|
||||
| AES-CBC-256 encrypted |
|
||||
+ bytes 8-15 header protected +
|
||||
| Long Header |
|
||||
+ (32 bytes) +
|
||||
| Long Header bytes 0-15, ChaCha20 |
|
||||
+ encrypted with Bob intro key n=0 +
|
||||
| bytes 8-15 header protected |
|
||||
+----+----+----+----+----+----+----+----+
|
||||
| Long Header bytes 16-31, ChaCha20 |
|
||||
+ encrypted with Bob intro key n=1 +
|
||||
| |
|
||||
+----+----+----+----+----+----+----+----+
|
||||
| |
|
||||
@ -4002,6 +4013,9 @@ It is not bound to the Session Request message other than by connection IDs.
|
||||
It is not required to decrypt the Session Request Noise message to create this
|
||||
message in response.
|
||||
|
||||
Minimum size: TBD, same rules as for Session Created?
|
||||
|
||||
|
||||
|
||||
Hole Punch Message
|
||||
-------------------------------
|
||||
@ -5563,11 +5577,11 @@ to indicate SSU2 support:
|
||||
32 bytes in binary, 44 bytes as Base 64 encoded,
|
||||
little-endian X25519 public key.
|
||||
|
||||
- i=(Base64 IV)
|
||||
The current IV for encrypting the headers for this RouterAddress.
|
||||
- i=(Base64 key)
|
||||
The current introduction key for encrypting the headers for this RouterAddress.
|
||||
Base 64 encoded using the standard I2P Base 64 alphabet.
|
||||
16 bytes in binary, 24 bytes as Base 64 encoded,
|
||||
big-endian.
|
||||
32 bytes in binary, 44 bytes as Base 64 encoded,
|
||||
big-endian ChaCha20 key.
|
||||
|
||||
- v=2
|
||||
The current version (2).
|
||||
@ -5658,7 +5672,7 @@ 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 and IV as well.
|
||||
noise key and intro key as well.
|
||||
|
||||
Implementations must be aware that changing the static public key or IV will prohibit
|
||||
incoming SSU2 connections from routers that have cached an older RouterInfo.
|
||||
@ -5666,10 +5680,7 @@ 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 as key rotation, except that IVs are not present
|
||||
except in published RouterAddresses, so there is no IV for hidden or firewalled
|
||||
routers. If anything changes (version, key, options?) it is recommended that
|
||||
the IV change as well.
|
||||
Intro key rotation is subject to identical rules as key rotation.
|
||||
|
||||
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
|
||||
@ -5718,29 +5729,117 @@ and recover the contents.
|
||||
|
||||
SSU 2 is designed to minimize the inbound packet classification effort while maintaining
|
||||
DPI resistance and other on-path threats. The session number is included in the header
|
||||
for all message types, and obfuscated using AES with a known key and IV.
|
||||
for all message types, and encyrpted (obfuscated) using ChaCha20 with a known key and nonce.
|
||||
Additionally, the message type is also included in the header
|
||||
(encrypted with header protection to a known key and then obfuscated with AES)
|
||||
(encrypted with header protection to a known key and then obfuscated with ChaCha20)
|
||||
and may be used for additional classification.
|
||||
In no case should a trial DH operation be necessary to classify a packet.
|
||||
In no case is a trial DH or other asymmetric crypto operation necessary to classify a packet.
|
||||
|
||||
For almost all messages from all peers, the AES key and IV are the destination router's
|
||||
router hash and IV as published in the netdb.
|
||||
For almost all messages from all peers, the ChaCha20 key is the destination router's
|
||||
router hash as published in the netdb, with a nonce of 0 for the short header
|
||||
(and for the first 16 bytes of the long header).
|
||||
The next 16 bytes of the long header, and the ephemeral key, are decrypted with
|
||||
the same key and a nonce of 1.
|
||||
|
||||
The only exceptions are the first messages sent from Bob to Alice (Session Created or Retry)
|
||||
where Alice's router hash is not yet known to Bob. In these cases, Bob's router hash
|
||||
and IV are used.
|
||||
is used as the key, with a nonce of 0 for the short header
|
||||
(and for the first 16 bytes of the long header).
|
||||
The next 16 bytes of the long header, and the ephemeral key, are decrypted with
|
||||
the same key and a nonce of 1.
|
||||
|
||||
Therefore, the recommended processing steps are:
|
||||
The protocol is designed to minimize packet classification processing that
|
||||
might require additional crypto operations in multiple
|
||||
fallback steps or complex heuristics.
|
||||
Additionally, the vast majority of received packets will not require
|
||||
a (possibly expensive) fallback lookup by source IP/port
|
||||
and a second header decryption.
|
||||
Only Session Created and Retry (and possibly others TBD) will require
|
||||
the fallback processing.
|
||||
|
||||
|
||||
Therefore, the recommended processing steps in the receiver loop logic are:
|
||||
|
||||
1) Decrypt the first 16 bytes with ChaCha20 using the local router hash
|
||||
as the key with n=0, to recover the session ID.
|
||||
If the session ID matches a current or pending inbound session:
|
||||
a) Using the session's header protection key, remove the header protection
|
||||
to recover the version, net ID, and message type at bytes 8-15.
|
||||
b) If the message type is Session Confirmed, it is a long header.
|
||||
Verify the net ID and protocol version are valid.
|
||||
Decrypt the next 16 bytes of the header with ChaCha20
|
||||
using the local router hash as the key. Then decrypt the message with
|
||||
Noise, using the decrypted 32-byte header as the AD.
|
||||
c) If the message type is valid but not Session Confirmed,
|
||||
it is a short header.
|
||||
Verify the net ID and protocol version are valid.
|
||||
decrypt the rest of the message with ChaCha20/Poly1305
|
||||
using the session key, using the decrypted 16-byte header
|
||||
as the AD.
|
||||
d) (optional) If session ID is a pending inbound session
|
||||
awaiting a Session Confirmed message,
|
||||
but the net ID, protocol, or message type is not valid,
|
||||
it could be a Data message received out-of-order before the
|
||||
Session Confirmed, so the data phase header protection keys are not yet known,
|
||||
and the header bytes 8-15 were incorrectly decrypted.
|
||||
Queue the message, and attempt to decrypt it once the
|
||||
Session Confirmed message is received.
|
||||
e) If b) or c) fails, drop the message.
|
||||
|
||||
2) If the session ID does not match a current session:
|
||||
Check the plaintext header at bytes 8-15 are valid
|
||||
(without doing any header protection operaion).
|
||||
Verify the net ID and protocol version are valid, and
|
||||
the message type is Session Request, or other message type
|
||||
allowed out-of-session (TBD).
|
||||
a) If all is valid and the message type is Session Request,
|
||||
decrypt the next 16 bytes of the header and the 32-byte X value
|
||||
with ChaCha20 using the local router hash as the key with n=1.
|
||||
- If the token at header bytes 24-31 is accepted, decrypt the
|
||||
message with Noise, using the decrypted 32-byte header as the AD.
|
||||
Send a Session Created in response.
|
||||
- If the token is not accepted, send a Retry message to the
|
||||
source IP/port with a token. Do not attempt to
|
||||
decrypt the message with Noise to avoid DDoS attacks.
|
||||
b) If the message type is some other message that is valid
|
||||
out-of-session, presumably with a short header,
|
||||
decrypt the rest of the message with ChaCha20/Poly1305
|
||||
using the intro key (TBD), using the decrypted 16-byte header
|
||||
as the AD. Process the message.
|
||||
c) If a) or b) fails, go to step 3)
|
||||
|
||||
|
||||
3) Look up a pending outbound session by the source IP/port of the packet.
|
||||
a) If found, decrypt the first 16 bytes with ChaCha20 using Bob's router hash
|
||||
as the key with n=0, to recover the session ID.
|
||||
b) If the session ID matches the pending session:
|
||||
Using the TBD key, remove the header protection
|
||||
to recover the version, net ID, and message type at bytes 8-15.
|
||||
Verify the net ID and protocol version are valid, and
|
||||
the message type is Session Response or Retry, or other message type
|
||||
allowed out-of-session (TBD).
|
||||
- If all is valid and the message type is Session Response,
|
||||
decrypt the next 16 bytes of the header and the 32-byte Y value
|
||||
with ChaCha20 using Bob's router hash as the key with n=1.
|
||||
Decrypt the message with Noise, using the decrypted 32-byte header as the AD.
|
||||
Send a Session Confirmed in response.
|
||||
- If all is valid and the message type is Retry,
|
||||
decrypt the next 16 bytes of the header
|
||||
with ChaCha20 using Bob's router hash as the key with n=1.
|
||||
Validate the remaining data (padding) and MAC using ChaCha20/Poly1305 using
|
||||
TBD as the key and TBD as the nonce and the decrypted 32-byte header as the AD.
|
||||
Resend a Session Request with the received token in response.
|
||||
- If the message type is some other message that is valid
|
||||
out-of-session, presumably with a short header,
|
||||
decrypt the rest of the message with ChaCha20/Poly1305
|
||||
using the intro key (TBD), using the decrypted 16-byte header
|
||||
as the AD. Process the message.
|
||||
c) If a pending outbound session is not found,
|
||||
or the session ID does not match the pending session, drop the message,
|
||||
unless the port is shared with SSU 1.
|
||||
|
||||
4) If running SSU 1 on the same port, attempt to process the message as an SSU 1 packet.
|
||||
|
||||
1) Remove the AES obfuscation to recover the session ID. If known, use that session
|
||||
for further processing.
|
||||
2) Remove the header protection to recover the version, net ID, message type,
|
||||
and packet number fields. If all are sensible, and the message type is 0 (Session Request),
|
||||
create a new session and use that session for further processing.
|
||||
3) Look up a pending outbound session by the source IP/port of the packet;
|
||||
if found, remove the session ID obfuscation using Bob's router hash and IV,
|
||||
verify the session ID matches, and use that pending session for further processing.
|
||||
|
||||
|
||||
Issues
|
||||
|
Reference in New Issue
Block a user