{% extends "global/layout.html" %} {% block title %}I2NP Specification{% endblock %} {% block lastupdated %}September 2014{% endblock %} {% block accuratefor %}0.9.15{% endblock %} {% block content %}

The I2P Network Protocol (I2NP), which is sandwiched between I2CP and the various I2P transport protocols, manages the routing and mixing of messages between routers, as well as the selection of what transports to use when communicating with a peer for which there are multiple common transports supported.

Common structures

The following structures are elements of multiple I2NP messages. They are not complete messages.

I2NP message header

Description

Common header to all I2NP messages, which contains important information like a checksum, expiration date, etc.

Contents

1 byte Integer specifying the type of this message, followed by a 4 byte Integer specifying the message-id. After that there is an expiration Date, followed by a 2 byte Integer specifying the length of the message payload, followed by a Hash, which is truncated to the first byte. After that the actual message data follows.

{% highlight lang='dataspec' %} Standard (16 bytes): +----+----+----+----+----+----+----+----+ |type| msg_id | expiration +----+----+----+----+----+----+----+----+ | size |chks| +----+----+----+----+----+----+----+----+ Short (SSU, 5 bytes): +----+----+----+----+----+ |type| short_expiration | +----+----+----+----+----+ {% endhighlight %}

Definition

type :: `Integer`
        length -> 1 byte
        
        purpose -> identifies the message type (see table below)

msg_id :: `Integer`
          length -> 4 bytes

          purpose -> uniquely identifies this message (for some time at least)
                     This is usually a locally-generated random number, but for
                     outgoing tunnel build messages it may be derived from
                     the incoming message. See below.

expiration :: `Date`
           8 bytes
           date this message will expire

short_expiration :: `Integer`
           4 bytes
           date this message will expire (seconds since the epoch)

size :: `Integer`
        length -> 2 bytes
        
        purpose -> length of the payload

chks :: `Integer`
        length -> 1 byte
     
        purpose -> checksum of the payload
                   SHA256 hash truncated to the first byte

data :: Data
        length -> $size bytes
        
        purpose -> actual message contents

Notes

BuildRequestRecord

Description

One Record in a set of multiple records to request the creation of one hop in the tunnel. For more details see the tunnel overview and the tunnel creation specification.

Contents

TunnelId to receive messages on, followed by the Hash of our RouterIdentity. After that the TunnelId and the Hash of the next router's RouterIdentity follow.

Definition

{% highlight lang='dataspec' %} Cleartext: +----+----+----+----+----+----+----+----+ | receive_tunnel | our_ident | +----+----+----+----+ + | | + + | | + + | | + +----+----+----+----+ | | next_tunnel | +----+----+----+----+----+----+----+----+ | next_ident | + + | | + + | | + + | | +----+----+----+----+----+----+----+----+ | layer_key | + + | | + + | | + + | | +----+----+----+----+----+----+----+----+ | iv_key | + + | | + + | | + + | | +----+----+----+----+----+----+----+----+ | reply_key | + + | | + + | | + + | | +----+----+----+----+----+----+----+----+ | reply_iv | + + | | +----+----+----+----+----+----+----+----+ |flag| request_time | send_msg_id +----+----+----+----+----+----+----+----+ | | +----+ + | 29 bytes padding | + + | | + +----+----+ | | +----+----+----+----+----+----+ ElGamal encrypted: +----+----+----+----+----+----+----+----+ | toPeer | + + | | +----+----+----+----+----+----+----+----+ | encrypted data... | ~ ~ | | +----+----+----+----+----+----+----+----+ ElGamal and AES encrypted: +----+----+----+----+----+----+----+----+ | encrypted data... | ~ ~ | | +----+----+----+----+----+----+----+----+ {% endhighlight %}

Definition

unencrypted:

receive_tunnel :: `TunnelId`
                  length -> 4 bytes
our_ident :: `Hash`
             length -> 32 bytes

next_tunnel :: `TunnelId`
               length -> 4 bytes

next_ident :: `Hash`
              length -> 32 bytes

