From 8289febc2acd6dd6c1278434d538ed38dedb32f6 Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Sun, 4 Aug 2019 12:51:52 +0000
Subject: [PATCH] Updates for proposals 144, 147, 152 New proposal 153 split
 out from 152

---
 .../144-ecies-x25519-aead-ratchet.rst         |  10 +-
 .../147-transport-network-id-check.rst        |   8 +-
 i2p2www/spec/proposals/152-ecies-tunnels.rst  | 279 +--------------
 .../153-chacha20-layer-encryption.rst         | 335 ++++++++++++++++++
 4 files changed, 353 insertions(+), 279 deletions(-)
 create mode 100644 i2p2www/spec/proposals/153-chacha20-layer-encryption.rst

diff --git a/i2p2www/spec/proposals/144-ecies-x25519-aead-ratchet.rst b/i2p2www/spec/proposals/144-ecies-x25519-aead-ratchet.rst
index a1777817b..f4b016acb 100644
--- a/i2p2www/spec/proposals/144-ecies-x25519-aead-ratchet.rst
+++ b/i2p2www/spec/proposals/144-ecies-x25519-aead-ratchet.rst
@@ -5,7 +5,7 @@ ECIES-X25519-AEAD-Ratchet
     :author: zzz, chisana
     :created: 2018-11-22
     :thread: http://zzz.i2p/topics/2639
-    :lastupdated: 2019-07-26
+    :lastupdated: 2019-08-04
     :status: Open
 
 .. contents::
@@ -109,6 +109,8 @@ Goals
   be a separate proposal
 - Don't break anything that relies on 32-byte binary destination hashes, e.g. bittorrent
 - Maintain 0-RTT message delivery using ephemeral-static DH
+- Do not require buffering / queueing of messages at this protocol layer;
+  continue to support unlimited message delivery in both directions without waiting for a response
 - Upgrade to ephemeral-ephemeral DH after 1 RTT
 - Maintain handling of out-of-order messages
 - Maintain 256-bit security
@@ -153,7 +155,9 @@ Non-Goals / Out-of-scope
 - LS2 format (see proposal 123)
 - New DHT rotation algorithm or shared random generation
 - New encryption for tunnel building.
-  That would be in a separate proposal.
+  See proposal 152.
+- New encryption for tunnel layer encryption.
+  See proposal 153.
 - Methods of encryption, transmission, and reception of I2NP DLM / DSM / DSRM messages.
   Not changing.
 - No LS1-to-LS2 or ElGamal/AES-to-this-proposal communication is supported.
@@ -168,7 +172,7 @@ Non-Goals / Out-of-scope
 Justification
 -------------
 
-ElGamal/AES+SessionTag has been our sole end-to-end protocol for around for about 15 years,
+ElGamal/AES+SessionTag has been our sole end-to-end protocol for about 15 years,
 essentially without modifications to the protocol.
 There are now cryptographic primitives that are faster.
 We need to enhance the security of the protocol.
diff --git a/i2p2www/spec/proposals/147-transport-network-id-check.rst b/i2p2www/spec/proposals/147-transport-network-id-check.rst
index 67a5cbd13..890144ce1 100644
--- a/i2p2www/spec/proposals/147-transport-network-id-check.rst
+++ b/i2p2www/spec/proposals/147-transport-network-id-check.rst
@@ -5,7 +5,7 @@ Transport Network ID Check
     :author: zzz
     :created: 2019-02-28
     :thread: http://zzz.i2p/topics/2687
-    :lastupdated: 2019-07-16
+    :lastupdated: 2019-08-04
     :status: Open
 
 .. contents::
@@ -125,7 +125,7 @@ HMAC-MD5(encryptedPayload + IV + (payloadLength ^ protocolVersion), macKey)
 
   '+' means append and '^' means exclusive-or.
   payloadLength is a 2 byte unsigned integer
-  protocolVersion is two bytes 0x0000
+  protocolVersion is one byte 0x00
 
 {% endhighlight %}
 
@@ -134,11 +134,11 @@ New:
 .. raw:: html
 
   {% highlight lang='dataspec' %}
-HMAC-MD5(encryptedPayload + IV + (payloadLength ^ protocolVersion ^ ((netid - 2) << 1)), macKey)
+HMAC-MD5(encryptedPayload + IV + (payloadLength ^ protocolVersion ^ ((netid - 2) << 8)), macKey)
 
   '+' means append, '^' means exclusive-or, '<<' means left shift.
   payloadLength is a 2 byte unsigned integer
-  protocolVersion is two bytes 0x0000
+  protocolVersion is one byte 0x00
   netid is a 1 byte unsigned integer
 
 
