diff --git a/i2p2www/pages/site/docs/index.html b/i2p2www/pages/site/docs/index.html index b9d1e041..f3df2514 100644 --- a/i2p2www/pages/site/docs/index.html +++ b/i2p2www/pages/site/docs/index.html @@ -1,7 +1,7 @@ {% extends "global/layout.html" %} {% block title %}{% trans %}Index to Technical Documentation{% endtrans %}{% endblock %} -{% block lastupdated %}2020-11{% endblock %} -{% block accuratefor %}0.9.48{% endblock %} +{% block lastupdated %}2021-01{% endblock %} +{% block accuratefor %}0.9.49{% endblock %} {% block content %}

{% trans -%} Following is an index to the technical documentation for I2P. @@ -117,7 +117,8 @@ Traditionally used only by Java applications and higher-level APIs.

{% trans %}End-to-End Encryption{% endtrans %}

{% trans %}How client messages are end-to-end encrypted by the router.{% endtrans %} diff --git a/i2p2www/spec/common-structures.rst b/i2p2www/spec/common-structures.rst index 6abc948c..d5f21555 100644 --- a/i2p2www/spec/common-structures.rst +++ b/i2p2www/spec/common-structures.rst @@ -3,8 +3,8 @@ Common structures Specification =============================== .. meta:: :category: Design - :lastupdated: 2020-09 - :accuratefor: 0.9.47 + :lastupdated: 2021-01 + :accuratefor: 0.9.49 .. contents:: @@ -79,6 +79,11 @@ The default type is ElGamal. As of release 0.9.38, other types may be supported, depending on context. Keys are big-endian unless otherwise noted. +X25519 keys are supported in Destinations and LeaseSet2 as of release 0.9.44. +X25519 keys are supported in RouterIdentities as of release 0.9.48. + + + ======= ============== ====== ===== Type Length (bytes) Since Usage ======= ============== ====== ===== @@ -86,7 +91,7 @@ ElGamal 256 All Router Identities and Destinations P256 64 TBD Reserved, see proposal 145 P384 96 TBD Reserved, see proposal 145 P521 132 TBD Reserved, see proposal 145 -X25519 32 0.9.38 Little-endian. See [ECIES]_ and proposal 156 +X25519 32 0.9.38 Little-endian. See [ECIES]_ and [ECIES-ROUTERS]_ ======= ============== ====== ===== JavaDoc: http://{{ i2pconv('echelon.i2p/javadoc') }}/net/i2p/data/PublicKey.html @@ -105,8 +110,8 @@ Other encryption schemes are in the process of being defined, see the table belo Contents ```````` -Key type and length are inferred from context or are specified in the Key -Certificate of a Destination or RouterInfo, or the fields in a LeaseSet2_ or other data structure. +Key type and length are inferred from context or are stored separately +in a data structure or a private key file. The default type is ElGamal. As of release 0.9.38, other types may be supported, depending on context. Keys are big-endian unless otherwise noted. @@ -118,7 +123,7 @@ ElGamal 256 All Router Identities and Destinations P256 32 TBD Reserved, see proposal 145 P384 48 TBD Reserved, see proposal 145 P521 66 TBD Reserved, see proposal 145 -X25519 32 0.9.38 Little-endian. See [ECIES]_ and proposal 156 +X25519 32 0.9.38 Little-endian. See [ECIES]_ and [ECIES-ROUTERS]_ ======= ============== ====== ===== JavaDoc: http://{{ i2pconv('echelon.i2p/javadoc') }}/net/i2p/data/PrivateKey.html @@ -280,6 +285,9 @@ JavaDoc: http://{{ i2pconv('echelon.i2p/javadoc') }}/net/i2p/data/Hash.html Session Tag ----------- +Note: Session Tags for ECIES-X25519 destinations (ratchet) and ECIES-X25519 routers +are 8 bytes. See [ECIES]_ and [ECIES-ROUTERS]_. + Description ``````````` A random number @@ -668,6 +676,10 @@ Notes * The Crypto Public Key is aligned at the start and the Signing Public Key is aligned at the end. The padding (if any) is in the middle. +* RouterIdentities with a key certificate and a ECIES_X25519 public key + are supported as of release 0.9.48. + Prior to that, all RouterIdentities were ElGamal. + JavaDoc: http://{{ i2pconv('echelon.i2p/javadoc') }}/net/i2p/data/router/RouterIdentity.html .. _struct-Destination: @@ -1714,6 +1726,9 @@ References .. [ECIES] {{ spec_url('ecies') }} +.. [ECIES-ROUTERS] + {{ spec_url('ecies-routers') }} + .. [ELGAMAL] {{ site_url('docs/how/cryptography', True) }}#elgamal diff --git a/i2p2www/spec/ecies-routers.rst b/i2p2www/spec/ecies-routers.rst new file mode 100644 index 00000000..9c8a91c6 --- /dev/null +++ b/i2p2www/spec/ecies-routers.rst @@ -0,0 +1,361 @@ +============================= +ECIES-X25519 Router Messages +============================= + +.. meta:: + :category: Protocols + :lastupdated: 2021-01 + :accuratefor: 0.9.49 + +.. contents:: + + +Note +==== +Supported as of release 0.9.49. +Network deployment and testing in progress. +Subject to minor revision. +See proposal 156 [Prop156]_. + + +Overview +======== + +This document specifies Garlic message encryption to ECIES routers, +using crypto primitives introduced by [ECIES-X25519]_. +It is a portion of the overall proposal +[Prop156]_ for converting routers from ElGamal to ECIES-X25519 keys. +This specification is implemented as of release 0.9.49. + +For an overview of all changes required for ECIES routers, see proposal 156 [Prop156]_. +For Garlic Messages to ECIES-X25519 destinations, see [ECIES-X25519]_. + + +Cryptographic Primitives +------------------------ + +The primitives required to implement this specification are: + +- AES-256-CBC as in [Cryptography]_ +- STREAM ChaCha20/Poly1305 functions: + ENCRYPT(k, n, plaintext, ad) and DECRYPT(k, n, ciphertext, ad) - as in [NTCP2]_ [ECIES-X25519]_ and [RFC-7539]_ +- X25519 DH functions - as in [NTCP2]_ and [ECIES-X25519]_ +- HKDF(salt, ikm, info, n) - as in [NTCP2]_ and [ECIES-X25519]_ + +Other Noise functions defined elsewhere: + +- MixHash(d) - as in [NTCP2]_ and [ECIES-X25519]_ +- MixKey(d) - as in [NTCP2]_ and [ECIES-X25519]_ + + + +Design +====== + +The ECIES Router SKM does not need a full Ratchet SKM as specified in [ECIES]_ for Destinations. +There is no requirement for non-anonymous messages using the IK pattern. +The threat model does not require Elligator2-encoded ephemeral keys. + +Therefore, the router SKM will use the Noise "N" pattern, same as specified +in [Prop152]_ for tunnel building. +It will use the same payload format as specified in [ECIES]_ for Destinations. +The zero static key (no binding or session) mode of IK specified in [ECIES]_ will not be used. + +Replies to lookups will be encrypted with a ratchet tag if requested in the lookup. +This is as documented in [Prop154]_, now specified in [I2NP]_. + +The design enables the router to have a single ECIES Session Key Manager. +There is no need to run "dual key" Session Key Managers as +described in [ECIES]_ for Destinations. +Routers only have one public key. + +An ECIES router does not have an ElGamal static key. +The router still needs an implementation of ElGamal to build tunnels +through ElGamal routers and send encrypted messages to ElGamal routers. + +An ECIES router MAY require a partial ElGamal Session Key Manager to +receive ElGamal-tagged messages received as replies to NetDB lookups +from pre-0.9.46 floodfill routers, as those routers do not +have an implementation of ECIES-tagged replies as specified in [Prop152]_. +If not, an ECIES router may not request an encrypted reply from a +pre-0.9.46 floodfill router. + +This is optional. Decision may vary in various I2P implementations +and may depend on the amount of the network that has upgraded to +0.9.46 or higher. +As of this date, approximately 85% of the network is 0.9.46 or higher. + + +Noise Protocol Framework +------------------------ + +This specification provides the requirements based on the Noise Protocol Framework +[NOISE]_ (Revision 34, 2018-07-11). +In Noise parlance, Alice is the initiator, and Bob is the responder. + +It is based on the Noise protocol Noise_N_25519_ChaChaPoly_SHA256. +This Noise protocol uses the following primitives: + +- 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. + + +Handshake Patterns +------------------ + +Handshakes use [Noise]_ handshake patterns. + +The following letter mapping is used: + +- e = one-time ephemeral key +- s = static key +- p = message payload + +The build request is identical to the Noise N pattern. +This is also identical to the first (Session Request) message in the XK pattern used in [NTCP2]_. + + +.. raw:: html + + {% highlight lang='dataspec' %} +<- s + ... + e es p -> + +{% endhighlight %} + + +Message encryption +----------------------- + +Messages are created and asymmetrically encrypted to the target router. +This asymmetric encryption of messages is currently ElGamal as defined in [Cryptography]_ +and contains a SHA-256 checksum. This design is not forward-secret. + +The ECIES design uses the one-way Noise pattern "N" with ECIES-X25519 ephemeral-static DH, with an HKDF, and +ChaCha20/Poly1305 AEAD for forward secrecy, integrity, and authentication. +Alice is the anonymous message sender, a router or destination. +The target ECIES router is Bob. + + + +Reply encryption +----------------------- + +Replies are not part of this protocol, as Alice is anonymous. The reply keys, if any, +are bundled in the request message. See the I2NP specification [I2NP]_ for Database Lookup Messages. + +Replies to Database Lookup messages are Database Store or Database Search Reply messages. +They are encrypted as Existing Session messages with +the 32-byte reply key and 8-byte reply tag +as specified in [I2NP]_ and [Prop154]_. + +There are no explicit replies to Database Store messages. The sender may bundle its +own reply as a Garlic Message to itself, containing a Delivery Status message. + + + +Specification +========================= + +X25519: See [ECIES]_. + +Router Identity and Key Certificate: See [Common]_. + + +Request Encryption +--------------------- + +The request encryption is the same as that specified in [Tunnel-Creation-ECIES]_ and [Prop152]_, +using the Noise "N" pattern. + +Replies to lookups will be encrypted with a ratchet tag if requested in the lookup. +Database Lookup request messages contain the 32-byte reply key and 8-byte reply tag +as specified in [I2NP]_ and [Prop154]_. The key and tag are used to encrypt the reply. + +Tag sets are not created. +The zero static key scheme specified in +ECIES-X25519-AEAD-Ratchet [Prop144]_ and [ECIES]_ will not be used. +Ephemeral keys will not be Elligator2-encoded. + +Generally, these will be New Session messages and will be sent with a zero static key +(no binding or session), as the sender of the message is anonymous. + + +KDF for Initial ck and h +```````````````````````` + +This is standard [NOISE]_ for pattern "N" with a standard protocol name. +This is the same as specified in [Tunnel-Creation-ECIES]_ and [Prop152]_ for tunnel build messages. + + +.. raw:: html + + {% highlight lang='text' %} +This is the "e" message pattern: + + // Define protocol_name. + Set protocol_name = "Noise_N_25519_ChaChaPoly_SHA256" + (31 bytes, US-ASCII encoded, no NULL termination). + + // Define Hash h = 32 bytes + // Pad to 32 bytes. Do NOT hash it, because it is not more than 32 bytes. + h = protocol_name || 0 + + Define ck = 32 byte chaining key. Copy the h data to ck. + Set chainKey = h + + // MixHash(null prologue) + h = SHA256(h); + + // up until here, can all be precalculated by all routers. + +{% endhighlight %} + + +KDF for Message +```````````````````````` + +Message creators generate an ephemeral X25519 keypair for each message. +Ephemeral keys must be unique per message. +This is the same as specified in [Tunnel-Creation-ECIES]_ and [Prop152]_ for tunnel build messages. + + +.. raw:: html + + {% highlight lang='dataspec' %} + +// Target router's X25519 static keypair (hesk, hepk) from the Router Identity + hesk = GENERATE_PRIVATE() + hepk = DERIVE_PUBLIC(hesk) + + // MixHash(hepk) + // || below means append + h = SHA256(h || hepk); + + // up until here, can all be precalculated by each router + // for all incoming messages + + // Sender generates an X25519 ephemeral keypair + sesk = GENERATE_PRIVATE() + sepk = DERIVE_PUBLIC(sesk) + + // MixHash(sepk) + h = SHA256(h || sepk); + + End of "e" message pattern. + + This is the "es" message pattern: + + // Noise es + // Sender performs an X25519 DH with receiver's static public key. + // The target router + // extracts the sender's ephemeral key preceding the encrypted record. + sharedSecret = DH(sesk, hepk) = DH(hesk, sepk) + + // MixKey(DH()) + //[chainKey, k] = MixKey(sharedSecret) + // ChaChaPoly parameters to encrypt/decrypt + keydata = HKDF(chainKey, sharedSecret, "", 64) + // Chain key is not used + //chainKey = keydata[0:31] + + // AEAD parameters + k = keydata[32:64] + n = 0 + plaintext = 464 byte build request record + ad = h + ciphertext = ENCRYPT(k, n, plaintext, ad) + + End of "es" message pattern. + + // MixHash(ciphertext) is not required + //h = SHA256(h || ciphertext) + +{% endhighlight %} + + + +Payload +```````````````````````` + +The payload is the same block format as defined in [ECIES]_ and [Prop144]_. +All messages must contain a DateTime block for replay prevention. + + + + +Implementation Notes +===================== + +* Older routers do not check the encryption type of the router and will send ElGamal-encrypted + messages. Some recent routers are buggy and will send various types of malformed messages. + Implementers should detect and reject these records prior to the DH operation + if possible, to reduce CPU usage. + + + +References +========== + +.. [Common] + {{ spec_url('common-structures') }} + +.. [Cryptography] + {{ spec_url('cryptography') }} + +.. [ECIES-X25519] + {{ spec_url('ecies') }} + +.. [I2NP] + {{ spec_url('i2np') }} + +.. [NOISE] + https://noiseprotocol.org/noise.html + +.. [NTCP2] + {{ spec_url('ntcp2') }} + +.. [Prop119] + {{ proposal_url('119') }} + +.. [Prop143] + {{ proposal_url('143') }} + +.. [Prop152] + {{ proposal_url('152') }} + +.. [Prop153] + {{ proposal_url('153') }} + +.. [Prop156] + {{ proposal_url('156') }} + +.. [Prop157] + {{ proposal_url('157') }} + +.. [Tunnel-Creation] + {{ spec_url('tunnel-creation') }} + +.. [Multiple-Encryption] + https://en.wikipedia.org/wiki/Multiple_encryption + +.. [RFC-7539] + https://tools.ietf.org/html/rfc7539 + +.. [RFC-7748] + https://tools.ietf.org/html/rfc7748 + + + diff --git a/i2p2www/spec/i2np.rst b/i2p2www/spec/i2np.rst index 16f479ce..e415b120 100644 --- a/i2p2www/spec/i2np.rst +++ b/i2p2www/spec/i2np.rst @@ -3,8 +3,8 @@ I2NP Specification ================== .. meta:: :category: Protocols - :lastupdated: 2020-11 - :accuratefor: 0.9.48 + :lastupdated: 2021-01 + :accuratefor: 0.9.49 .. contents:: @@ -42,11 +42,15 @@ below. ============== ================================================================ Version Required I2NP Features ============== ================================================================ - 0.9.48 ECIES-X25519 Build Request/Response records + 0.9.49 Garlic messages to ECIES-X25519 routers + + 0.9.48 ECIES-X25519 Routers + + ECIES-X25519 Build Request/Response records 0.9.46 DatabaseLookup flag bit 4 for AEAD reply - 0.9.44 X25519 keys in LeaseSet2 + 0.9.44 ECIES-X25519 keys in LeaseSet2 0.9.40 MetaLeaseSet may be sent in a DSM @@ -576,7 +580,7 @@ Delivery Instructions! Tunnel ID :: `TunnelId` 4 bytes Optional, present if delivery type is TUNNEL - The destination tunnel ID + The destination tunnel ID, nonzero Delay :: `Integer` 4 bytes @@ -862,7 +866,7 @@ Contents reply_tunnelId :: 4 byte `TunnelID` only included if deliveryFlag == 1 - tunnelId of the tunnel to send the reply to + tunnelId of the tunnel to send the reply to, nonzero size :: 2 byte `Integer` @@ -898,14 +902,21 @@ Reply Encryption Flag bit 4 is used in combination with bit 1 to determine the reply encryption mode. Flag bit 4 must only be set when sending to routers with version 0.9.46 or higher. -See proposal 154 for details. +See proposals 154 and 156 for details. + +In the table below, +"DH n/a" means that the reply is not encrypted. +"DH no" means that the reply keys are included in the request. +"DH yes" means that the reply keys are derived from the DH operation. ============= ========= ========= ====== === ======= -Flag bits 4,1 From Dest To Router Reply DH? notes +Flag bits 4,1 From To Router Reply DH? notes ============= ========= ========= ====== === ======= -0 0 Any Any no enc no +0 0 Any Any no enc n/a no encryption 0 1 ElG ElG AES no As of 0.9.7 1 0 ECIES ElG AEAD no As of 0.9.46 +1 0 ECIES ECIES AEAD no As of 0.9.49 +1 1 ElG ECIES AES yes TBD 1 1 ECIES ECIES AEAD yes TBD ============= ========= ========= ====== === ======= @@ -1043,12 +1054,24 @@ tag :: 8 byte reply_tag {% endhighlight %} -ECIES to ECIES -`````````````` +ECIES to ECIES (0.9.49) +----------------------------- + +ECIES destination or router sends a lookup to a ECIES router. +Supported as of 0.9.49. + +ECIES routers were introduced in 0.9.48, see [Prop156]_. +ECIES destinations and routers may use the same format as in +the "ECIES to ElG" section above, with reply keys included in the request. +The lookup message encryption is specified in [ECIES-ROUTERS]_. +The requester is anonymous. + + +ECIES to ECIES (future) +----------------------------- + This option is not yet fully defined. -ECIES routers do not yet exist and there is no documented proposal -for ECIES routers at this time. -See proposal 154. +See [Prop156]_. Notes @@ -1313,6 +1336,7 @@ Contents tunnelId :: 4 byte `TunnelId` identifies the tunnel this message is directed at + nonzero data :: 1024 bytes @@ -1347,6 +1371,7 @@ Contents tunnelId :: 4 byte `TunnelId` identifies the tunnel this message is directed at + nonzero length :: 2 byte `Integer` @@ -1541,6 +1566,9 @@ References .. [ECIES] {{ spec_url('ecies') }} +.. [ECIES-ROUTERS] + {{ spec_url('ecies-routers') }} + .. [ElG-AES] {{ site_url('docs/how/elgamal-aes', True) }} @@ -1559,6 +1587,9 @@ References .. [NTCP2] {{ spec_url('ntcp2') }} +.. [Prop156] + {{ proposal_url('156') }} + .. [RouterIdentity] {{ ctags_url('RouterIdentity') }} diff --git a/i2p2www/spec/proposals/154-ecies-lookups.rst b/i2p2www/spec/proposals/154-ecies-lookups.rst index e7a6fd0e..12c60743 100644 --- a/i2p2www/spec/proposals/154-ecies-lookups.rst +++ b/i2p2www/spec/proposals/154-ecies-lookups.rst @@ -5,7 +5,7 @@ Database Lookups from ECIES Destinations :author: zzz :created: 2020-03-23 :thread: http://zzz.i2p/topics/2856 - :lastupdated: 2020-05-07 + :lastupdated: 2021-01-08 :status: Closed :target: 0.9.46 :implementedin: 0.9.46 @@ -15,11 +15,11 @@ Database Lookups from ECIES Destinations Note ==== -ECIES to ElG is implemented and the proposal phase is closed. +ECIES to ElG is implemented in 0.9.46 and the proposal phase is closed. See [I2NP]_ for the official specification. This proposal may still be referenced for background information. -ECIES to ECIES is not fully specified or implemented at this time. -The ECIES-to-ECIES section may be reopened or incorporated +ECIES to ECIES with included keys is implemented as of 0.9.48. +The ECIES-to-ECIES (derived keys) section may be reopened or incorporated in a future proposal. @@ -146,14 +146,21 @@ Flag bit 4 is used in combination with bit 1 to determine the reply encryption m Flag bit 4 must only be set when sending to routers with version 0.9.46 or higher. +In the table below, +"DH n/a" means that the reply is not encrypted. +"DH no" means that the reply keys are included in the request. +"DH yes" means that the reply keys are derived from the DH operation. + + ============= ========= ========= ====== === ======= Flag bits 4,1 From Dest To Router Reply DH? notes ============= ========= ========= ====== === ======= -0 0 Any Any no enc no current +0 0 Any Any no enc n/a current 0 1 ElG ElG AES no current 0 1 ECIES ElG AES no i2pd workaround -1 0 ECIES ElG AEAD no new, no DH -1 1 ECIES ECIES AEAD yes future, with DH +1 0 ECIES ElG AEAD no this proposal +1 0 ECIES ECIES AEAD no 0.9.49 +1 1 ECIES ECIES AEAD yes future ============= ========= ========= ====== === ======= @@ -262,11 +269,28 @@ tag :: 8 byte reply_tag -ECIES to ECIES --------------- +ECIES to ECIES (0.9.49) +----------------------------- -ECIES destination sends a lookup to a ECIES router. -Supported as of 0.9.TBD. +ECIES destination or router sends a lookup to a ECIES router, with bundled reply keys. +Supported as of 0.9.49. + +ECIES routers were introduced in 0.9.48, see [Prop156]_. +As of 0.9.49, ECIES destinations and routers may use the same format as in +the "ECIES to ElG" section above, with reply keys included in the request. +The lookup will use the "one time format" in [ECIES]_ +as the requester is anonymous. + +For a new method with derived keys, see the next section. + + + + +ECIES to ECIES (future) +----------------------------- + +ECIES destination or router sends a lookup to a ECIES router, and the reply keys are derived from the DH. +Not fully defined or supported, implementation is TBD. The lookup will use the "one time format" in [ECIES]_ as the requester is anonymous. @@ -275,8 +299,6 @@ Redefine reply_key field as follows. There are no associated tags. The tags will be generated in the KDF below. This section is incomplete and requires further study. -ECIES routers do not yet exist and there is no documented proposal -for ECIES routers at this time. .. raw:: html @@ -428,3 +450,5 @@ References .. [I2NP] {{ spec_url('i2np') }} +.. [Prop156] + {{ proposal_url('156') }} diff --git a/i2p2www/spec/proposals/156-ecies-routers.rst b/i2p2www/spec/proposals/156-ecies-routers.rst index c239bb47..a586acb7 100644 --- a/i2p2www/spec/proposals/156-ecies-routers.rst +++ b/i2p2www/spec/proposals/156-ecies-routers.rst @@ -12,6 +12,19 @@ ECIES Routers .. contents:: +Note +==== +Network deployment and testing in progress. +Subject to revision. +Status: + +- ECIES Routers implemented as of 0.9.48, see [Common]_. +- Tunnel building implemented as of 0.9.48, see [Tunnel-Creation-ECIES]_. +- Encrypted messages to ECIES routers implemented as of 0.9.49, see [ECIES-ROUTERS]_. +- New tunnel build message is not yet defined or implemented. + + + Overview ======== @@ -538,6 +551,9 @@ References .. [ECIES] {{ spec_url('ecies') }} +.. [ECIES-ROUTERS] + {{ spec_url('ecies-routers') }} + .. [I2NP] {{ spec_url('i2np') }} diff --git a/i2p2www/spec/tunnel-message.rst b/i2p2www/spec/tunnel-message.rst index 173be492..1c26d77a 100644 --- a/i2p2www/spec/tunnel-message.rst +++ b/i2p2www/spec/tunnel-message.rst @@ -3,8 +3,8 @@ Tunnel Message Specification ============================ .. meta:: :category: Design - :lastupdated: September 2016 - :accuratefor: 0.9.26 + :lastupdated: 2021-01 + :accuratefor: 0.9.49 .. contents:: @@ -60,7 +60,7 @@ These are the contents of a tunnel data message after encryption. Tunnel ID :: `TunnelId` 4 bytes - the ID of the next hop + the ID of the next hop, nonzero IV :: 16 bytes @@ -121,7 +121,7 @@ These are the contents of a tunnel data message when decrypted. Tunnel ID :: `TunnelId` 4 bytes - the ID of the next hop + the ID of the next hop, nonzero IV :: 16 bytes @@ -225,7 +225,7 @@ or a complete (unfragmented) I2NP message, and the instructions are: Tunnel ID :: `TunnelId` 4 bytes Optional, present if delivery type is TUNNEL - The destination tunnel ID + The destination tunnel ID, nonzero To Hash :: 32 bytes