layer_key :: `SessionKey`
             length -> 32 bytes

iv_key :: `SessionKey`
          length -> 32 bytes

reply_key :: `SessionKey`
             length -> 32 bytes

reply_iv :: data
            length -> 16 bytes

flag :: `Integer`
        length -> 1 byte

request_time :: `Integer`
                length -> 4 bytes
                Hours since the epoch, i.e. current time / 3600

send_message_id :: `Integer`
                   length -> 4 bytes

padding :: Data
           length -> 29 bytes
           source -> random

total length: 222


ElGamal encrypted:

toPeer :: First 16 bytes of the SHA-256 Hash of the peer's router identity
          length -> 16 bytes

encrypted_data :: ElGamal-2048 encrypted data (see notes)
                  length -> 512

total length: 528


ElGamal and AES encrypted:

encrypted_data :: ElGamal and AES encrypted data
                  length -> 528

total length: 528

Notes

BuildResponseRecord

{% highlight lang='dataspec' %} unencrypted: +----+----+----+----+----+----+----+----+ | | + + | | + SHA-256 Hash of following bytes + | | + + | | +----+----+----+----+----+----+----+----+ | random data... | ~ ~ | | + +----+ | |ret | +----+----+----+----+----+----+----+----+ {% endhighlight %}

Definition

unencrypted:
bytes 0-31   : SHA-256 Hash of bytes 32-527
bytes 32-526 : random data
byte  527    : reply

encrypted:
bytes 0-527: AES-encrypted record(note: same size as BuildRequestRecord)

total length: 528

Notes

GarlicClove

{% highlight lang='dataspec' %} unencrypted: +----+----+----+----+----+----+----+----+ | Delivery Instructions | ~ ~ ~ ~ | | +----+----+----+----+----+----+----+----+ | I2NP Message | ~ ~ ~ ~ | | +----+----+----+----+----+----+----+----+ | Clove ID | Expiration +----+----+----+----+----+----+----+----+ | Certificate | +----+----+----+----+----+----+----+ {% endhighlight %}

Definition

unencrypted:
Delivery Instructions :: as defined below
       Length varies but is typically 1, 33, or 37 bytes

I2NP Message :: Any I2NP Message

Clove ID :: 4 byte `Integer`

Expiration :: `Date` (8 bytes)

Certificate :: Always NULL in the current implementation (3 bytes total, all zeroes)

Notes

Garlic Clove Delivery Instructions

This specification is for Delivery Instructions inside Garlic Cloves only. Note that "Delivery Instructions" are also used inside Tunnel Messages, where the format is significantly different. See the Tunnel Message documentation for details. Do NOT use the following specification for Tunnel Message Delivery Instructions! {% highlight lang='dataspec' %} +----+----+----+----+----+----+----+----+ |flag| | +----+ + | | + Session Key (optional) + | | + + | | + +----+----+----+----+--------------+ | | | +----+ + | | + To Hash (optional) + | | + + | | + +----+----+----+----+--------------+ | | Tunnel ID (opt) | Delay (opt) +----+----+----+----+----+----+----+----+ | +----+ {% endhighlight %}

Definition

flag:
       1 byte
       Bit order: 76543210
       bit 7: encrypted? Unimplemented, always 0
                If 1, a 32-byte encryption session key is included
       bits 6-5: delivery type
                0x0 = LOCAL, 0x01 = DESTINATION, 0x02 = ROUTER, 0x03 = TUNNEL
       bit 4: delay included?  Not fully implemented, always 0
                If 1, four delay bytes are included
       bits 3-0: reserved, set to 0 for compatibility with future uses

Session Key:
       32 bytes
       Optional, present encrypt flag bit is set. Unimplemented, never set, never present.

To Hash:
       32 bytes
       Optional, present if delivery type is DESTINATION, ROUTER, or TUNNEL
          If DESTINATION, the SHA256 Hash of the destination
          If ROUTER, the SHA256 Hash of the router
          If TUNNEL, the SHA256 Hash of the gateway router