diff --git a/i2p2www/spec/proposals/152-ecies-tunnels.rst b/i2p2www/spec/proposals/152-ecies-tunnels.rst
index f2ded763c..e8126a3bd 100644
--- a/i2p2www/spec/proposals/152-ecies-tunnels.rst
+++ b/i2p2www/spec/proposals/152-ecies-tunnels.rst
@@ -6,7 +6,7 @@ ECIES Tunnels
     :author: chisana
     :created: 2019-07-04
     :thread: http://zzz.i2p/topics/2737
-    :lastupdated: 2019-07-26
+    :lastupdated: 2019-08-04
     :status: Open
 
 .. contents::
@@ -27,12 +27,7 @@ No changes will be made to the format, processing, or encryption of ElGamal hops
 ElGamal tunnel creators will need to create ephemeral X25519 keypairs per-hop, and
 follow this spec for creating tunnels containing ECIES hops.
 
-The proposal is split into two sections:
-
-- ECIES for Tunnel Building
-- ECIES for Tunnel Layer Encryption
-
-If necessary, the proposal can be split into independent proposals for separate analysis and adoption.
+This proposal specifies changes needed for ECIES-X25519 Tunnel Building.
 
 Cryptographic Primitives
 ------------------------
@@ -117,24 +112,6 @@ are supported, TBD.
 
 Ranged random padding will be formatted using the Padding block structure from [ECIES-X25519]_ and [NTCP2]_.
 
-Flag Changes for Mixed Tunnels
-``````````````````````````````
-
-.. raw:: html
-
-  {% highlight lang='dataspec' %}
-
-Bit order: 76543210 (bit 7 is MSB)
-  bit 7: if set, allow messages from anyone
-  bit 6: if set, allow messages to anyone, and send the reply to the
-         specified next hop in a Tunnel Build Reply Message
-  bit 5: if set, use new (ChaCha20) layer encryption
-  bits 4-0: Undefined, must set to 0 for compatibility with future options
-
-{% endhighlight %}
-
-New layer encryption flag may be moved into Tunnel Build Options, TBD.
-
 Tunnel Reply Records for ECIES
 ------------------------------
 
@@ -349,11 +326,9 @@ This means that tunnel hops will only see encrypted records from their same encr
 For ElGamal and ECIES tunnel creators, they will generate unique ephemeral X25519 keypairs
 per-hop for encrypting to ECIES hops.
 
-**WARNING**: if the same ephemeral keypair is used for more than one hop, it can only be
-used for at most **two** hops, and the hops must be **consecutive**.
+Ephemeral keys must be unique per ECIES hop, and per build record.
 
-**WARNING**: Using the same ephemeral keys for non-consecutive hops, or more than two hops,
-allows colluding hops to know they're in the same tunnel, **VERY BAD**!!!
+**IMPORTANT**: Failing to use unique keys opens an attack vector for colluding hops to confirm they are in the same tunnel.
 
 .. raw:: html
 
@@ -372,7 +347,7 @@ allows colluding hops to know they're in the same tunnel, **VERY BAD**!!!
 Reply Record Encryption for ECIES Hops
 --------------------------------------
 
-The nonce must be unique per ChaCha20/ChaCha20-Poly1305 invocation using the same key.
+The nonces must be unique per ChaCha20/ChaCha20-Poly1305 invocation using the same key.
 
 See [RFC-7539-S4]_ Security Considerations for more information.
 
@@ -426,246 +401,6 @@ ECIES, used with new ephemeral keys per-BuildRequestRecord or VariableTunnelBuil
 
 ChaCha20Poly1305 provides AEAD encryption, allowing the recipient to verify message integrity before attempting decryption.
 
