forked from I2P_Developers/i2p.www
prop 144 updates
This commit is contained in:
@@ -5,7 +5,7 @@ ECIES-X25519-AEAD-Ratchet
|
||||
:author: zzz
|
||||
:created: 2018-11-22
|
||||
:thread: http://zzz.i2p/topics/2639
|
||||
:lastupdated: 2019-04-03
|
||||
:lastupdated: 2019-04-06
|
||||
:status: Open
|
||||
|
||||
.. contents::
|
||||
@@ -186,16 +186,15 @@ Existing I2P router implementations will require implementations for
|
||||
the following standard cryptographic primitives,
|
||||
which are not required for current I2P protocols:
|
||||
|
||||
1) ECIES (but this is essentially X25519)
|
||||
- ECIES (but this is essentially X25519)
|
||||
- Elligator2
|
||||
|
||||
Existing I2P router implementations that have not yet implemented NTCP2 (Proposal 111)
|
||||
will also require implementations for:
|
||||
|
||||
1) X25519 key generation and DH
|
||||
|
||||
2) AEAD_ChaCha20_Poly1305 (abbreviated as ChaChaPoly below)
|
||||
|
||||
3) HKDF
|
||||
- X25519 key generation and DH
|
||||
- AEAD_ChaCha20_Poly1305 (abbreviated as ChaChaPoly below)
|
||||
- HKDF
|
||||
|
||||
|
||||
Detailed Proposal
|
||||
@@ -448,8 +447,8 @@ Alice-Bob new session message:
|
||||
- 3 byte I2NP block overhead ?
|
||||
- 16 byte Poly1305 tag
|
||||
|
||||
Total:
|
||||
212 bytes
|
||||
Total:
|
||||
212 bytes
|
||||
{% endhighlight %}
|
||||
|
||||
Bob-Alice existing session message:
|
||||
@@ -590,6 +589,74 @@ Multicast
|
||||
TBD
|
||||
|
||||
|
||||
Definitions
|
||||
-----------
|
||||
We define the following functions corresponding to the cryptographic building blocks used.
|
||||
|
||||
ZEROLEN
|
||||
zero-length byte array
|
||||
|
||||
CSRNG(n)
|
||||
n-byte output from a cryptographically-secure random number generator.
|
||||
|
||||
H(p, d)
|
||||
SHA-256 hash function that takes a personalization string p and data d, and
|
||||
produces an output of length 32 bytes.
|
||||
|
||||
Use SHA-256 as follows::
|
||||
|
||||
H(p, d) := SHA-256(p || d)
|
||||
|
||||
STREAM
|
||||
The ChaCha20/Poly1305 AEAD as specified in [RFC-7539]_.
|
||||
S_KEY_LEN = 32 and S_IV_LEN = 12.
|
||||
|
||||
ENCRYPT(k, n, plaintext, ad)
|
||||
Encrypts plaintext using the cipher key k, and nonce n which MUST be unique for
|
||||
the key k.
|
||||
Associated data ad is optional.
|
||||
Returns a ciphertext that is the size of the plaintext + 16 bytes for the HMAC.
|
||||
|
||||
The entire ciphertext must be indistinguishable from random if the key is secret.
|
||||
|
||||
DECRYPT(k, n, ciphertext, ad)
|
||||
Decrypts ciphertext using the cipher key k, and nonce n.
|
||||
Associated data ad is optional.
|
||||
Returns the plaintext.
|
||||
|
||||
DH
|
||||
X25519 public key agreement system. Private keys of 32 bytes, public keys of 32
|
||||
bytes, produces outputs of 32 bytes. It has the following
|
||||
functions:
|
||||
|
||||
GENERATE_PRIVATE()
|
||||
Generates a new private key.
|
||||
|
||||
DERIVE_PUBLIC(privkey)
|
||||
Returns the public key corresponding to the given private key.
|
||||
|
||||
GENERATE_PRIVATE_ELG2()
|
||||
Generates a new private key suitable for Elligator2.
|
||||
|
||||
DERIVE_PUBLIC_ELG2(privkey)
|
||||
Returns the Elligator2 public key corresponding to the given private key (inverse mapping).
|
||||
|
||||
MAP_PUBLIC_ELG2(pubkey)
|
||||
Returns the public key corresponding to the given Elligator2 public key.
|
||||
|
||||
DH(privkey, pubkey)
|
||||
Generates a shared secret from the given private and public keys.
|
||||
|
||||
HKDF(salt, ikm, info, n)
|
||||
A cryptographic key derivation function which takes some input key material ikm (which
|
||||
should have good entropy but is not required to be a uniformly random string), a salt
|
||||
of length 32 bytes, and a context-specific 'info' value, and produces an output
|
||||
of n bytes suitable for use as key material.
|
||||
|
||||
Use HKDF as specified in [RFC-5869]_, using the HMAC hash function SHA-256
|
||||
as specified in [RFC-2104]_. This means that SALT_LEN is 32 bytes max.
|
||||
|
||||
|
||||
|
||||
1) Message format
|
||||
-----------------
|
||||
@@ -742,9 +809,8 @@ Some recommended strategies include:
|
||||
1a) New session format
|
||||
----------------------
|
||||
|
||||
Public key (32 bytes)
|
||||
Nonce (8 bytes)
|
||||
Encrypted data and MAC (see section 3 below)
|
||||
New Session One Time Public key (32 bytes)
|
||||
Encrypted data and MAC (remaining bytes)
|
||||
|
||||
|
||||
Format
|
||||
@@ -757,28 +823,12 @@ Encrypted:
|
||||
+----+----+----+----+----+----+----+----+
|
||||
| |
|
||||
+ +
|
||||
| New Session Public Key |
|
||||
| New Session One Time Public Key |
|
||||
+ +
|
||||
| |
|
||||
+ +
|
||||
| |
|
||||
+----+----+----+----+----+----+----+----+
|
||||
| Nonce 8 bytes |
|
||||
+----+----+----+----+----+----+----+----+
|
||||
| |
|
||||
+ +
|
||||
| ChaCha20 encrypted data |
|
||||
+ +
|
||||
| |
|
||||
+ +
|
||||
| |
|
||||
+ +
|
||||
| |
|
||||
+----+----+----+----+----+----+----+----+
|
||||
| Poly1305 Message Authentication Code |
|
||||
+ (MAC) +
|
||||
| 16 bytes |
|
||||
+----+----+----+----+----+----+----+----+
|
||||
| |
|
||||
+ +
|
||||
| ChaCha20 encrypted data |
|
||||
@@ -794,64 +844,156 @@ Encrypted:
|
||||
|
||||
Public Key :: 32 bytes, little endian, cleartext
|
||||
|
||||
Nonce :: 8 bytes, little endian? cleartext
|
||||
encrypted data :: remaining data minus 16 bytes
|
||||
|
||||
encrypted data 1 :: 55 bytes
|
||||
|
||||
MAC 1 :: Poly1305 message authentication code, 16 bytes
|
||||
|
||||
encrypted data 2 :: Same size as plaintext data, Size varies
|
||||
|
||||
MAC 2 :: Poly1305 message authentication code, 16 bytes
|
||||
MAC :: Poly1305 message authentication code, 16 bytes
|
||||
|
||||
{% endhighlight %}
|
||||
|
||||
|
||||
Decrypted data 1:
|
||||
|
||||
See AEAD section below.
|
||||
Encrypted length is 71 bytes.
|
||||
Decrypted length is 55 bytes.
|
||||
Contents must be the following blocks in the following order:
|
||||
|
||||
================================== ============= ============
|
||||
Payload Block Type Type Number Block Length
|
||||
================================== ============= ============
|
||||
Options 5 9
|
||||
Message Number 6 9
|
||||
Next Key 7 37
|
||||
================================== ============= ============
|
||||
Block Total 55
|
||||
HMAC 16
|
||||
Total 71
|
||||
================================== ============= ============
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Decrypted data 2:
|
||||
Decrypted data
|
||||
``````````````
|
||||
|
||||
See AEAD section below.
|
||||
Encrypted length is the remainder of the data.
|
||||
Decrypted length is 16 less than the encrypted length.
|
||||
All types are supported.
|
||||
All block types are supported.
|
||||
Typical contents include the following blocks:
|
||||
|
||||
================================== ============= ============
|
||||
Payload Block Type Type Number Block Length
|
||||
================================== ============= ============
|
||||
DateTime 0 7
|
||||
I2NP Message 3 varies
|
||||
Options 5 9
|
||||
Message Number 6 9
|
||||
Next Key 7 37
|
||||
ACK Request 9 varies
|
||||
Padding 254 varies
|
||||
================================== ============= ============
|
||||
|
||||
|
||||
DateTime Message Contents
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The current time.
|
||||
|
||||
|
||||
I2NP Message Contents
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The I2NP message sent.
|
||||
|
||||
|
||||
Options Contents
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
- STL = 8
|
||||
|
||||
|
||||
Message Number Contents
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Key ID = 0
|
||||
- PN = 0
|
||||
- N starts with 0, incremented with every new session message sent with this key
|
||||
|
||||
|
||||
Next Key Contents
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Key ID = 0
|
||||
- Key = Alice's first ratchet public key rapk (See KDF for part 2 below),
|
||||
remains constant for every new session message for this session
|
||||
|
||||
|
||||
ACK Request Contents
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Delivery instructions for the ack.
|
||||
|
||||
|
||||
Padding Contents
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
As desired.
|
||||
|
||||
|
||||
|
||||
|
||||
KDF
|
||||
```
|
||||
|
||||
KDF for Encrypted Contents
|
||||
``````````````````````````
|
||||
|
||||
.. raw:: html
|
||||
|
||||
{% highlight lang='text' %}
|
||||
See message key ratchet below.
|
||||
// Bob's X25519 static keys
|
||||
// bpk is published in leaseset
|
||||
bsk = GENERATE_PRIVATE()
|
||||
bpk = DERIVE_PUBLIC(bsk)
|
||||
|
||||
// Alice's X25519 one-time-use ephemeral keys
|
||||
ask = GENERATE_PRIVATE_ELG2()
|
||||
// eapk is sent in cleartext in the
|
||||
// beginning of the new session message
|
||||
eapk = DERIVE_PUBLIC_ELG2(ask)
|
||||
apk = MAP_PUBLIC_ELG2(eapk)
|
||||
|
||||
INITIAL_ROOT_KEY = SHA256("144-ECIES-X25519-AEAD-Ratchet")
|
||||
|
||||
sharedSecret = DH(ask, bpk) = DH(bsk, apk)
|
||||
|
||||
// ChaChaPoly parameters to encrypt/decrypt part 1
|
||||
k = HKDF(INITIAL_ROOT_KEY, sharedSecret, "NewSessionTmpKey", 32)
|
||||
n = 0
|
||||
ad = SHA-256(eapk)
|
||||
|
||||
{% endhighlight %}
|
||||
|
||||
|
||||
|
||||
KDF for Ratchets
|
||||
````````````````
|
||||
|
||||
.. raw:: html
|
||||
|
||||
{% highlight lang='text' %}
|
||||
// Bob's X25519 static keys
|
||||
// bpk is published in leaseset
|
||||
bsk = GENERATE_PRIVATE()
|
||||
bpk = DERIVE_PUBLIC(bsk)
|
||||
|
||||
// Alice's first ratchet X25519 ephemeral keys
|
||||
rask = GENERATE_PRIVATE()
|
||||
// rapk is sent encrypted in part 1
|
||||
// of the new session message
|
||||
rapk = DERIVE_PUBLIC(rask)
|
||||
|
||||
INITIAL_ROOT_KEY = SHA256("144-ECIES-X25519-AEAD-Ratchet")
|
||||
|
||||
sharedSecret = DH(rask, bpk) = DH(bsk, rapk)
|
||||
|
||||
// KDF_RK(rk, dh_out)
|
||||
keydata = HKDF(INITIAL_ROOT_KEY, sharedSecret, "FirstRatchetStep", 64)
|
||||
nextRootKey = keydata[0:31]
|
||||
ck = keydata[32:63]
|
||||
|
||||
// KDF_CK(ck, constant)
|
||||
CONSTANT = SHA256("KDF_CK_constant")
|
||||
keydata[0] = HKDF(ck, CONSTANT, "DeriveFirstChain", 64)
|
||||
chainKey[0] = keydata[0:31]
|
||||
k[0] = keydata[32:63]
|
||||
|
||||
// repeat as necessary to get to k[n]
|
||||
keydata[n] = HKDF(chainKey[n-1], CONSTANT, "DeriveFirstChain", 64)
|
||||
chainKey[n] = keydata[0:31]
|
||||
k[n] = keydata[32:63]
|
||||
|
||||
// ChaChaPoly parameters to encrypt/decrypt part 2
|
||||
n = N from message number block (type 6) in part 1
|
||||
k = k[n]
|
||||
|
||||
ad = ZEROLEN
|
||||
|
||||
Key: KDF TBD
|
||||
IV: As published in a LS2 property?
|
||||
Nonce: From header
|
||||
{% endhighlight %}
|
||||
|
||||
|
||||
@@ -886,11 +1028,6 @@ Issues
|
||||
|
||||
- Obfuscation of cleartext key? We could do Elligator 2 but that's expensive.
|
||||
|
||||
- Do we need a nonce? Does it need to be 8 bytes? 4?
|
||||
|
||||
- IV is in the LS2 property? Alternative: Send a 16 byte IV instead of 8 byte nonce,
|
||||
and use a nonce of 0.
|
||||
|
||||
|
||||
|
||||
1b) Existing session format
|
||||
@@ -1067,16 +1204,16 @@ Inputs to the encryption/decryption functions:
|
||||
{% highlight lang='dataspec' %}
|
||||
k :: 32 byte cipher key, as generated from KDF
|
||||
|
||||
nonce :: Counter-based nonce, 12 bytes.
|
||||
Starts at 0 and incremented for each message.
|
||||
First four bytes are always zero.
|
||||
In new session message:
|
||||
Last eight bytes are the nonce from the message header.
|
||||
In existing session message:
|
||||
Last eight bytes are the message number (N), little-endian encoded.
|
||||
Maximum value is 2**64 - 2.
|
||||
Session must be ratcheted before N reaches that value.
|
||||
The value 2**64 - 1 must never be used.
|
||||
n :: Counter-based nonce, 12 bytes.
|
||||
Starts at 0 and incremented for each message.
|
||||
First four bytes are always zero.
|
||||
In new session message:
|
||||
Last eight bytes are the nonce from the message header.
|
||||
In existing session message:
|
||||
Last eight bytes are the message number (N), little-endian encoded.
|
||||
Maximum value is 2**64 - 2.
|
||||
Session must be ratcheted before N reaches that value.
|
||||
The value 2**64 - 1 must never be used.
|
||||
|
||||
ad :: In new session message:
|
||||
Associated data, 32 bytes.
|
||||
@@ -1138,7 +1275,8 @@ Notes
|
||||
AEAD Error Handling
|
||||
```````````````````
|
||||
|
||||
TBD
|
||||
All received data that fails the AEAD verification must be discarded.
|
||||
No response is returned.
|
||||
|
||||
|
||||
Justification
|
||||
@@ -1154,7 +1292,8 @@ Notes
|
||||
Issues
|
||||
``````
|
||||
|
||||
We may need a different AEAD with a larger nonce that's resistant to nonce reuse,
|
||||
Avoid using random nonces. If we do need random nonces,
|
||||
we may need a different AEAD with a larger nonce that's resistant to nonce reuse,
|
||||
so we can use random nonces. (SIV?)
|
||||
|
||||
|
||||
@@ -1404,8 +1543,9 @@ so the max unencrypted data is 65519 bytes.
|
||||
~ . . . ~
|
||||
|
||||
blk :: 1 byte
|
||||
0-2 reserved (used in NTCP2)
|
||||
3 for I2NP message (Garlic Message only)
|
||||
0 datetime
|
||||
1-2 reserved
|
||||
3 I2NP message (Garlic Message only)
|
||||
4 termination
|
||||
5 options
|
||||
6 message number and previous message number (ratchet)
|
||||
@@ -1431,21 +1571,16 @@ so the max unencrypted data is 65519 bytes.
|
||||
|
||||
Block Ordering Rules
|
||||
````````````````````
|
||||
In first decrypted part of the new session message,
|
||||
the following three blocks are required, in the following order:
|
||||
In the new session message,
|
||||
the following blocks are required, in the following order:
|
||||
|
||||
- Options (type 5) (must be total length = 9)
|
||||
- Message Number (type 6)
|
||||
- New Key (type 7)
|
||||
|
||||
No other blocks are allowed.
|
||||
Other allowed blocks:
|
||||
|
||||
In second decrypted part of the new session message,
|
||||
three blocks are required, and padding is optional, in the following order:
|
||||
|
||||
- Message Number (type 6)
|
||||
- New Key (type 7)
|
||||
- I2NP message (type 3) (one or more)
|
||||
- I2NP message (type 3)
|
||||
- Padding (type 254)
|
||||
|
||||
No other blocks are allowed.
|
||||
@@ -1463,6 +1598,26 @@ a single frame, but it is not prohibited.
|
||||
|
||||
|
||||
|
||||
DateTime
|
||||
````````
|
||||
Timestamp for replay prevention:
|
||||
|
||||
.. raw:: html
|
||||
|
||||
{% highlight lang='dataspec' %}
|
||||
+----+----+----+----+----+----+----+
|
||||
| 0 | 4 | timestamp |
|
||||
+----+----+----+----+----+----+----+
|
||||
|
||||
blk :: 0
|
||||
size :: 2 bytes, big endian, value = 4
|
||||
timestamp :: Unix timestamp, unsigned seconds.
|
||||
Wraps around in 2106
|
||||
|
||||
{% endhighlight %}
|
||||
|
||||
|
||||
|
||||
I2NP Message
|
||||
````````````
|
||||
|
||||
@@ -1553,9 +1708,13 @@ Additional reasons listed are for consistency, logging, debugging, or if policy
|
||||
Options
|
||||
```````
|
||||
Pass updated options.
|
||||
Options include: TBD.
|
||||
Options include various parameters for the session.
|
||||
|
||||
Options block will be variable length.
|
||||
In a new session message, the options block is fixed length,
|
||||
nine bytes, as more_options is not present.
|
||||
|
||||
In an existing session message, the options block may be variable length,
|
||||
nine or more bytes, as more_options may be present.
|
||||
|
||||
|
||||
.. raw:: html
|
||||
@@ -1572,11 +1731,11 @@ Options block will be variable length.
|
||||
+----+----+----+----+----+----+----+----+
|
||||
|
||||
blk :: 5
|
||||
size :: 2 bytes, big endian, size of options to follow, TBD bytes minimum
|
||||
size :: 2 bytes, big endian, size of options to follow, 6 bytes minimum
|
||||
STL :: Session tag length (default 8), min and max TBD
|
||||
OTW :: Outbound Session tag window (max lookahead)
|
||||
STimeout :: Session idle timeout
|
||||
MITW :: Max Inbound Session tag window (max lookahead)
|
||||
MITW :: Max Inbound Session Tag window (max lookahead)
|
||||
flg :: 1 byte flags
|
||||
bit order: 76543210
|
||||
bit 0: 1 to request a ratchet (new key), 0 if not
|
||||
@@ -1598,9 +1757,10 @@ Options Notes
|
||||
|
||||
Options Issues
|
||||
``````````````
|
||||
- Options format is TBD.
|
||||
- more_options format is TBD.
|
||||
- Options negotiation is TBD.
|
||||
- Padding parameters also?
|
||||
- Is 255 big enough for max MITW?
|
||||
|
||||
|
||||
Message Numbers
|
||||
@@ -1638,7 +1798,8 @@ Notes
|
||||
|
||||
- N is not strictly needed in an existing session message, as it's associated with the Session Tag
|
||||
|
||||
- This is similar to what Signal does, but in Signal, PN and N are in the header.
|
||||
- PN and N are as defined in Signal.
|
||||
This is similar to what Signal does, but in Signal, PN and N are in the header.
|
||||
Here, they're in the encrypted message body.
|
||||
|
||||
- Key ID can be just an incrementing counter.
|
||||
@@ -1677,7 +1838,6 @@ at the beginning.
|
||||
key ID :: 2 bytes, big endian, used for ack
|
||||
Public Key :: The next public key, 32 bytes, little endian
|
||||
|
||||
TBD :: Format TBD
|
||||
|
||||
{% endhighlight %}
|
||||
|
||||
@@ -1814,6 +1974,8 @@ Issues
|
||||
|
||||
- Is the next public key the right thing to sign?
|
||||
|
||||
- Use alice's static pubkey instead?
|
||||
|
||||
|
||||
|
||||
Padding
|
||||
@@ -1958,6 +2120,11 @@ TODO
|
||||
References
|
||||
==========
|
||||
|
||||
.. [Elligator2]
|
||||
https://elligator.cr.yp.to/elligator-20130828.pdf
|
||||
https://www.imperialviolet.org/2013/12/25/elligator.html
|
||||
See also OBFS4 code
|
||||
|
||||
.. [Prop111]
|
||||
{{ proposal_url('111') }}
|
||||
|
||||
|
Reference in New Issue
Block a user