Tunnel ID:
       4 bytes
       Optional, present if delivery type is TUNNEL
       The destination tunnel ID

Delay:
       4 bytes
       Optional, present if delay included flag is set
       Not fully implemented. A 4 byte integer specifying the delay in seconds.

Total length: Typical length is:
       1 byte for LOCAL delivery;
       33 bytes for ROUTER / DESTINATION delivery;
       37 bytes for TUNNEL delivery

Messages

Message Type
DatabaseStore 1
DatabaseLookup 2
DatabaseSearchReply 3
DeliveryStatus 10
Garlic 11
TunnelData 18
TunnelGateway 19
Data 20
TunnelBuild 21
TunnelBuildReply 22
VariableTunnelBuild 23
VariableTunnelBuildReply 24

DatabaseStore

Description

An unsolicited database store, or the response to a successful Database Lookup Message

Contents

An uncompressed LeaseSet or a compressed RouterInfo

{% highlight lang='dataspec' %} with reply token: +----+----+----+----+----+----+----+----+ | SHA256 Hash as key | + + | | + + | | + + | | +----+----+----+----+----+----+----+----+ |type| reply token | reply tunnel- +----+----+----+----+----+----+----+----+ Id | SHA256 of the gateway RouterInfo | +----+ + | | + + | | + + | | + +----+----+----+----+----+----+----+ | | data ... +----+-// with reply token == 0: +----+----+----+----+----+----+----+----+ | SHA256 Hash as key | + + | | + + | | + + | | +----+----+----+----+----+----+----+----+ |type| 0 | data ... +----+----+----+----+----+-// {% endhighlight %}

Definition

key:
    32 bytes
    SHA256 hash

type:
     1 byte
     type identifier
     mapping:
             0    `RouterInfo`
             1    `LeaseSet`

reply token:
            4 bytes
            If greater than zero, a Delivery Status Message
            is requested with the Message ID set to the value of the Reply Token.
            A floodfill router is also expected to flood the data to the closest floodfill peers
            if the token is greater than zero.

reply tunnelId:
               4 byte `TunnelID`
               only included if reply token > 0
               This is the tunnel ID of the inbound gateway of the tunnel the response should be sent to

reply gateway:
              32 bytes
              Hash of the routerInfo entry to reach the gateway
              only included if reply token > 0
              This is the router hash of the inbound gateway of the tunnel the response should be sent to

data:
     If type == 0, data is a 2-byte integer specifying the number of bytes that follow,
                   followed by a gzip-compressed `RouterInfo`.
     If type == 1, data is an uncompressed `LeaseSet`.

Notes

DatabaseLookup

Description

A request to look up an item in the network database. The response is either a DatabaseStore or a DatabaseSearchReply.

Contents

{% highlight lang='dataspec' %} +----+----+----+----+----+----+----+----+ | SHA256 hash as the key to look up | + + | | + + | | + + | | +----+----+----+----+----+----+----+----+ | SHA256 hash of the routerInfo | + who is asking, or the gateway to + | send the reply to | + + | | + + | | +----+----+----+----+----+----+----+----+ |flag| reply_tunnelId |size | | +----+----+----+----+----+----+----+ + | SHA256 of $key1 to exclude | + + | | + + | | + +----+ | | | +----+----+----+----+----+----+----+ + | SHA256 of $key2 to exclude | + + ~ ~ + +----+ | | | +----+----+----+----+----+----+----+ + | | + + | Session key if reply encryption | + was requested + | | + +----+ | |tags| +----+----+----+----+----+----+----+----+ | | + + | Session tags if reply encryption | + was requested + | | + + | | +----+----+----+----+----+----+----+----+ {% endhighlight %}

Definition

key ::
    32 bytes
    SHA256 hash of the object to lookup

from ::
     32 bytes
     if deliveryFlag == 0, the SHA256 hash of the routerInfo entry this request came from (and to which the reply should be sent)
     if deliveryFlag == 1, the SHA256 hash of the reply tunnel gateway (to which the reply should be sent)

