prop 144 updates

This commit is contained in:
zzz
2019-09-18 16:53:55 +00:00
parent 20c8d329e9
commit b9e95c75dc

View File

@@ -5,7 +5,7 @@ ECIES-X25519-AEAD-Ratchet
:author: zzz, chisana :author: zzz, chisana
:created: 2018-11-22 :created: 2018-11-22
:thread: http://zzz.i2p/topics/2639 :thread: http://zzz.i2p/topics/2639
:lastupdated: 2019-09-14 :lastupdated: 2019-09-18
:status: Open :status: Open
.. contents:: .. contents::
@@ -269,23 +269,68 @@ Crypto type 0 is ElGamal.
Crypto types 1-3 are reserved for ECIES-ECDH-AES-SessionTag, see proposal 145. 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 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: The following letter mapping is used:
- i = one-time ephemeral key
- e = one-time ephemeral key - e = one-time ephemeral key
- s = static key - s = static key
- p = message payload - p = message payload
One-time and Unbound sessions One-time and Unbound sessions are similar to the Noise N pattern.
`````````````````````````````
Similar to the Noise N pattern.
.. raw:: html .. raw:: html
@@ -296,19 +341,15 @@ Similar to the Noise N pattern.
{% endhighlight %} {% endhighlight %}
Bound sessions Bound sessions are similar to the Noise IK pattern.
``````````````
Similar to the Noise IK pattern, with an additional ephemeral key in the reply.
TODO replace i with a tag?
.. raw:: html .. raw:: html
{% highlight lang='dataspec' %} {% highlight lang='dataspec' %}
<- s <- s
... ...
e es s ss p -> e es p s ss p ->
<- i si e ee se p <- tag e ee se p
{% endhighlight %} {% endhighlight %}
@@ -663,7 +704,7 @@ Encrypted:
+ + + +
| New Session Ephemeral Public Key | | New Session Ephemeral Public Key |
+ 32 bytes + + 32 bytes +
| | | Encoded with Elligator2 |
+ + + +
| | | |
+----+----+----+----+----+----+----+----+ +----+----+----+----+----+----+----+----+
@@ -707,6 +748,9 @@ Encrypted:
1c) New session format (without binding) 1c) New session format (without binding)
---------------------------------------- ----------------------------------------
If no reply is required, no static key is sent.
Encrypted: Encrypted:
.. raw:: html .. raw:: html
@@ -716,8 +760,8 @@ Encrypted:
| | | |
+ + + +
| New Session Ephemeral Public Key | | 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, 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: Encrypted:
@@ -782,8 +826,8 @@ Encrypted:
| | | |
+ + + +
| Ephemeral Public Key | | 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 Payload Block Type Type Number Block Length
================================== ============= ============ ================================== ============= ============
I2NP Message 3 varies Garlic Message 3 varies
Options 5 9 Options 5 9
Next Key 7 37 Next Key 7 37
ACK Request 9 varies 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 Options Contents
@@ -972,8 +1016,6 @@ This is the "e" message pattern:
Define ck = 32 byte chaining key. Copy the h data to ck. Define ck = 32 byte chaining key. Copy the h data to ck.
Set chainKey = h Set chainKey = h
Define rs = Bob's 32-byte static key as published in the RouterInfo
// MixHash(null prologue) // MixHash(null prologue)
h = SHA256(h); h = SHA256(h);
@@ -1039,11 +1081,20 @@ This is the "e" message pattern:
n = 0 n = 0
ad = h ad = h
End of "es" message pattern.
This is the "s" message pattern:
// MixHash(ciphertext) // MixHash(ciphertext)
// Save for Payload section KDF // Save for Payload section KDF
h = SHA256(h || 64 byte encrypted flags/static key section) 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 %} {% endhighlight %}
@@ -1073,11 +1124,13 @@ This is the "ss" message pattern:
n = 0 n = 0
ad = h ad = h
End of "ss" message pattern.
// MixHash(ciphertext) // MixHash(ciphertext)
// Save for New Session Reply KDF // Save for New Session Reply KDF
h = SHA256(h || encrypted payload section) h = SHA256(h || encrypted payload section)
End of "ss" message pattern. TODO tag = HKDF(...)
{% endhighlight %} {% endhighlight %}
@@ -1085,6 +1138,10 @@ This is the "ss" message pattern:
KDF for Payload Section (without Alice static key) 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 .. raw:: html
{% highlight lang='text' %} {% highlight lang='text' %}
@@ -1100,35 +1157,21 @@ chainKey = from Flags/Static key section
1g) New Session Reply format 1g) New Session Reply format
---------------------------- ----------------------------
TODO replace i with a tag?
Encrypted: Encrypted:
.. raw:: html .. raw:: html
{% highlight lang='dataspec' %} {% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+ +----+----+----+----+----+----+----+----+
| | | Session Tag 8 bytes |
+ +
| New Session Ephemeral Public Key |
+ +
| |
+ +
| |
+----+----+----+----+----+----+----+----+ +----+----+----+----+----+----+----+----+
| | | |
+ Ephemeral Key Section + + Ephemeral Public Key +
| ChaCha20 encrypted data |
+ 48 bytes +
| | | |
+ 32 bytes +
| Encoded with Elligator2 |
+ + + +
| | | |
+ +
| |
+----+----+----+----+----+----+----+----+
| Poly1305 Message Authentication Code |
+ (MAC) for above section +
| 16 bytes |
+----+----+----+----+----+----+----+----+ +----+----+----+----+----+----+----+----+
| | | |
+ Payload Section + + Payload Section +
@@ -1143,9 +1186,11 @@ Encrypted:
| 16 bytes | | 16 bytes |
+----+----+----+----+----+----+----+----+ +----+----+----+----+----+----+----+----+
Tag :: 8 bytes, cleartext
Public Key :: 32 bytes, little endian, Elligator2, 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 Payload Section encrypted data :: remaining data minus 16 bytes
@@ -1153,50 +1198,10 @@ Encrypted:
{% endhighlight %} {% endhighlight %}
Decrypted: Notes
`````
Ephemeral Key Section Decrypted data The tag is generated in the New Session payload KDF.
```````````````````````````````````` This correlates the reply to the session.
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.
Payload 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. 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 .. raw:: html
{% highlight lang='text' %} {% highlight lang='text' %}
// Alice's X25519 static keys // Keys from the New Session message
// apk is sent in original New Session message // Alice's X25519 keys
ask = GENERATE_PRIVATE() // apk and aepk are sent in original New Session message
apk = DERIVE_PUBLIC(ask) // 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 // MixHash(tag)
ibsk = GENERATE_PRIVATE_ELG2() h = SHA256(h || tag)
ibpk = DERIVE_PUBLIC(ibsk)
// ebpk is sent in cleartext in the 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 // beginning of the new session message
ebpk = ENCODE_ELG2(ibpk) elg2_bepk = ENCODE_ELG2(bepk)
// As decoded by Bob // As decoded by Bob
ibpk = DECODE_ELG2(ebpk) ibpk = DECODE_ELG2(elg2_bepk)
// Must be the same as the original New Session message End of "e" message pattern.
// Alice doesn't know it's a reply yet
INITIAL_ROOT_KEY = SHA256("144-ECIES-X25519-AEAD-Ratchet")
// Noise-like si This is the "ee" message pattern:
sharedSecret = DH(ask, ibpk) = DH(ibsk, apk)
// 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) // MixKey(sharedSecret)
// ChaChaPoly parameters to encrypt/decrypt // ChaChaPoly parameters to encrypt/decrypt
// chainKey from original New Session Payload Section // 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) keydata = HKDF(chainKey, sharedSecret, "", 32)
chainKey = keydata[0:31] chainKey = keydata[0:31]
// Alice's X25519 static keys from original New Session Message End of "ee" message pattern.
ask = GENERATE_PRIVATE()
// apk was decrypted in original New Session Static Key Section This is the "se" message pattern:
apk = DERIVE_PUBLIC(ask)
// Noise se
// MixKey(sharedSecret) // MixKey(sharedSecret)
sharedSecret = DH(ask, rbpk) = DH(rbsk, apk) sharedSecret = DH(ask, rbpk) = DH(rbsk, apk)
keydata = HKDF(chainKey, sharedSecret, "", 64) keydata = HKDF(chainKey, sharedSecret, "", 64)
@@ -1300,9 +1274,13 @@ KDF for Payload Section Encrypted Contents
n = 0 n = 0
ad = SHA-256(rbpk) ad = SHA-256(rbpk)
End of "se" message pattern.
// MixHash() // MixHash()
h = SHA256(h || encrypted payload section) h = SHA256(h || encrypted payload section)
chainKey is used in the ratchet below.
{% endhighlight %} {% endhighlight %}
Notes Notes
@@ -1964,7 +1942,7 @@ so the max unencrypted data is 65519 bytes.
blk :: 1 byte blk :: 1 byte
0-2 reserved 0-2 reserved
3 I2NP message (Garlic Message only) 3 Garlic Message
4 termination 4 termination
5 options 5 options
6 message number and previous message number (ratchet) 6 message number and previous message number (ratchet)
@@ -1997,7 +1975,7 @@ the following blocks are required, in the following order:
Other allowed blocks: Other allowed blocks:
- I2NP message (type 3) - Garlic message (type 3)
- Padding (type 254) - Padding (type 254)
In the new session reply message, In the new session reply message,
@@ -2007,7 +1985,7 @@ the following blocks are required:
Other allowed blocks: Other allowed blocks:
- I2NP message (type 3) - Garlic message (type 3)
- Padding (type 254) - Padding (type 254)
No other blocks are allowed. 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. A single decrypted Garlic Message as specified in [I2NP]_.
I2NP messages may not be fragmented across blocks or Garlic messages may not be fragmented across blocks or
across ChaChaPoly frames. across ChaChaPoly frames.
This uses the first 9 bytes from the standard NTCP I2NP header, 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 blk :: 3
size :: 2 bytes, big endian, size of type + msg id + exp + message to follow size :: 2 bytes, big endian, size of type + msg id + exp + message to follow
I2NP message body size is (size - 9). 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 msg id :: 4 bytes, big endian, I2NP message ID
short exp :: 4 bytes, big endian, I2NP message expiration, Unix timestamp, unsigned seconds. short exp :: 4 bytes, big endian, I2NP message expiration, Unix timestamp, unsigned seconds.
Wraps around in 2106 Wraps around in 2106
message :: I2NP message body message :: Decrypted Garlic Message body
{% endhighlight %} {% endhighlight %}
@@ -3163,6 +3141,12 @@ References
https://www.imperialviolet.org/2013/12/25/elligator.html https://www.imperialviolet.org/2013/12/25/elligator.html
See also OBFS4 code See also OBFS4 code
.. [I2NP]
{{ spec_url('i2np') }}
.. [NTCP2]
{{ spec_url('ntcp2') }}
.. [NOISE] .. [NOISE]
http://noiseprotocol.org/noise.html http://noiseprotocol.org/noise.html