-ECIES Tunnel Layer Encryption
-=============================
-
-Goals
------
-
-The goal of this section is to replace AES256/ECB+CBC with Blowfish+ChaCha20 for established tunnel IV and layer encryption.
-
-Established Tunnel Message Processing
--------------------------------------
-
-This section describes changes to:
-
-- Outbound and Inbound Gateway preprocessing + encryption
-- Participant encryption + postprocessing
-- Outbound and Inbound Endpoint encryption + postprocessing
-
-Changes are for mixed tunnels, and ElGamal hops are considered unchanged.
-
-For an overview of current tunnel message processing, see the [Tunnel-Implementation]_ spec.
-
-Only changes for ECIES gateways + hops are discussed.
-
-No changes are considered for mixed tunnel with ElGamal routers, until a safe protocol can be devised
-for converting a 128-bit AES IV to a 64-bit ChaCha20 nonce. Bloom filters guarantee uniqueness
-for the full IV, but the first half of unique IVs could be identical.
-
-This means ECIES routers will use current AES tunnel layer encryption whenever ElGamal hops
-are present in the tunnel.
-
-See section on build request records for ECIES hop detection of ElGamal tunnel creators.
-
-Gateway and Tunnel Creator Message Processing
----------------------------------------------
-
-Gateways will fragment and bundle messages in the same way.
-
-AEAD frames (including the MAC) can be split across fragments, but any dropped
-fragments will result in failed AEAD decryption (failed MAC verification).
-
-Gateway Preprocessing & Encryption
-----------------------------------
-
-When tunnels are ECIES-only, gateways will generate 64-bit nonces for use by ECIES hops.
-
-Inbound tunnels:
-
-- Encrypt the IV and tunnel message(s) using ChaCha20
-- Use 8-byte ``tunnelNonce`` given the lifetime of tunnels
-- Use 8-byte monotonically increasing counter for ``tunnelNonce`` encryption
-- Destroy tunnel before 2^(64 - 1) messages: 2^64 - 1 = 18,446,744,073,709,551,615
-
-  - Nonce limit in place to avoid rollover of the 64-bit counter
-  - Nonce limit exceedingly unlikely to ever be reached, given this would be over ~3,074,457,345,618,258 msgs/second for 10 minute tunnels
-
-The tunnel's Inbound Gateway (IBGW), processes messages received from another tunnel's Outbound Endpoint (OBEP).
-
-At this point, the outermost message layer is encrypted using point-to-point transport encryption.
-The I2NP message headers are visible, at the tunnel layer, to the OBEP and IBGW.
-The inner I2NP messsages are wrapped in Garlic cloves, encrypted using end-to-end session encryption.
-
-The IBGW preprocesses the messages into the appropriately formatted tunnel messages, and encrypts as following:
-
-.. raw:: html
-
-  {% highlight lang='dataspec' %}
-
-// For ECIES-only tunnels
-  // IBGW generates a random nonce, ensuring no collision in its Bloom filter
-  tunnelNonce = Random(len = 64-bits)
-  counter = counter + 1
-  // IBGW ChaCha20 "encrypts" the preprocessed tunnel messages with its tunnelNonce and layerKey
-  encMsg = ChaCha20(msg = tunnel msg(s), nonce = tunnelNonce, key = layerKey)
-
-  // For mixed tunnels w/ ElGamal hops (unchanged)
-  encIV = AES256/ECB-Encrypt(msg = prev. encIV, key = hop's IVKey)
-  encMsg = AES256/CBC-Encrypt(msg = tunnel msg(s), IV = encIV, key = hop's layerKey)
-  encIV2 = AES256/ECB-Encrypt(msg = encIV, key = hop's IVKey)
-
-{% endhighlight %}
-
-Tunnel message format will slightly change, using an 8-byte nonce instead of a 16-byte IV.
-The counter used for encrypting the nonce is appended to the 8-byte ``tunnelNonce``.
-The counter is not advanced by tunnel participants.
-The rest of the format is unchanged.
-
-Outbound tunnels:
-
-For outbound tunnels, the tunnel creator is the Outbound Gateway (OBGW).
-
-On outbound tunnel creation, Variable Tunnel Build Messages are created,
-preprocessed (iteratively decrypted), and sent out to the first potential hop in the tunnel.
-
-Replies are directed to a zero-hop or existing inbound tunnel's IBGW.
-
-- Iteratively decrypt tunnel messages
-
-  - ECIES-only tunnel hops will encrypt using ChaCha20
-  - mixed-tunnel hops will encrypt using AES256/ECB+CBC
-
-- Use the same rules for IV and layer nonces as Inbound tunnels
-- For ECIES-only tunnels, advance the nonce once per set of tunnel messages sent
-
-.. raw:: html
-
-  {% highlight lang='dataspec' %}
-
-
-// For ECIES-only tunnel hops
-  // For each set of messages, increase the counter
-  counter = counter + 1
-  // For each hop, ChaCha20 the previous tunnelNonce with the current hop's IV key
-  // The counter is advanced for each set of tunnel messages
-  tunnelNonce = ChaCha20(msg = prev. tunnelNonce, nonce = counter, key = IVKey)
-  // For each hop, ChaCha20 "decrypt" the tunnel message with the current hop's tunnelNonce and layerKey
-  decMsg = ChaCha20(msg = tunnel msg(s), nonce = tunnelNonce, key = hop's layerKey)
-
-  // For ElGamal hops (unchanged)
-  // Tunnel creator generates a random IV
-  // For each hop, decrypt the IV and tunnel message(s)
-  // For the first hop, the previous decrypted IV will be the randomly generated IV
-  decIV = AES256/ECB-Decrypt(msg = prev. decIV, key = hop's IVKey)
-  decMsg = AES256/CBC-Decrypt(msg = tunnel msg(s), IV = decIV, key = hop's layerKey)
-  decIV2 = AES256/ECB-Decrypt(msg = decIV, key = hop's IVKey)
-
-{% endhighlight %}
-
-Participant Processing
-----------------------
-
-Participants will track seen messages in the same way, using decaying Bloom filters.
-
-IV double-encryption is no longer necessary for ECIES hops,
-since there are no padding-oracle attacks against ChaCha20.
-
-ChaCha20 hops will encrypt the received nonce to prevent confirmation attacks between prior and later hops,
-i.e. colluding, non-consecutive hops being able to tell they belong to the same tunnel.
-
-IV double-encryption will still be used for mixed-tunnel hops, since they are considered unchanged.
-
-To validate received ``tunnelNonce``, the participant checks against its Bloom filter for duplicates.
-
-To validate the received counter, the participant checks against it counter Bloom filter for duplicates.
-
-The two Bloom filters must be independent from one another.
-
-Participants do not advance the counter.
-
-After validation, the participant:
-
-- ChaCha20 encrypts the ``tunnelNonce`` with its ``IVKey`` and received counter
-- Uses the encrypted ``tunnelNonce`` & its ``layerKey`` to ChaCha20 encrypt the tunnel message(s)
-- Sends the tuple {``tunnelId``, encrypted ``tunnelNonce``, ciphertext} to the next hop.
-
-.. raw:: html
-
-  {% highlight lang='dataspec' %}
-
-// For ECIES-only tunnel hops
-  // For verification, tunnel participant should check Bloom filter for received nonce uniqueness
-  // The counter must also be checked for uniqueness against its own independent Bloom filter
-  // After verification, ChaCha20 encrypt the tunnelNonce with the hop's IVKey
-  tunnelNonce = ChaCha20(msg = received tunnelNonce, nonce = received counter, key = IVKey)
-  encMsg = ChaCha20(msg = received message, nonce = tunnelNonce, key = layerKey)
-
-  // For ElGamal hops (unchanged)
-  currentIV = AES256/ECB-Encrypt(msg = received IV, key = hop's IVKey)
-  encMsg = AES256/CBC-Encrypt(msg = tunnel msg(s), IV = currentIV, key = hop's layerKey)
-  nextIV = AES256/ECB-Encrypt(msg = currentIV, key = hop's IVKey)
-
-{% endhighlight %}
-
-Inbound Endpoint Processing
----------------------------
-
-Inbound Endpoints will check the composition of their tunnel hops (ECIES or ElGamal).
-
-Mixed tunnels are considered unchanged for tunnel layer encryption.
-
-For ECIES-only tunnels, the following scheme will be used:
-
-- Validate the received ``tunnelNonce`` and counter against the respective Bloom filters
-- ChaCha20 decrypt the encrypted data using the received ``tunnelNonce`` & the hop's ``layerKey``
-- ChaCha20 decrypt the ``tunnelNonce`` using the hop's ``IVKey`` and received counter to get the preceding ``tunnelNonce``
-- ChaCha20 decrypt the encrypted data using the decrypted ``tunnelNonce`` & the preceding hop's ``layerKey``
-- Repeat for each hop in the tunnel, back to the IBGW
-
-.. raw:: html
-
-  {% highlight lang='dataspec' %}
-
-// For ECIES-only tunnel hops
-  // Repeat for each hop in the tunnel back to the IBGW
-  // Replace the received tunnelNonce w/ the prior round hop's decrypted tunnelNonce for subsequent hops
-  tunnelNonce = ChaCha20(msg = received tunnelNonce, nonce = received counter, key = IVKey)
-  decMsg(s) = ChaCha20(msg = encrypted layer message(s), nonce = tunnelNonce, key = layerKey)
-
-  // For mixed tunnel hops (unchanged)
-  // Repeat for each hop in the tunnel back to the IBGW
-  // Replace the received IV w/ the prior round hop's double-decrypted IV for subsequent hops
-  decIV = AES256/ECB(msg = received IV, key = IVKey)
-  decMsg = AES256/CBC(msg = tunnel msg(s), IV = decIV, key = layerKey)
-  decIV2 = AES256/ECB(msg = decIV, key = IVKey)
-
-{% endhighlight %}
-
-Security Analysis for ChaCha20 Tunnel Layer Encryption
----------------------------------------------------------------
-
-Switching from AES256/ECB to ChaCha20 has a number of advantages, and new security considerations.
-
-The biggest security considerations to account for, are that ChaCha20 nonces must be unique per-message,
-for the life of the key being used.
-
-Failing to use unique nonces with the same key on different messages breaks ChaCha20.
-
-Simple counters will be used alongside the ``tunnelNonce`` for encrypting the nonce,
-since they are required for proper decryption by the IBEP.
-
-Using an appended counter allows the IBEP to decrypt the ``tunnelNonce`` for each hop's layer encryption,
-recovering the previous nonce.
-
-The 64-bit counter alongside the ``tunnelNonce`` doesn't reveal any new information to tunnel hops,
-and cannot be used for correlation attacks. The counter also doesn't need to be private, as it only
-needs to be unique per-message in a given tunnel. Uniqueness can be ensured by a second Bloom filter,
-tracking which counter values have been used.
-
-The biggest security advantage is that there are no confirmation or oracle attacks against ChaCha20.
-
-There are chosen/known-plaintext attacks against AES256/ECB, when the key is reused (as in tunnel layer encryption).
-
-It is unlikely the chosen-plaintext attack can be used to recover double-encrypted IVs, since it requires at least two blocks
-to be encrypted, and a single pass of the cipher.
-
-An attack confirming a chosen plaintext IV is much more likely, but still unclear if it would be successful given
-double-encryption.
-
-The chosen-plaintext producing a recovered IV cannot be used to perform
-a padding-oracle attack against AES256/CBC layer encryption, since duplicate IVs are rejected.
-
 Tunnel Message Overhead for ECIES
 =================================
 
@@ -713,8 +448,8 @@ Wrapped I2NP message overhead:
 
 Tunnel message overhead:
 
-Tunnel layer keys, IV keys, and reply keys no longer need to be transmitted in ECIES BuildRequest Records.
-Unused space claimed by random padding and the trailing 16 byte Poly1305 MAC.
+Tunnel layer keys, IV/nonce keys, and reply keys no longer need to be transmitted in ECIES BuildRequest Records.
+Unused space claimed by build options, random padding, and the trailing 16 byte Poly1305 MAC.
 
 ECIES session messages will be wrapped in I2NP Data messages, surrounded by a Garlic Clove,
 and fragmented in Tunnel Data messages like any other message.
diff --git a/i2p2www/spec/proposals/153-chacha20-layer-encryption.rst b/i2p2www/spec/proposals/153-chacha20-layer-encryption.rst
new file mode 100644
index 000000000..e8283be41
--- /dev/null
+++ b/i2p2www/spec/proposals/153-chacha20-layer-encryption.rst
@@ -0,0 +1,335 @@
+ChaCha Tunnel Layer Encryption
+==============================
+
+.. meta::
+    :author: chisana
+    :created: 2019-08-04
+    :thread: http://zzz.i2p/topics/2753
+    :lastupdated: 2019-08-04
+    :status: Draft
+
+.. contents::
+
+Overview
+========
+
+This proposal builds on and requires the changes from proposal 152: ECIES Tunnels.
+
+Only tunnels built through hops supporting the BuildRequestRecord format for ECIES-X25519
+tunnels can implement this specification.
+
+This specification requires the Tunnel Build Options format for indicating
+tunnel layer encryption type, and transmitting layer AEAD keys.
+
+Goals
+-----
+
+The goals of this proposal are to:
+
+- Replace AES256/ECB+CBC with ChaCha20 for established tunnel IV and layer encryption
+- Use ChaCha20-Poly1305 for inter-hop AEAD protection
+- Be undetectable from existing tunnel layer encryption by non-tunnel participants
+- Make no changes to overall tunnel message length
+
+Established Tunnel Message Processing
+-------------------------------------
+
+This section describes changes to:
+
+- Outbound and Inbound Gateway preprocessing + encryption
+- Participant encryption + postprocessing
+- Outbound and Inbound Endpoint encryption + postprocessing
+
+For an overview of current tunnel message processing, see the [Tunnel-Implementation]_ spec.
+
+Only changes for routers supporting ChaCha20 layer encryption are discussed.
+
+No changes are considered for mixed tunnel with AES layer encryption, until a safe protocol can be devised
+for converting a 128-bit AES IV to a 64-bit ChaCha20 nonce. Bloom filters guarantee uniqueness
+for the full IV, but the first half of unique IVs could be identical.
+
+This means layer encryption must be uniform for all hops in the tunnel, and established using
+tunnel build options during the tunnel creation process.
+
+All gateways and tunnel participants will need to maintain a Bloom filter for validating the two independent nonces.
+
+The ``nonceKey`` mentioned throughout this proposal takes the place of the ``IVKey`` used in AES layer encryption.
+It is generated using the same KDF from proposal 152.
+
+AEAD Encryption of Hop-to-Hop Messages
+--------------------------------------
+
+An additional unique ``AEADKey`` will need to be generated for each pair of consecutive hops.
+This key will be used by consecutive hops to ChaCha20-Poly1305 encrypt and decrypt the
+inner ChaCha20 encrypted tunnel message.
+
+Tunnel messages will need to reduce the length of the inner encrypted frame by 16 bytes to
+accommodate the Poly1305 MAC.
+
+AEAD cannot be used on the messages directly, since iterative decryption is needed by outbound tunnels.
+Iterative decryption can only be achieved, in the way it's used now, using ChaCha20 without AEAD.
+
+.. raw:: html
+
+  {% highlight lang='dataspec' -%}
++----+----+----+----+----+----+----+----+
+  |    Tunnel ID      |   tunnelNonce     |
+  +----+----+----+----+----+----+----+----+
+  | tunnelNonce cont. |    obfsNonce      |
+  +----+----+----+----+----+----+----+----+
+  |  obfsNonce cont.  |                   |
+  +----+----+----+----+                   +
+  |                                       |
+  +           Encrypted Data              +
+  ~                                       ~
+  |                                       |
+  +                   +----+----+----+----+
+  |                   |    Poly1305 MAC   |
+  +----+----+----+----+                   +  
+  |                                       |
+  +                   +----+----+----+----+
+  |                   |
+  +----+----+----+----+
+
+  Tunnel ID :: `TunnelId`
+         4 bytes
+         the ID of the next hop
+
+  tunnelNonce ::
+         8 bytes
+         the tunnel layer nonce
+
+  obfsNonce ::
+         8 bytes
+         the tunnel layer nonce encryption nonce
+
+  Encrypted Data ::
+         992 bytes
+         the encrypted tunnel message
+
+  Poly1305 MAC ::
+         16 bytes
+
+  total size: 1028 Bytes
+{% endhighlight %}
+
+Inner hops (with preceding and following hops), will have two ``AEADKeys``, one for decrypting
+the AEAD layer of the previous hop, and encrypting the AEAD layer to the following hop.
+
+All inner hop participants will thus have 64 additional bytes of key material included in their BuildRequestRecords.
+
+The Outbound Endpoint and Inbound Gateway will only require an additional 32 bytes of keydata,
+since they do not tunnel layer encrypt messages between each other.
+
+The Outbound Gateway generates its ``outAEAD`` key, which is the same as the first
+outbound hop's ``inAEAD`` key.
+
+The Inbound Endpoint generates its ``inAEAD`` key, which is the same as the final
+inbound hop's ``outAEAD`` key.
+
+Inner hops will receive and ``inAEADKey`` and ``outAEADKey`` which will be used to AEAD decrypt
+incoming messages and encrypt outgoing messages, respectively.
+
+As an example, in a tunnel with inner hops OBGW, A, B, OBEP:
+
+- A's ``inAEADKey`` is the same as the OBGW's ``outAEADKey``
+- B's ``inAEADKey`` is the same as A's ``outAEADKey``
+- B's ``outAEADKey`` is the same as OBEP's ``inAEADKey``
+
+Keys are unique to hop pairs, so OBEP's ``inAEADKey`` will be different than A's ``inAEADKey``,
+A's ``outAEADKey`` different than B's ``outAEADKey``, etc.
+
+Gateway and Tunnel Creator Message Processing
+---------------------------------------------
+
+Gateways will fragment and bundle messages in the same way, reserving space after the instructions-fragment
+frame for the Poly1305 MAC.
+
+Inner I2NP messages containing AEAD frames (including the MAC) can be split across fragments,
+but any dropped fragments will result in failed AEAD decryption (failed MAC verification) at the
+endpoint.
+
+Gateway Preprocessing & Encryption
+----------------------------------
+
+When tunnels support ChaCha20 layer encryption, gateways will generate two 64-bit nonces per message set.
+
+Inbound tunnels:
+
+- Encrypt the IV and tunnel message(s) using ChaCha20
+- Use 8-byte ``tunnelNonce`` and ``obfsNonce`` given the lifetime of tunnels
+- Use 8-byte ``obfsNonce`` for ``tunnelNonce`` encryption
+- Destroy tunnel before 2^(64 - 1) - 1 sets of messages: 2^63 - 1 = 9,223,372,036,854,775,807
+
+  - Nonce limit in place to avoid collision of the 64-bit nonces
+  - Nonce limit nearly impossible to ever be reached, given this would be over ~15,372,286,728,091,294 msgs/second for 10 minute tunnels
+
+- Tune the Bloom filter based on a reasonable number of expected elements (128 msgs/sec, 1024 msgs/sec? TBD)
+
+The tunnel's Inbound Gateway (IBGW), processes messages received from another tunnel's Outbound Endpoint (OBEP).
+
+At this point, the outermost message layer is encrypted using point-to-point transport encryption.
+The I2NP message headers are visible, at the tunnel layer, to the OBEP and IBGW.
+The inner I2NP messsages are wrapped in Garlic cloves, encrypted using end-to-end session encryption.
+
+The IBGW preprocesses the messages into the appropriately formatted tunnel messages, and encrypts as following:
+
+.. raw:: html
+
+  {% highlight lang='dataspec' %}
+
+// IBGW generates random nonces, ensuring no collision in its Bloom filter for each nonce
+  tunnelNonce = Random(len = 64-bits)
+  obfsNonce = Random(len = 64-bits)
+  // IBGW ChaCha20 "encrypts" each of the preprocessed tunnel messages with its tunnelNonce and layerKey
+  encMsg = ChaCha20(msg = tunnel msg, nonce = tunnelNonce, key = layerKey)
+
+  // ChaCha20-Poly1305 encrypt each message's encrypted data frame with the tunnelNonce and outAEADKey
+  (encMsg, MAC) = ChaCha20-Poly1305-Encrypt(msg = encMsg, nonce = tunnelNonce, key = outAEADKey)
+{% endhighlight %}
+
+Tunnel message format will slightly change, using two 8-byte nonces instead of a 16-byte IV.
+The ``obfsNonce`` used for encrypting the nonce is appended to the 8-byte ``tunnelNonce``,
+and is encrypted by each hop using the encrypted ``tunnelNonce`` and the hop's ``nonceKey``.
+
+After the message set has be pre-emptively decrypted for each hop, the Outbound Gateway
+ChaCha20-Poly1305 AEAD encrypts the ciphertext portion of each tunnel message using
+the ``tunnelNonce`` and its ``outAEADKey``.
+
+Outbound tunnels:
+
+- Iteratively decrypt tunnel messages
+- ChaCha20-Poly1305 encrypt preemptively decrypted tunnel message encrypted frames
+- Use the same rules for layer nonces as Inbound tunnels
+- Generate random nonces once per set of tunnel messages sent
+
+.. raw:: html
+
+  {% highlight lang='dataspec' %}
+
+
+// For each set of messages, generate unique, random nonces
+  tunnelNonce = Random(len = 64-bits)
+  obfsNonce = Random(len = 64-bits)
+
+  // For each hop, ChaCha20 the previous tunnelNonce with the current hop's IV key
+  tunnelNonce = ChaCha20(msg = prev. tunnelNonce, nonce = obfsNonce, key = hop's nonceKey)
+
+  // For each hop, ChaCha20 "decrypt" the tunnel message with the current hop's tunnelNonce and layerKey
+  decMsg = ChaCha20(msg = tunnel msg(s), nonce = tunnelNonce, key = hop's layerKey)
+
+  // For each hop, ChaCha20 "decrypt" the obfsNonce with the current hop's encrypted tunnelNonce and nonceKey
+  obfsNonce = ChaCha20(msg = obfsNonce, nonce = tunnelNonce, key = hop's nonceKey)
+
+  // After hop processing, ChaCha20-Poly1305 encrypt each tunnel message's "decrypted" data frame with the first hop's encrypted tunnelNonce and inAEADKey
+  (encMsg, MAC) = ChaCha20-Poly1305-Encrypt(msg = decMsg, nonce = first hop's encrypted tunnelNonce, key = first hop's inAEADKey / GW outAEADKey)
+{% endhighlight %}
+
+Participant Processing
+----------------------
+
+Participants will track seen messages in the same way, using decaying Bloom filters.
+
+Tunnel nonces will each need to be encrypted once per-hop, to prevent confirmation attacks
+by non-consecutive, colluding hops.
+
+Hops will encrypt the received nonce to prevent confirmation attacks between prior and later hops,
+i.e. colluding, non-consecutive hops being able to tell they belong to the same tunnel.
+
+To validate received ``tunnelNonce`` and ``obfsNonce``, participants check each nonce individually
+against their Bloom filter for duplicates.
+
+After validation, the participant:
+
+- ChaCha20-Poly1305 decrypts each tunnel message's AEAD ciphertext with the received ``tunnelNonce`` and its ``inAEADKey``
+- ChaCha20 encrypts the ``tunnelNonce`` with its ``nonceKey`` and received ``obfsNonce``
+- ChaCha20 encrypts the each tunnel message's encrypted data frame with the encrypted ``tunnelNonce`` and its ``layerKey``
+- ChaCha20-Poly1305 encrypts each tunnel message's encrypted data frame the encrypted ``tunnelNonce`` and its ``outAEADKey`` 
+- ChaCha20 encrypts the ``obfsNonce`` with its ``nonceKey`` and encrypted ``tunnelNonce``
+- Sends the tuple {``nextTunnelId``, encrypted (``tunnelNonce`` || ``obfsNonce``), AEAD ciphertext || MAC} to the next hop.
+
+.. raw:: html
+
+  {% highlight lang='dataspec' %}
+
+// For verification, tunnel hops should check Bloom filter for each received nonce's uniqueness
+  // After verification, unwrap the AEAD frame(s) byChaCha20-Poly1305 decrypt each tunnel message's encrypted frame
+  // with the received tunnelNonce and inAEADKey 
+  encTunMsg = ChaCha20-Poly1305-Decrypt(msg = received encMsg \|\| MAC, nonce = received tunnelNonce, key = inAEADKey)
+
+  // ChaCha20 encrypt the tunnelNonce with the obfsNonce and hop's nonceKey
+  tunnelNonce = ChaCha20(msg = received tunnelNonce, nonce = received obfsNonce, key = nonceKey)
+
+  // ChaCha20 encrypt each tunnel message's encrypted data frame with the encrypted tunnelNonce and hop's layerKey
+  encMsg = ChaCha20(msg = encTunMsg, nonce = tunnelNonce, key = layerKey)
+
+  // For AEAD protection, also ChaCha20-Poly1305 encrypt each message's encrypted data frame
+  // with the encrypted tunnelNonce and the hop's outAEADKey
+  (encMsg, MAC) = ChaCha20-Poly1305-Encrypt(msg = encMsg, nonce = tunnelNonce, key = outAEADKey)
+
+  // ChaCha20 encrypt the received obfsNonce with the encrypted tunnelNonce and hop's nonceKey
+  obfsNonce = ChaCha20(msg = obfsNonce, nonce = tunnelNonce, key = nonceKey)
+{% endhighlight %}
+
+Inbound Endpoint Processing
+---------------------------
+
+For ChaCha20 tunnels, the following scheme will be used to decrypt each tunnel message:
+
+- Validate the received ``tunnelNonce`` and ``obfsNonce`` independently against its Bloom filter
+- ChaCha20-Poly1305 decrypt the encrypted data frame using the received ``tunnelNonce`` and ``inAEADKey``
+- ChaCha20 decrypt the encrypted data frame using the received ``tunnelNonce`` & the hop's ``layerKey``
+- ChaCha20 decrypt the ``obfsNonce`` using the hop's ``nonceKey`` and received ``tunnelNonce`` to get the preceding ``obfsNonce``
+- ChaCha20 decrypt the received ``tunnelNonce`` using the hop's ``nonceKey`` and decrypted ``obfsNonce`` to get the preceding ``tunnelNonce``
+- ChaCha20 decrypt the encrypted data using the decrypted ``tunnelNonce`` & the preceding hop's ``layerKey``
+- Repeat the steps for nonce and layer decryption for each hop in the tunnel, back to the IBGW
+- The AEAD frame decryption is only needed in the first round
+
+.. raw:: html
+
+  {% highlight lang='dataspec' %}
+
+// For the first round, ChaCha20-Poly1305 decrypt each message's encrypted data frame + MAC
+  // using the received tunnelNonce and inAEADKey
+  msg = encTunMsg \|\| MAC
+  tunnelNonce = received tunnelNonce
+  encTunMsg = ChaCha20-Poly1305-Decrypt(msg, nonce = tunnelNonce, key = inAEADKey)
+
+  // Repeat for each hop in the tunnel back to the IBGW
+  // For every round, ChaCha20 decrypt each hop's layer encryption on each message's encrypted data frame
+  // Replace the received tunnelNonce w/ the prior round's decrypted tunnelNonce for each hop
+  decMsg = ChaCha20(msg = encTunMsg, nonce = tunnelNonce, key = layerKey)
+  obfsNonce = ChaCha20(msg = obfsNonce, nonce = tunnelNonce, key = nonceKey)
+  tunnelNonce = ChaCha20(msg = tunnelNonce, nonce = obfsNonce, key = nonceKey)
+{% endhighlight %}
+
+Security Analysis for ChaCha20+ChaCha20-Poly1305 Tunnel Layer Encryption
+------------------------------------------------------------------------
+
+Switching from AES256/ECB+AES256/CBC to ChaCha20+ChaCha20-Poly1305 has a number of advantages, and new security considerations.
+
+The biggest security considerations to account for, are that ChaCha20 and ChaCha20-Poly1305 nonces must be unique per-message,
+for the life of the key being used.
+
+Failing to use unique nonces with the same key on different messages breaks ChaCha20 and ChaCha20-Poly1305.
+
+Using an appended ``obfsNonce`` allows the IBEP to decrypt the ``tunnelNonce`` for each hop's layer encryption,
+recovering the previous nonce.
+
+The ``obfsNonce`` alongside the ``tunnelNonce`` doesn't reveal any new information to tunnel hops,
+since the ``obfsNonce`` is encrypted using the encrypted ``tunnelNonce``. This also allows the IBEP to recover
+the previous ``obfsNonce`` in a similar way to ``tunnelNonce`` recovery.
+
+The biggest security advantage is that there are no confirmation or oracle attacks against ChaCha20,
+and using ChaCha20-Poly1305 between hops adds AEAD protection against ciphertext manipulation from
+out-of-band MitM attackers.
+
+There are practical oracle attacks against AES256/ECB + AES256/CBC, when the key is reused (as in tunnel layer encryption).
+
+The oracle attacks against AES256/ECB won't work, because of the double-encryption used, and encryption is over a
+single block (the tunnel IV).
+
+The padding oracle attacks against AES256/CBC won't work, because no padding is used. If tunnel message length ever
+changed to non-mod-16 lengths, AES256/CBC would still not be vulnerable due to rejected duplicate IVs.
+
+Both attacks are also blocked by disallowing multiple oracle calls using the same IV, since duplicate IVs are rejected.
-- 
GitLab