flags ::
     1 byte
     bit order: 76543210
     bit 0: deliveryFlag
             0  => send reply directly
             1  => send reply to some tunnel
     bit 1: encryptionFlag
             through release 0.9.5, must be set to 0
             as of release 0.9.6, ignored
             as of release 0.9.7:
             0  => send unencrypted reply
             1  => send AES encrypted reply using enclosed key and tag
     bits 3-2: lookup type flags
             through release 0.9.5, must be set to 00
             as of release 0.9.6, ignored
             as of release 0.9.16 (proposed):
             00  => normal lookup, return RI or LS or DSRM
             01  => LS lookup, return LS or DSRM
             10  => RI lookup, return RI or DSRM
             11  => exploration lookup, return DSRM containing non-floodfill routers only
                    (replaces an excludedPeer of all zeroes)
     bits 7-4:
             through release 0.9.5, must be set to 0
             as of release 0.9.6, ignored, set to 0 for compatibility with future uses and with older routers

reply_tunnelId ::
               4 byte `TunnelID`
               only included if deliveryFlag == 1
               tunnelId of the tunnel to send the reply to

size ::
     2 byte `Integer`
     valid range: 0-512
     number of peers to exclude from the DatabaseSearchReply Message

excludedPeers ::
              $size SHA256 hashes of 32 bytes each (total $size*32 bytes)
              if the lookup fails, these peers are requested to be excluded from the list in
              the DatabaseSearchReply Message.
              if excludedPeers includes a hash of all zeroes, the request is exploratory, and
              the DatabaseSearchReply Message is requested to list non-floodfill routers only.

reply_key ::
     32 byte `SessionKey`
     only included if encryptionFlag == 1, only as of release 0.9.7

tags ::
     1 byte `Integer`
     valid range: 1-32 (typically 1)
     the number of reply tags that follow
     only included if encryptionFlag == 1, only as of release 0.9.7

reply_tags ::
     one or more 32 byte `SessionTags` (typically one)
     only included if encryptionFlag == 1, only as of release 0.9.7

Notes

DatabaseSearchReply

Description

The response to a failed Database Lookup Message

Contents

A list of router hashes closest to the requested key

{% highlight lang='dataspec' %} +----+----+----+----+----+----+----+----+ | SHA256 hash as query key | + + | | + + | | + + | | +----+----+----+----+----+----+----+----+ |num | peer_hash $1 | +----+ + | | + + | | + + | | + +----+----+----+----+----+----+----+ | | | +----+ $num peer_hashes + + +----+----+----+----+----+----+----+ | | from | +----+ + | | + + | | + + | | + +----+----+----+----+----+----+----+ | | +----+ {% endhighlight %}

Definition

key ::
    32 bytes
    SHA256 of the object being searched

num ::
    1 byte `Integer`
    number of peer hashes that follow, 0-255

peer_hash ($num entries) ::
          32 bytes
          SHA256 of the `RouterIdentity` that the other router thinks is close to the key

from ::
     32 bytes
     SHA256 of the `RouterInfo` of the router this reply was sent from

Notes

DeliveryStatus

Description

A simple message acknowledgment. Generally created by the message originator, and wrapped in a Garlic Message with the message itself, to be returned by the destination.

Contents

The ID of the delivered message, and the creation or arrival time.

{% highlight lang='dataspec' %} +----+----+----+----+----+----+----+----+----+----+----+----+ |msg_id | time_stamp | +----+----+----+----+----+----+----+----+----+----+----+----+ {% endhighlight %}

Definition

msg_id ::
       4 bytes
       unique ID of the message we deliver the DeliveryStatus for (see common I2NP header for details)

time_stamp :: Date
             8 bytes
             time the message was successfully created or delivered

Notes

Garlic

Description

Used to wrap multiple encrypted I2NP Messages

Contents

When decrypted, a series of Garlic Cloves.

