forked from I2P_Developers/i2p.www
prop 144 updates
This commit is contained in:
@@ -5,7 +5,7 @@ ECIES-X25519-AEAD-Ratchet
|
||||
:author: zzz, chisana
|
||||
:created: 2018-11-22
|
||||
:thread: http://zzz.i2p/topics/2639
|
||||
:lastupdated: 2019-09-14
|
||||
:lastupdated: 2019-09-18
|
||||
:status: Open
|
||||
|
||||
.. contents::
|
||||
@@ -269,23 +269,68 @@ Crypto type 0 is ElGamal.
|
||||
Crypto types 1-3 are reserved for ECIES-ECDH-AES-SessionTag, see proposal 145.
|
||||
|
||||
|
||||
Noise Protocol Framework
|
||||
------------------------
|
||||
|
||||
This proposal provides the requirements based on the Noise Protocol Framework
|
||||
[NOISE]_ (Revision 34, 2018-07-11).
|
||||
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 is based on the Noise protocol Noise_IK_25519_ChaChaPoly_SHA256.
|
||||
(The actual identifier for the initial key derivation function
|
||||
is "Noise_IKelg2_25519_ChaChaPoly_SHA256"
|
||||
to indicate I2P extensions - see KDF 1 section below)
|
||||
This Noise protocol uses the following primitives:
|
||||
|
||||
- Interactive Handshake Pattern: IK
|
||||
Alice immediately transmits her static key to Bob (I)
|
||||
Alice knows Bob's static key already (K)
|
||||
|
||||
- One-Way Handshake Pattern: N
|
||||
Alice does not transmit her static key to Bob (N)
|
||||
|
||||
- DH Function: X25519
|
||||
X25519 DH with a key length of 32 bytes as specified in [RFC-7748]_.
|
||||
|
||||
- Cipher Function: ChaChaPoly
|
||||
AEAD_CHACHA20_POLY1305 as specified in [RFC-7539]_ section 2.8.
|
||||
12 byte nonce, with the first 4 bytes set to zero.
|
||||
Identical to that in [NTCP2]_.
|
||||
|
||||
- Hash Function: SHA256
|
||||
Standard 32-byte hash, already used extensively in I2P.
|
||||
|
||||
|
||||
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.
|
||||
|
||||
1) Cleartext ephemeral keys are encoded with [Elligator2]_.ion using a known
|
||||
|
||||
2) The reply is prefixed with a cleartext tag.
|
||||
|
||||
3) The payload format is defined for messages 1, 2, and the data phase.
|
||||
Of course, this is not defined in Noise.
|
||||
|
||||
|
||||
|
||||
Handshake Patterns
|
||||
------------------
|
||||
|
||||
Handshakes similar to Noise handshake patterns: https://noiseprotocol.org/noise.html#handshake-patterns
|
||||
Handshakes are to [Noise]_ handshake patterns.
|
||||
|
||||
The following letter mapping is used:
|
||||
|
||||
- i = one-time ephemeral key
|
||||
- e = one-time ephemeral key
|
||||
- s = static key
|
||||
- p = message payload
|
||||
|
||||
One-time and Unbound sessions
|
||||
`````````````````````````````
|
||||
|
||||
Similar to the Noise N pattern.
|
||||
One-time and Unbound sessions are similar to the Noise N pattern.
|
||||
|
||||
.. raw:: html
|
||||
|
||||
@@ -296,19 +341,15 @@ Similar to the Noise N pattern.
|
||||
|
||||
{% endhighlight %}
|
||||
|
||||
Bound sessions
|
||||
``````````````
|
||||
|
||||
Similar to the Noise IK pattern, with an additional ephemeral key in the reply.
|
||||
TODO replace i with a tag?
|
||||
Bound sessions are similar to the Noise IK pattern.
|
||||
|
||||
.. raw:: html
|
||||
|
||||
{% highlight lang='dataspec' %}
|
||||
<- s
|
||||
...
|
||||
e es s ss p ->
|
||||
<- i si e ee se p
|
||||
e es p s ss p ->
|
||||
<- tag e ee se p
|
||||
|
||||
{% endhighlight %}
|
||||
|
||||
@@ -663,7 +704,7 @@ Encrypted:
|
||||
+ +
|
||||
| New Session Ephemeral Public Key |
|
||||
+ 32 bytes +
|
||||
| |
|
||||
| Encoded with Elligator2 |
|
||||
+ +
|
||||
| |
|
||||
+----+----+----+----+----+----+----+----+
|
||||
@@ -707,6 +748,9 @@ Encrypted:
|
||||
1c) New session format (without binding)
|
||||
----------------------------------------
|
||||
|
||||
If no reply is required, no static key is sent.
|
||||
|
||||
|
||||
Encrypted:
|
||||
|
||||
.. raw:: html
|
||||
@@ -716,8 +760,8 @@ Encrypted:
|
||||
| |
|
||||
+ +
|
||||
| New Session Ephemeral Public Key |
|
||||
+ +
|
||||
| |
|
||||
+ 32 bytes +
|
||||
| Encoded with Elligator2 |
|
||||
+ +
|
||||
| |
|
||||
+----+----+----+----+----+----+----+----+
|
||||
@@ -770,7 +814,7 @@ The payload section must contain an ACK Request block.
|
||||
-------------------------------------------
|
||||
|
||||
If only a single message is expected to be sent,
|
||||
no session setup or ephemeral key is required.
|
||||
no session setup or static key is required.
|
||||
|
||||
|
||||
Encrypted:
|
||||
@@ -782,8 +826,8 @@ Encrypted:
|
||||
| |
|
||||
+ +
|
||||
| Ephemeral Public Key |
|
||||
+ +
|
||||
| |
|
||||
+ 32 bytes +
|
||||
| Encoded with Elligator2 |
|
||||
+ +
|
||||
| |
|
||||
+----+----+----+----+----+----+----+----+
|
||||
@@ -902,7 +946,7 @@ Typical contents include the following blocks:
|
||||
================================== ============= ============
|
||||
Payload Block Type Type Number Block Length
|
||||
================================== ============= ============
|
||||
I2NP Message 3 varies
|
||||
Garlic Message 3 varies
|
||||
Options 5 9
|
||||
Next Key 7 37
|
||||
ACK Request 9 varies
|
||||
@@ -910,10 +954,10 @@ Padding 254 varies
|
||||
================================== ============= ============
|
||||
|
||||
|
||||
I2NP Message Contents
|
||||
Garlic Message Contents
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The I2NP message sent.
|
||||
The decrypted Garlic Message as specified in [I2NP]_.
|
||||
|
||||
|
||||
Options Contents
|
||||
@@ -972,8 +1016,6 @@ This is the "e" message pattern:
|
||||
Define ck = 32 byte chaining key. Copy the h data to ck.
|
||||
Set chainKey = h
|
||||
|
||||
Define rs = Bob's 32-byte static key as published in the RouterInfo
|
||||
|
||||
// MixHash(null prologue)
|
||||
h = SHA256(h);
|
||||
|
||||
@@ -1039,11 +1081,20 @@ This is the "e" message pattern:
|
||||
n = 0
|
||||
ad = h
|
||||
|
||||
End of "es" message pattern.
|
||||
|
||||
This is the "s" message pattern:
|
||||
|
||||
// MixHash(ciphertext)
|
||||
// Save for Payload section KDF
|
||||
h = SHA256(h || 64 byte encrypted flags/static key section)
|
||||
|
||||
End of "es" message pattern.
|
||||
// Alice's X25519 static keys
|
||||
ask = GENERATE_PRIVATE()
|
||||
apk = DERIVE_PUBLIC(ask)
|
||||
|
||||
End of "s" message pattern.
|
||||
|
||||
|
||||
{% endhighlight %}
|
||||
|
||||
@@ -1073,11 +1124,13 @@ This is the "ss" message pattern:
|
||||
n = 0
|
||||
ad = h
|
||||
|
||||
End of "ss" message pattern.
|
||||
|
||||
// MixHash(ciphertext)
|
||||
// Save for New Session Reply KDF
|
||||
h = SHA256(h || encrypted payload section)
|
||||
|
||||
End of "ss" message pattern.
|
||||
TODO tag = HKDF(...)
|
||||
|
||||
{% endhighlight %}
|
||||
|
||||
@@ -1085,6 +1138,10 @@ This is the "ss" message pattern:
|
||||
KDF for Payload Section (without Alice static key)
|
||||
``````````````````````````````````````````````````
|
||||
|
||||
Note that this is a Noise "N" pattern, but we use the same "IK" initializer
|
||||
as for bound sessions.
|
||||
|
||||
|
||||
.. raw:: html
|
||||
|
||||
{% highlight lang='text' %}
|
||||
@@ -1100,35 +1157,21 @@ chainKey = from Flags/Static key section
|
||||
1g) New Session Reply format
|
||||
----------------------------
|
||||
|
||||
TODO replace i with a tag?
|
||||
|
||||
Encrypted:
|
||||
|
||||
.. raw:: html
|
||||
|
||||
{% highlight lang='dataspec' %}
|
||||
+----+----+----+----+----+----+----+----+
|
||||
| |
|
||||
+ +
|
||||
| New Session Ephemeral Public Key |
|
||||
+ +
|
||||
| |
|
||||
+ +
|
||||
| |
|
||||
| Session Tag 8 bytes |
|
||||
+----+----+----+----+----+----+----+----+
|
||||
| |
|
||||
+ Ephemeral Key Section +
|
||||
| ChaCha20 encrypted data |
|
||||
+ 48 bytes +
|
||||
+ Ephemeral Public Key +
|
||||
| |
|
||||
+ 32 bytes +
|
||||
| Encoded with Elligator2 |
|
||||
+ +
|
||||
| |
|
||||
+ +
|
||||
| |
|
||||
+----+----+----+----+----+----+----+----+
|
||||
| Poly1305 Message Authentication Code |
|
||||
+ (MAC) for above section +
|
||||
| 16 bytes |
|
||||
+----+----+----+----+----+----+----+----+
|
||||
| |
|
||||
+ Payload Section +
|
||||
@@ -1143,9 +1186,11 @@ Encrypted:
|
||||
| 16 bytes |
|
||||
+----+----+----+----+----+----+----+----+
|
||||
|
||||
Tag :: 8 bytes, cleartext
|
||||
|
||||
Public Key :: 32 bytes, little endian, Elligator2, cleartext
|
||||
|
||||
Ephemeral Key Section encrypted data :: 48 bytes
|
||||
Ephemeral Key Section encrypted data :: 32 bytes
|
||||
|
||||
Payload Section encrypted data :: remaining data minus 16 bytes
|
||||
|
||||
@@ -1153,50 +1198,10 @@ Encrypted:
|
||||
|
||||
{% endhighlight %}
|
||||
|
||||
Decrypted:
|
||||
|
||||
Ephemeral Key Section Decrypted data
|
||||
````````````````````````````````````
|
||||
|
||||
The Ephemeral Key section contains flags and a key.
|
||||
It is always 48 bytes.
|
||||
|
||||
TODO don't need session ID?
|
||||
|
||||
.. raw:: html
|
||||
|
||||
{% highlight lang='dataspec' %}
|
||||
+----+----+----+----+----+----+----+----+
|
||||
| flags | unused | tsB |
|
||||
+----+----+----+----+----+----+----+----+
|
||||
| Session ID |
|
||||
+----+----+----+----+----+----+----+----+
|
||||
| |
|
||||
+ Ephemeral Key +
|
||||
| 32 bytes |
|
||||
+ +
|
||||
| |
|
||||
+ +
|
||||
| |
|
||||
+----+----+----+----+----+----+----+----+
|
||||
|
||||
flags :: 2 bytes
|
||||
bit order: 15 14 .. 3210
|
||||
bit 0: 1 for ephemeral key is to be used
|
||||
bit 1: 1 for the session ID to be used
|
||||
bit 2: 1 for New Session Reply (0 for New Session)
|
||||
bits 15-3: Unused, set to 0 for future compatibility
|
||||
unused :: 2 bytes, set to 0 for future compatibility
|
||||
tsB :: 4 bytes, seconds since epoch, big endian, rolls over in 2106
|
||||
sessionID :: session ID, 8 bytes.
|
||||
Uniquely identifies the session request this is a reply for.
|
||||
key :: the originator's ephemeral key, 32 bytes.
|
||||
|
||||
{% endhighlight %}
|
||||
|
||||
Alice must implement a Bloom filter or other mechanism to prevent replay attacks,
|
||||
using the date in the ephemeral key section. Specification TBD.
|
||||
|
||||
Notes
|
||||
`````
|
||||
The tag is generated in the New Session payload KDF.
|
||||
This correlates the reply to the session.
|
||||
|
||||
|
||||
Payload
|
||||
@@ -1215,83 +1220,52 @@ Optional blocks can have multiple I2NP blocks, but only a single padding block.
|
||||
If present, the padding block must be the final block.
|
||||
|
||||
|
||||
KDF for Ephemeral Key Section Encrypted Contents
|
||||
KDF for Payload Section Encrypted Contents
|
||||
````````````````````````````````````````````````
|
||||
|
||||
Same as Static Key Section in the New Session Message.
|
||||
Needs to be the same, because Alice will not know this is a reply
|
||||
until the Ephemeral Key Section is decrypted.
|
||||
|
||||
.. raw:: html
|
||||
|
||||
{% highlight lang='text' %}
|
||||
// Alice's X25519 static keys
|
||||
// apk is sent in original New Session message
|
||||
ask = GENERATE_PRIVATE()
|
||||
apk = DERIVE_PUBLIC(ask)
|
||||
// Keys from the New Session message
|
||||
// Alice's X25519 keys
|
||||
// apk and aepk are sent in original New Session message
|
||||
// ask = Alice private static key
|
||||
// apk = Alice public static key
|
||||
// aesk = Alice ephemeral private key
|
||||
// aepk = Alice ephemeral public key
|
||||
// Bob's X25519 static keys
|
||||
// bsk = Bob private static key
|
||||
// bpk = Bob public static key
|
||||
|
||||
// Bob's X25519 one-time-use ephemeral keys
|
||||
ibsk = GENERATE_PRIVATE_ELG2()
|
||||
ibpk = DERIVE_PUBLIC(ibsk)
|
||||
// ebpk is sent in cleartext in the
|
||||
// MixHash(tag)
|
||||
h = SHA256(h || tag)
|
||||
|
||||
This is the "e" message pattern:
|
||||
|
||||
// Bob's X25519 ephemeral keys
|
||||
besk = GENERATE_PRIVATE_ELG2()
|
||||
bepk = DERIVE_PUBLIC(besk)
|
||||
// elg2_bepk is sent in cleartext in the
|
||||
// beginning of the new session message
|
||||
ebpk = ENCODE_ELG2(ibpk)
|
||||
elg2_bepk = ENCODE_ELG2(bepk)
|
||||
// As decoded by Bob
|
||||
ibpk = DECODE_ELG2(ebpk)
|
||||
ibpk = DECODE_ELG2(elg2_bepk)
|
||||
|
||||
// Must be the same as the original New Session message
|
||||
// Alice doesn't know it's a reply yet
|
||||
INITIAL_ROOT_KEY = SHA256("144-ECIES-X25519-AEAD-Ratchet")
|
||||
End of "e" message pattern.
|
||||
|
||||
// Noise-like si
|
||||
sharedSecret = DH(ask, ibpk) = DH(ibsk, apk)
|
||||
This is the "ee" message pattern:
|
||||
|
||||
// MixKey(DH())
|
||||
// ChaChaPoly parameters to encrypt/decrypt
|
||||
keydata = HKDF(INITIAL_ROOT_KEY, sharedSecret, "NewSessionTmpKey", 64)
|
||||
chainKey = keydata[0:31]
|
||||
k = keydata[32:64]
|
||||
n = 0
|
||||
ad = SHA-256(ebpk)
|
||||
|
||||
// MixHash(ibpk)
|
||||
h = SHA256(h || encrypted payload section)
|
||||
|
||||
|
||||
{% endhighlight %}
|
||||
|
||||
|
||||
|
||||
KDF for Payload Section Encrypted Contents
|
||||
``````````````````````````````````````````
|
||||
|
||||
.. raw:: html
|
||||
|
||||
{% highlight lang='text' %}
|
||||
// Bob's X25519 ephemeral keys generated for the Ephemeral Key Section
|
||||
rbsk = GENERATE_PRIVATE()
|
||||
// rbpk decrypted by Alice in Ephemeral Key Section
|
||||
rbpk = DERIVE_PUBLIC(rbsk)
|
||||
|
||||
// Alice's X25519 ephemeral keys from original New Session Message
|
||||
rask = GENERATE_PRIVATE()
|
||||
// rapk was decrypted in original New Session Ephemeral Key Section
|
||||
rapk = DERIVE_PUBLIC(rask)
|
||||
|
||||
// Noise ee
|
||||
// MixKey(sharedSecret)
|
||||
// ChaChaPoly parameters to encrypt/decrypt
|
||||
// chainKey from original New Session Payload Section
|
||||
sharedSecret = DH(rask, rbpk) = DH(rbsk, rapk)
|
||||
sharedSecret = DH(aesk, bepk) = DH(besk, bepk)
|
||||
keydata = HKDF(chainKey, sharedSecret, "", 32)
|
||||
chainKey = keydata[0:31]
|
||||
|
||||
// Alice's X25519 static keys from original New Session Message
|
||||
ask = GENERATE_PRIVATE()
|
||||
// apk was decrypted in original New Session Static Key Section
|
||||
apk = DERIVE_PUBLIC(ask)
|
||||
End of "ee" message pattern.
|
||||
|
||||
This is the "se" message pattern:
|
||||
|
||||
// Noise se
|
||||
// MixKey(sharedSecret)
|
||||
sharedSecret = DH(ask, rbpk) = DH(rbsk, apk)
|
||||
keydata = HKDF(chainKey, sharedSecret, "", 64)
|
||||
@@ -1300,9 +1274,13 @@ KDF for Payload Section Encrypted Contents
|
||||
n = 0
|
||||
ad = SHA-256(rbpk)
|
||||
|
||||
End of "se" message pattern.
|
||||
|
||||
// MixHash()
|
||||
h = SHA256(h || encrypted payload section)
|
||||
|
||||
chainKey is used in the ratchet below.
|
||||
|
||||
{% endhighlight %}
|
||||
|
||||
Notes
|
||||
@@ -1964,7 +1942,7 @@ so the max unencrypted data is 65519 bytes.
|
||||
|
||||
blk :: 1 byte
|
||||
0-2 reserved
|
||||
3 I2NP message (Garlic Message only)
|
||||
3 Garlic Message
|
||||
4 termination
|
||||
5 options
|
||||
6 message number and previous message number (ratchet)
|
||||
@@ -1997,7 +1975,7 @@ the following blocks are required, in the following order:
|
||||
|
||||
Other allowed blocks:
|
||||
|
||||
- I2NP message (type 3)
|
||||
- Garlic message (type 3)
|
||||
- Padding (type 254)
|
||||
|
||||
In the new session reply message,
|
||||
@@ -2007,7 +1985,7 @@ the following blocks are required:
|
||||
|
||||
Other allowed blocks:
|
||||
|
||||
- I2NP message (type 3)
|
||||
- Garlic message (type 3)
|
||||
- Padding (type 254)
|
||||
|
||||
No other blocks are allowed.
|
||||
@@ -2026,11 +2004,11 @@ a single frame, but it is not prohibited.
|
||||
|
||||
|
||||
|
||||
I2NP Message
|
||||
Garlic Message
|
||||
````````````
|
||||
|
||||
An single I2NP message with a modified header.
|
||||
I2NP messages may not be fragmented across blocks or
|
||||
A single decrypted Garlic Message as specified in [I2NP]_.
|
||||
Garlic messages may not be fragmented across blocks or
|
||||
across ChaChaPoly frames.
|
||||
|
||||
This uses the first 9 bytes from the standard NTCP I2NP header,
|
||||
@@ -2056,11 +2034,11 @@ and remove the one-byte SHA256 checksum.
|
||||
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
|
||||
type :: 1 byte, I2NP msg type (11 for Garlic Message)
|
||||
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
|
||||
message :: Decrypted Garlic Message body
|
||||
|
||||
{% endhighlight %}
|
||||
|
||||
@@ -3163,6 +3141,12 @@ References
|
||||
https://www.imperialviolet.org/2013/12/25/elligator.html
|
||||
See also OBFS4 code
|
||||
|
||||
.. [I2NP]
|
||||
{{ spec_url('i2np') }}
|
||||
|
||||
.. [NTCP2]
|
||||
{{ spec_url('ntcp2') }}
|
||||
|
||||
.. [NOISE]
|
||||
http://noiseprotocol.org/noise.html
|
||||
|
||||
|
Reference in New Issue
Block a user