{% highlight lang='dataspec' %} encrypted: +----+----+----+----+----+----+----+----+ | length | data | +----+----+----+----+ + | | ~ ~ ~ ~ | | +----+----+----+----+----+----+----+----+ unencrypted data: +----+----+----+----+----+----+----+----+ |num | clove 1 | +----+ + | | ~ ~ ~ ~ | | +----+----+----+----+----+----+----+----+ | clove 2 ... | ~ ~ ~ ~ | | +----+----+----+----+----+----+----+----+ | Certificate | Message_ID | +----+----+----+----+----+----+----+----+ Expiration | +----+----+----+----+----+----+----+ {% endhighlight %}

Definition

Encrypted:

length ::
       4 byte Integer
       number of bytes that follow 0 - 64 KB

data ::
     $length bytes
     ElGamal encrypted data


Unencrypted data:

num ::
     1 byte Integer number of `GarlicCloves` to follow

clove ::  a `GarlicClove`

Certificate :: always NULL in the current implementation (3 bytes total, all zeroes)

Message_ID :: 4 byte `Integer`

Expiration :: `Date` (8 bytes)

Notes

TunnelData

Description

A message sent from a tunnel's gateway or participant to the next participant or endpoint. The data is of fixed length, containing I2NP messages that are fragmented, batched, padded, and encrypted.

Contents

{% highlight lang='dataspec' %} +----+----+----+----+----+----+----+----+ | tunnnelID | data | +----+----+----+----+ | | | ~ ~ ~ ~ | | + +----+----+----+----+ | | +----+----+----+----+ {% endhighlight %}

Definition

tunnelId ::
         4 byte `TunnelID`
         identifies the tunnel this message is directed at

data ::
     1024 bytes
     payload data.. fixed to 1024 bytes

Notes

TunnelGateway

Description

Wraps another I2NP message to be sent into a tunnel at the tunnel's inbound gateway.

Contents

{% highlight lang='dataspec' %} +----+----+----+----+----+----+----+-// | tunnelId | length | data... +----+----+----+----+----+----+----+-// {% endhighlight %}

Definition

tunnelId ::
         4 byte `TunnelID`
         identifies the tunnel this message is directed at

length ::
       2 byte `Integer`
       length of the payload

data ::
     $length bytes
     actual payload of this message

Notes

Data

Description

Used by Garlic Messages and Garlic Cloves to wrap arbitrary data.

Contents

A length Integer, followed by opaque data.

{% highlight lang='dataspec' %} +----+----+----+----+----+-//-+ | length | data... | +----+----+----+----+----+-//-+ {% endhighlight %}

Definition

length ::
       4 bytes
       length of the payload

data ::
     $length bytes
     actual payload of this message

TunnelBuild

{% highlight lang='dataspec' %} +----+----+----+----+----+----+----+----+ | Record 0 ... | | | +----+----+----+----+----+----+----+----+ | Record 1 ... | ..... +----+----+----+----+----+----+----+----+ | Record 7 ... | | | +----+----+----+----+----+----+----+----+ {% endhighlight %}

Definition

Just 8 `BuildRequestRecords` attached together
record size: 528 bytes
total size: 8*528 = 4224 bytes

Notes

TunnelBuildReply

{% highlight lang='dataspec' %} same format as `TunnelBuild` message, with `BuildResponseRecords` {% endhighlight %}

Notes

VariableTunnelBuild

{% highlight lang='dataspec' %} +----+----+----+----+----+----+----+----+ |num | BuildRequestRecords... +----+----+----+----+----+----+----+----+ {% endhighlight %}

Definition

Same format as TunnelBuildMessage, except for the addition of an "num" field in front and $num number of Build Request Records instead of 8

num ::
       1 byte `Integer`
       Valid values: 1-8

record size: 528 bytes
total size: 1 + $num*528

Notes

VariableTunnelBuildReply

{% highlight lang='dataspec' %} +----+----+----+----+----+----+----+----+ |num | BuildResponseRecords... +----+----+----+----+----+----+----+----+ {% endhighlight %}

Definition

Same format as VariableTunnelBuild message, with Build Response Records.

Notes

{% endblock %}