Migrated tunnel pages

This commit is contained in:
str4d
2012-12-11 10:12:40 +00:00
parent eaaf583b56
commit a45d706ff8
5 changed files with 30 additions and 22 deletions

View File

@@ -79,10 +79,18 @@
<li><a href="{{ site_url('docs/spec/i2np') }}"><span>I2NP</span></a></li>
<li><a href="{{ site_url('docs/spec/plugin') }}"><span>{{ _('Plugins') }}</span></a></li>
<li><a href="{{ site_url('docs/spec/ssu') }}"><span>SSU</span></a></li>
<li><a href="{{ site_url('docs/spec/tunnel_creation') }}"><span>{{ _('Tunnel creation') }}</span></a></li>
<li><a href="{{ site_url('docs/spec/tunnel_message') }}"><span>{{ _('Tunnel messages') }}</span></a></li>
<li><a href="{{ site_url('docs/spec/updates') }}"><span>{{ _('Software updates') }}</span></a></li>
</ul>
</li>
<li class="has-sub"><a href="#"><span>{{ _('Tunnels') }}</span></a>
<ul>
<li><a href="{{ site_url('docs/tunnels/implementation') }}"><span>{{ _('Tunnel implementation') }}</span></a></li>
<li><a href="{{ site_url('docs/tunnels/unidirectional') }}"><span>{{ _('Unidirectional tunnels') }}</span></a></li>
<li><a href="{{ site_url('docs/tunnels/old') }}"><span>{{ _('Old implementation') }}</span></a></li>
</ul>
</li>
<li><a href="{{ site_url('docs/naming') }}"><span>{{ _('Naming and addressbook') }}</span></a></li>
<li><a href="{{ site_url('docs/plugins') }}"><span>{{ _('Plugins') }}</span></a></li>
</ul>

View File

@@ -0,0 +1,326 @@
{% extends "_layout.html" %}
{% block title %}Tunnel Creation{% endblock %}
{% block content %}
This page documents the current tunnel build implementation.
Updated August 2010 for release 0.8
<h2 id="tunnelCreate.overview">Tunnel Creation Specification</h2>
<p>
This document specifies the details of the encrypted tunnel build messages
used to create tunnels using a "non-interactive telescoping" method.
See <a href="tunnel-alt.html">the tunnel build document</a>
for an overview of the process, including peer selection and ordering methods.
<p>The tunnel creation is accomplished by a single message passed along
the path of peers in the tunnel, rewritten in place, and transmitted
back to the tunnel creator. This single tunnel message is made up
of a variable number of records (up to 8) - one for each potential peer in
the tunnel. Individual records are asymmetrically
<a href="how_cryptography.html#elgamal">(ElGamal)</a>
encrypted to be
read only by a specific peer along the path, while an additional
symmetric layer of encryption
<a href="how_cryptography.html#AES">(AES)</a>
is added at each hop so as to expose
the asymmetrically encrypted record only at the appropriate time.</p>
<h3 id="number">Number of Records</h3>
Not all records must contain valid data.
The build message for a 3-hop tunnel, for example, may contain more records
to hide the actual length of the tunnel from the participants.
There are two build message types. The original
<a href="i2np_spec.html#msg_TunnelBuild">Tunnel Build Message</a> (TBM)
contains 8 records, which is more than enough for any practical tunnel length.
The recently-implemented
<a href="i2np_spec.html#msg_VariableTunnelBuild">Variable Tunnel Build Message</a> (VTBM)
contains 1 to 8 records. The originator may trade off the size of the message
with the desired amount of tunnel length obfuscation.
<p>
In the current network, most tunnels are 2 or 3 hops long.
The current implementation uses a 5-record VTBM to build tunnels of 4 hops or less,
and the 8-record TBM for longer tunnels.
The 5-record VTBM (which, when fragmented, fits in three 1KB tunnel messaages) reduces network traffic
and increases build sucess rate, because smaller messages are less likely to be dropped.
<p>
The reply message must be the same type and length as the build message.
<h3 id="tunnelCreate.requestRecord">Request Record Specification</h3>
Also specified in the
<a href="i2np_spec.html#struct_BuildRequestRecord">I2NP Specification</a>
<p>Cleartext of the record, visible only to the hop being asked:</p><pre>
bytes 0-3: tunnel ID to receive messages as
bytes 4-35: local router identity hash
bytes 36-39: next tunnel ID
bytes 40-71: next router identity hash
bytes 72-103: AES-256 tunnel layer key
bytes 104-135: AES-256 tunnel IV key
bytes 136-167: AES-256 reply key
bytes 168-183: AES-256 reply IV
byte 184: flags
bytes 185-188: request time (in hours since the epoch)
bytes 189-192: next message ID
bytes 193-221: uninterpreted / random padding</pre>
<p>The next tunnel ID and next router identity hash fields are used to
specify the next hop in the tunnel, though for an outbound tunnel
endpoint, they specify where the rewritten tunnel creation reply
message should be sent. In addition, the next message ID specifies the
message ID that the message (or reply) should use.</p>
<p>The flags field contains the following:
<pre>
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
bits 5-0: Undefined
</pre>
Bit 7 indicates that the hop will be an inbound gateway (IBGW).
Bit 6 indicates that the hop will be an outbound endpoint (OBEP).
If neither bit is set, the hop will be an intermediate participant.
<h4>Request Record Creation</h4>
<p>
Every hop gets a random Tunnel ID.
The current and next-hop Tunnel IDs are filled in.
Every record gets a random tunnel IV key, and reply IV.
The layer and reply key pairs are generated.
</p>
<h4 id="encryption">Request Record Encryption</h4>
<p>That cleartext record is <a href="how_cryptography.html#elgamal">ElGamal 2048 encrypted</a> with the hop's
public encryption key and formatted into a 528 byte record:</p><pre>
bytes 0-15: First 16 bytes of the SHA-256 of the current hop's router identity
bytes 16-527: ElGamal-2048 encrypted request record</pre>
In the 512-byte encrypted record,
the ElGamal data contains bytes 1-256 and 258-513 of the
<a href="how_cryptography.html#elgamal">514-byte ElGamal encrypted block</a>.
The two padding bytes from the block (the zero bytes at locations 0 and 257) are removed.
<p>Since the cleartext uses the full field, there is no need for
additional padding beyond <code>SHA256(cleartext) + cleartext</code>.</p>
<p>
Each 528-byte record is then iteratively encrypted
(using AES decryption, with the reply key and reply IV for each hop) so that the router identity will only be in cleartext
for the hop in question.
</p>
<h3 id="tunnelCreate.hopProcessing">Hop Processing and Encryption</h3>
<p>When a hop receives a TunnelBuildMessage, it looks through the
records contained within it for one starting with their own identity
hash (trimmed to 8 bytes). It then decrypts the ElGamal block from
that record and retrieves the protected cleartext. At that point,
they make sure the tunnel request is not a duplicate by feeding the
AES-256 reply key into a bloom filter.
Duplicates or invalid requests
are dropped.</p>
<p>After deciding whether they will agree to participate in the tunnel
or not, they replace the record that had contained the request with
an encrypted reply block. All other records are <a href="how_cryptography.html#AES">AES-256
encrypted</a> with the included reply key and IV. Each is
encrypted separately, rather than chained across records.</p>
<p>
Each hop knows only its own response.
If it agrees, it will maintain the tunnel until expiration,
even if it will not be used,
as it cannot know whether all other hops agreed.
</p>
<h4 id="tunnelCreate.replyRecord">Reply Record Specification</h4>
<p>After the current hop reads their record, they replace it with a
reply record stating whether or not they agree to participate in the
tunnel, and if they do not, they classify their reason for
rejection. This is simply a 1 byte value, with 0x0 meaning they
agree to participate in the tunnel, and higher values meaning higher
levels of rejection.
<p>
The following rejection codes are defined:
<ul>
<li>
TUNNEL_REJECT_PROBABALISTIC_REJECT = 10
<li>
TUNNEL_REJECT_TRANSIENT_OVERLOAD = 20
<li>
TUNNEL_REJECT_BANDWIDTH = 30
<li>
TUNNEL_REJECT_CRIT = 50
</ul>
To hide other causes, such as router shutdown, from peers, the current implementation
uses TUNNEL_REJECT_BANDWIDTH for almost all rejections.
<p>
The reply is encrypted with the AES session
key delivered to it in the encrypted block, padded with 527 bytes of random data
to reach the full record size.
The padding is placed before the status byte:
</p><pre>
AES-256-CBC(SHA-256(padding+status) + padding + status, key, IV)</pre>
This is also described in the
<a href="i2np_spec.html#msg_TunnelBuildReply">I2NP spec</a>.
<h3 id="tunnelCreate.requestPreparation">Tunnel Build Message Preparation</h3>
<p>When building a new Tunnel Build Messaage, all of the Build Request Records must first be
built and asymmetrically encrypted using
<a href="how_cryptography.html#elgamal">ElGamal</a>.
Each record is then
premptively decrypted with the reply keys and IVs of the hops earlier in the
path, using
<a href="how_cryptography.html#AES">AES</a>.
That decryption should be run in reverse order so that the
asymmetrically encrypted data will show up in the clear at the
right hop after their predecessor encrypts it.</p>
<p>The excess records not needed for individual requests are simply
filled with random data by the creator.</p>
<h3 id="tunnelCreate.requestDelivery">Tunnel Build Message Delivery</h3>
<p>For outbound tunnels, the delivery is done directly from the tunnel
creator to the first hop, packaging up the TunnelBuildMessage as if
the creator was just another hop in the tunnel. For inbound
tunnels, the delivery is done through an existing outbound tunnel.
The outbound tunnel is generally from the same pool as the new tunnel being built.
If no outbound tunnel is available in that pool, an outbound exploratory tunnel is used.
At startup, when no outbound exploratory tunnel exists yet, a fake 0-hop
outbound tunnel is used.</p>
<h3 id="tunnelCreate.endpointHandling">Tunnel Build Message Endpoint Handling</h3>
<p>
For creation of an outbound tunnel,
when the request reaches an outbound endpoint (as determined by the
'allow messages to anyone' flag), the hop is processed as usual,
encrypting a reply in place of the record and encrypting all of the
other records, but since there is no 'next hop' to forward the
TunnelBuildMessage on to, it instead places the encrypted reply
records into a
<a href="i2np_spec.html#msg_TunnelBuildReply">TunnelBuildReplyMessage</a>
or
<a href="i2np_spec.html#msg_VariableTunnelBuildReply">VariableTunnelBuildReplyMessage</a>
(the type of message and number of records must match that of the request)
and delivers it to the
reply tunnel specified within the request record. That reply tunnel
forwards the Tunnel Build Reply Message back to the tunnel creator,
<a href="tunnel-alt.html#tunnel.operation">just as for any other message</a>.
The tunnel creator then
processes it, as described below.</p>
<p>The reply tunnel was selected by the creator as follows:
Generally it is an inbound tunnel from the same pool as the new outbound tunnel being built.
If no inbound tunnel is available in that pool, an inbound exploratory tunnel is used.
At startup, when no inbound exploratory tunnel exists yet, a fake 0-hop
inbound tunnel is used.</p>
<p>
For creation of an inbound tunnel,
when the request reaches the inbound endpoint (also known as the
tunnel creator), there is no need to generate an explicit Tunnel Build Reply Message, and
the router processes each of the replies, as below.</p>
<h3 id="tunnelCreate.replyProcessing">Tunnel Build Reply Message Processing</h3>
<p>To process the reply records, the creator simply has to AES decrypt
each record individually, using the reply key and IV of each hop in
the tunnel after the peer (in reverse order). This then exposes the
reply specifying whether they agree to participate in the tunnel or
why they refuse. If they all agree, the tunnel is considered
created and may be used immediately, but if anyone refuses, the
tunnel is discarded.</p>
<p>
The agreements and rejections are noted in each peer's
<a href="how_peerselection.html">profile</a>, to be used in future assessments
of peer tunnel capacity.
<h2 id="tunnelCreate.notes">History and Notes</h2>
<p>
This strategy came about during a discussion on the I2P mailing list
between Michael Rogers, Matthew Toseland (toad), and jrandom regarding
the predecessor attack. See: <ul>
<li><a href="http://osdir.com/ml/network.i2p/2005-10/msg00138.html">Summary</a></li>
<li><a href="http://osdir.com/ml/network.i2p/2005-10/msg00129.html">Reasoning</a></li>
</ul></li>
It was introduced in release 0.6.1.10 on 2006-02-16, which was the last time
a non-backward-compatible change was made in I2P.
</p>
<p>
Notes:
<ul>
<li>This design does not prevent two hostile peers within a tunnel from
tagging one or more request or reply records to detect that they are
within the same tunnel, but doing so can be detected by the tunnel
creator when reading the reply, causing the tunnel to be marked as
invalid.</li>
<li>This design does not include a proof of work on the asymmetrically
encrypted section, though the 16 byte identity hash could be cut in
half with the latter replaced by a hashcash function of up to 2^64
cost.</li>
<li>This design alone does not prevent two hostile peers within a tunnel from
using timing information to determine whether they are in the same
tunnel. The use of batched and synchronized request delivery
could help (batching up requests and sending them off on the
(ntp-synchronized) minute). However, doing so lets peers 'tag' the
requests by delaying them and detecting the delay later in the
tunnel, though perhaps dropping requests not delivered in a small
window would work (though doing that would require a high degree of
clock synchronization). Alternately, perhaps individual hops could
inject a random delay before forwarding on the request?</li>
<li>Are there any nonfatal methods of tagging the request?</li>
</ul>
<h2 id="ref">References</h2>
<ul>
<li>
<a href="http://prisms.cs.umass.edu/brian/pubs/wright-tissec.pdf">Predecessor
attack</a>
<li>
<a href="http://prisms.cs.umass.edu/brian/pubs/wright.tissec.2008.pdf">2008
update</a>
<li>
<a href="http://www-users.cs.umn.edu/~hopper/hashing_it_out.pdf">Hashing it out in Public</a>
</ul>
<h2 id="future">Future Work</h2>
<ul>
<li>
In the current implementation, the originator leaves one record empty
for itself. Thus a message of n records can only build a
tunnel of n-1 hops.
This appears to be necessary for inbound tunnels (where the next-to-last hop
can see the hash prefix for the next hop), but not for outbound tunnels.
This is to be researched and verified.
If it is possible to use the remaining record without compromising anonymity,
we should do so.
<li>
The usefulness of a timestamp with an hour resolution is questionable,
and the constraint is not currently enforced.
Therefore the request time field is unused.
This should be researched and possibly changed.
<li>
Further analysis of possible tagging and timing attacks described in the above notes.
</li><li>
The Bloom filter rotation time should be evaluated.
</li><li>
Use only VTBM; do not select old peers that don't support it.
</li></ul>
{% endblock %}

View File

@@ -0,0 +1,440 @@
{% extends "global/layout.html" %}
{% block title %}Tunnel Implementation{% endblock %}
{% block content %}
This page documents the current tunnel implementation.
Updated October 2010 for release 0.8
<h2 id="tunnel.overview">Tunnel overview</h2>
<p>Within I2P, messages are passed in one direction through a virtual
tunnel of peers, using whatever means are available to pass the
message on to the next hop. Messages arrive at the tunnel's
</i>gateway</i>, get bundled up and/or fragmented into fixed-size tunnel messages,
and are forwarded on to the next hop in the tunnel, which processes and verifies
the validity of the message and sends it on to the next hop, and so on, until
it reaches the tunnel endpoint. That <i>endpoint</i> takes the messages
bundled up by the gateway and forwards them as instructed - either
to another router, to another tunnel on another router, or locally.</p>
<p>Tunnels all work the same, but can be segmented into two different
groups - inbound tunnels and outbound tunnels. The inbound tunnels
have an untrusted gateway which passes messages down towards the
tunnel creator, which serves as the tunnel endpoint. For outbound
tunnels, the tunnel creator serves as the gateway, passing messages
out to the remote endpoint.</p>
<p>The tunnel's creator selects exactly which peers will participate
in the tunnel, and provides each with the necessary configuration
data. They may have any number of hops.
It is the intent to make
it hard for either participants or third parties to determine the length of
a tunnel, or even for colluding participants to determine whether they are a
part of the same tunnel at all (barring the situation where colluding peers are
next to each other in the tunnel).</p>
<p>In practice, a series of tunnel pools are used for different
purposes - each local client destination has its own set of inbound
tunnels and outbound tunnels, configured to meet its anonymity and
performance needs. In addition, the router itself maintains a series
of pools for participating in the network database and for managing
the tunnels themselves.</p>
<p>I2P is an inherently packet switched network, even with these
tunnels, allowing it to take advantage of multiple tunnels running
in parallel, increasing resilience and balancing load. Outside of
the core I2P layer, there is an optional end to end streaming library
available for client applications, exposing TCP-esque operation,
including message reordering, retransmission, congestion control, etc.</p>
<p>
An overview of I2P tunnel terminology is
<a href="{{ site_url('docs/how/tunnelrouting') }}">on the tunnel overview page</a>.
</p>
<h2 id="tunnel.operation">Tunnel Operation (Message Processing)</h2>
<h3>Overview</h3>
<p>After a tunnel is built, <a href="{{ site_url('docs/spec/i2np') }}">I2NP messages</a> are processed and passed through it.
Tunnel operation has four distinct processes, taken on by various
peers in the tunnel. <ol><li>First, the tunnel gateway accumulates a number
of I2NP messages and preprocesses them into tunnel messages for
delivery. </li><li>Next, that gateway encrypts that preprocessed data, then
forwards it to the first hop. </li><li>That peer, and subsequent tunnel
participants, unwrap a layer of the encryption, verifying that it isn't
a duplicate, then forward it on to the next peer.
</li><li>Eventually, the tunnel messages arrive at the endpoint where the I2NP messages
originally bundled by the gateway are reassembled and forwarded on as
requested.</li></ol></p>
<p>
Intermediate tunnel participants do not know whether they are in an
inbound or an outbound tunnel; they always "encrypt" for the next hop.
Therefore, we take advantage of symmetric AES encryption
to "decrypt" at the outbound tunnel gateway,
so that the plaintext is revealed at the outbound endpoint.
</p>
<p>
<center>
<img src="{{ url_for('static', filename='images/tunnels.png') }}" alt="Inbound and outbound tunnel schematic" title="Inbound and outbound tunnel schematic" />
</center>
</p>
<table><tr>
<th>Role</th>
<th>Preprocessing</th>
<th>Encryption Operation</th>
<th>Postprocessing</th>
</tr>
<tr><td>Outbound Gateway (Creator)</td>
<td>Fragment, Batch, and Pad</td>
<td>Iteratively encrypt (using decryption operations)</td>
<td>Forward to next hop</td>
</tr>
<tr><td>Participant</td>
<td>&nbsp;</td>
<td>Decrypt (using an encryption operation)</td>
<td>Forward to next hop</td>
</tr>
<tr><td>Outbound Endpoint</td>
<td>&nbsp;</td>
<td>Decrypt (using an encryption operation) to reveal plaintext tunnel message</td>
<td>Reassemble Fragments, Forward as instructed to Inbound Gateway or Router</td>
</tr>
<tr><td colspan="4"><hr></td></tr>
<tr><td>Inbound Gateway</td>
<td>Fragment, Batch, and Pad</td>
<td>Encrypt</td>
<td>Forward to next hop</td>
</tr>
<tr><td>Participant</td>
<td>&nbsp;</td>
<td>Encrypt</td>
<td>Forward to next hop</td>
</tr>
<tr><td>Inbound Endpoint (Creator)</td>
<td>&nbsp;</td>
<td>Iteratively decrypt to reveal plaintext tunnel message</td>
<td>Reassemble Fragments, Receive data</td>
</tr>
</table>
<h3 id="tunnel.gateway">Gateway Processing</h3>
<h4 id="tunnel.preprocessing">Message Preprocessing</h4>
<p>A tunnel gateway's function is to fragment and pack
<a href="{{ site_url('docs/spec/i2np') }}">I2NP messages</a> into fixed-size
<a href="{{ site_url('docs/spec/tunnel_message') }}">tunnel messages</a>
and encrypt the tunnel messages.
Tunnel messages contain the following:
<ul>
<li>A 4 byte Tunnel ID</li>
<li>A 16 byte IV (initialization vector)</li>
<li>A checksum
<li>Padding, if necessary</li>
<li>One or more { delivery instruction, I2NP message fragment } pairs</li>
</ul>
<p>Tunnel IDs are 4 byte numbers used at each hop - participants know what
tunnel ID to listen for messages with and what tunnel ID they should be forwarded
on as to the next hop, and each hop chooses the tunnel ID which they receive messages
on. Tunnels themselves are short-lived (10 minutes).
Even if subsequent tunnels are built using the same sequence of
peers, each hop's tunnel ID will change.</p>
<p>To prevent adversaries from tagging the messages along the path by adjusting
the message size, all tunnel messages are a fixed 1024 bytes in size. To accommodate
larger I2NP messages as well as to support smaller ones more efficiently, the
gateway splits up the larger I2NP messages into fragments contained within each
tunnel message. The endpoint will attempt to rebuild the I2NP message from the
fragments for a short period of time, but will discard them as necessary.</p>
<p>
Details are in the
<a href="{{ site_url('docs/spec/tunnel_message') }}">tunnel message specification</a>.
<h3>Gateway Encryption</h3>
<p>After the preprocessing of messages into a padded payload, the gateway builds
a random 16 byte IV value, iteratively encrypting it and the tunnel message as
necessary, and forwards the tuple {tunnelID, IV, encrypted tunnel message} to the next hop.</p>
<p>How encryption at the gateway is done depends on whether the tunnel is an
inbound or an outbound tunnel. For inbound tunnels, they simply select a random
IV, postprocessing and updating it to generate the IV for the gateway and using
that IV along side their own layer key to encrypt the preprocessed data. For outbound
tunnels they must iteratively decrypt the (unencrypted) IV and preprocessed
data with the IV and layer keys for all hops in the tunnel. The result of the outbound
tunnel encryption is that when each peer encrypts it, the endpoint will recover
the initial preprocessed data.</p>
<h3 id="tunnel.participant">Participant Processing</h3>
<p>When a peer receives a tunnel message, it checks that the message came from
the same previous hop as before (initialized when the first message comes through
the tunnel). If the previous peer is a different router, or if the message has
already been seen, the message is dropped. The participant then encrypts the
received IV with AES256/ECB using their IV key to determine the current IV, uses
that IV with the participant's layer key to encrypt the data, encrypts the
current IV with AES256/ECB using their IV key again, then forwards the tuple
{nextTunnelId, nextIV, encryptedData} to the next hop. This double encryption
of the IV (both before and after use) help address a certain class of
confirmation attacks.</p>
<p>Duplicate message detection is handled by a decaying Bloom filter on message
IVs. Each router maintains a single Bloom filter to contain the XOR of the IV and
the first block of the message received for all of the tunnels it is participating
in, modified to drop seen entries after 10-20 minutes (when the tunnels will have
expired). The size of the bloom filter and the parameters used are sufficient to
more than saturate the router's network connection with a negligible chance of
false positive. The unique value fed into the Bloom filter is the XOR of the IV
and the first block so as to prevent nonsequential colluding peers in the tunnel
from tagging a message by resending it with the IV and first block switched.</p>
<h3 id="tunnel.endpoint">Endpoint Processing</h3>
<p>After receiving and validating a tunnel message at the last hop in the tunnel,
how the endpoint recovers the data encoded by the gateway depends upon whether
the tunnel is an inbound or an outbound tunnel. For outbound tunnels, the
endpoint encrypts the message with its layer key just like any other participant,
exposing the preprocessed data. For inbound tunnels, the endpoint is also the
tunnel creator so they can merely iteratively decrypt the IV and message, using the
layer and IV keys of each step in reverse order.</p>
<p>At this point, the tunnel endpoint has the preprocessed data sent by the gateway,
which it may then parse out into the included I2NP messages and forwards them as
requested in their delivery instructions.</p>
<h2 id="tunnel.building">Tunnel Building</h2>
<p>When building a tunnel, the creator must send a request with the necessary
configuration data to each of the hops and wait for all of them to agree before
enabling the tunnel. The requests are encrypted so that only the peers who need
to know a piece of information (such as the tunnel layer or IV key) has that
data. In addition, only the tunnel creator will have access to the peer's
reply. There are three important dimensions to keep in mind when producing
the tunnels: what peers are used (and where), how the requests are sent (and
replies received), and how they are maintained.</p>
<h3 id="tunnel.peerselection">Peer Selection</h3>
<p>Beyond the two types of tunnels - inbound and outbound - there are two styles
of peer selection used for different tunnels - exploratory and client.
Exploratory tunnels are used for both network database maintenance and tunnel
maintenance, while client tunnels are used for end to end client messages. </p>
<h4 id="tunnel.selection.exploratory">Exploratory tunnel peer selection</h4>
<p>Exploratory tunnels are built out of a random selection of peers from a subset
of the network. The particular subset varies on the local router and on what their
tunnel routing needs are. In general, the exploratory tunnels are built out of
randomly selected peers who are in the peer's "not failing but active" profile
category. The secondary purpose of the tunnels, beyond merely tunnel routing,
is to find underutilized high capacity peers so that they can be promoted for
use in client tunnels.</p>
<p>
Exploratory peer selection is discussed further on the
<a href="{{ site_url('docs/how/peerselection') }}">Peer Profiling and Selection page</a>.
<h4 id="tunnel.selection.client">Client tunnel peer selection</h4>
<p>Client tunnels are built with a more stringent set of requirements - the local
router will select peers out of its "fast and high capacity" profile category so
that performance and reliability will meet the needs of the client application.
However, there are several important details beyond that basic selection that
should be adhered to, depending upon the client's anonymity needs.</p>
<p>
Client peer selection is discussed further on the
<a href="{{ site_url('docs/how/peerselection') }}">Peer Profiling and Selection page</a>.
<h4 id="ordering">Peer Ordering within Tunnels</h4>
Peers are ordered within tunnels to
to deal with the <a href="http://prisms.cs.umass.edu/brian/pubs/wright-tissec.pdf">predecessor
attack</a> <a href="http://prisms.cs.umass.edu/brian/pubs/wright.tissec.2008.pdf">(2008
update)</a>.
<p>To frustrate the predecessor
attack, the tunnel selection keeps the peers selected in a strict order -
if A, B, and C are in a tunnel for a particular tunnel pool, the hop after A is always B, and the hop after
B is always C.
<p>Ordering is implemented by generating a random 32-byte key for each
tunnel pool at startup.
Peers should not be able to guess the ordering, or an attacker could
craft two router hashes far apart to maximize the chance of being at both
ends of a tunnel.
Peers are sorted by XOR distance of the
SHA256 Hash of (the peer's hash concatenated with the random key) from the random key
<pre>
p = peer hash
k = random key
d = XOR(H(p+k), k)
</pre>
<p>Because each tunnel pool uses a different random key, ordering is consistent
within a single pool but not between different pools.
New keys are generated at each router restart.
<h3 id="tunnel.request">Request delivery</h3>
<p>
A multi-hop tunnel is built using a single build message which is repeatedly
decrypted and forwarded.
In the terminology of
<a href="http://www-users.cs.umn.edu/~hopper/hashing_it_out.pdf">Hashing it out in Public</a>,
this is "non-interactive" telescopic tunnel building.
<p>This tunnel request preparation, delivery, and response method is
<a href="{{ site_url('docs/spec/tunnel_creation') }}">designed</a> to reduce the number of
predecessors exposed, cuts the number of messages transmitted, verifies proper
connectivity, and avoids the message counting attack of traditional telescopic
tunnel creation.
(This method, which sends messages to extend a tunnel through the already-established
part of the tunnel, is termed "interactive" telescopic tunnel building in
the "Hashing it out" paper.)
<p>The details of tunnel request and response messages, and their encryption,
<a href="{{ site_url('docs/spec/tunnel_creation') }}">are specified here</a>.
<p>Peers may reject tunnel creation requests for a variety of reasons, though
a series of four increasingly severe rejections are known: probabilistic rejection
(due to approaching the router's capacity, or in response to a flood of requests),
transient overload, bandwidth overload, and critical failure. When received,
those four are interpreted by the tunnel creator to help adjust their profile of
the router in question.
<p>
For more information on peer profiling, see the
<a href="{{ site_url('docs/how/peerselection') }}">Peer Profiling and Selection page</a>.
<h3 id="tunnel.pooling">Tunnel Pools</h3>
<p>To allow efficient operation, the router maintains a series of tunnel pools,
each managing a group of tunnels used for a specific purpose with their own
configuration. When a tunnel is needed for that purpose, the router selects one
out of the appropriate pool at random. Overall, there are two exploratory tunnel
pools - one inbound and one outbound - each using the router's default configuration.
In addition, there is a pair of pools for each local destination -
one inbound and one outbound tunnel pool. Those pools use the configuration specified
when the local destination connects to the router via <a href="{{ site_url('docs/spec/i2cp') }}">I2CP</a>, or the router's defaults if
not specified.</p>
<p>Each pool has within its configuration a few key settings, defining how many
tunnels to keep active, how many backup tunnels to maintain in case of failure,
how long the tunnels should be, whether those
lengths should be randomized, as
well as any of the other settings allowed when configuring individual tunnels.
Configuration options are specified on the <a href="i2cp.html">I2CP page</a>.
<h3 id="length">Tunnel Lengths and Defaults</h3>
<a href="{{ site_url('docs/how/tunnelrouting') }}#length">On the tunnel overview page</a>.
<h3 id="strategy">Anticipatory Build Strategy and Priority</h3>
<p>
Tunnel building is expensive, and tunnels expire a fixed time after they are built.
However, when a pool that runs out of tunnels, the Destination is essentially dead.
In addition, tunnel build success rate may vary greatly with both local and global
network conditions.
Therefore, it is important to maintain an anticipatory, adaptive build strategy
to ensure that new tunnels are successfully built before they are needed,
without building an excess of tunnels, building them too soon,
or consuming too much CPU or bandwidth creating and sending the encrypted build messages.
</p>
<p>
For each tuple {exploratory/client, in/out, length, length variance}
the router maintains statistics on the time required for a successful
tunnel build.
Using these statistics, it calculates how long before a tunnel's expiration
it should start attempting to build a replacement.
As the expiration time approaches without a successful replacement,
it starts multiple build attempts in parallel, and then
will increase the number of parallel attempts if necessary.
</p>
<p>
To cap bandwidth and CPU usage,
the router also limits the maximum number of build attempts outstanding
across all pools.
Critical builds (those for exploratory tunnels, and for pools that have
run out of tunnels) are prioritized.
</p>
<h2 id="tunnel.throttling">Tunnel Message Throttling</h2>
<p>Even though the tunnels within I2P bear a resemblance to a circuit switched
network, everything within I2P is strictly message based - tunnels are merely
accounting tricks to help organize the delivery of messages. No assumptions are
made regarding reliability or ordering of messages, and retransmissions are left
to higher levels (e.g. I2P's client layer streaming library). This allows I2P
to take advantage of throttling techniques available to both packet switched and
circuit switched networks. For instance, each router may keep track of the
moving average of how much data each tunnel is using, combine that with all of
the averages used by other tunnels the router is participating in, and be able
to accept or reject additional tunnel participation requests based on its
capacity and utilization. On the other hand, each router can simply drop
messages that are beyond its capacity, exploiting the research used on the
normal Internet.</p>
<p>
In the current implementation, routers implement a
weighted random early discard (WRED) strategy.
For all participating routers (internal participant, inbound gateway, and outbound endpoint),
the router will start randomly dropping a portion of messages as the
bandwidth limits are approached.
As traffic gets closer to, or exceeds, the limits, more messages are dropped.
For an internal participant, all messages are fragmented and padded and therefore are the same size.
At the inbound gateway and outbound endpoint, however, the dropping decision is made
on the full (coalesced) message, and the message size is taken into account.
Larger messages are more likely to be dropped.
Also, messages are more likely to be dropped at the outbound endpoint than the inbound gateway,
as those messages are not as "far along" in their journey and thus the network cost of
dropping those messages is lower.
</p>
<h2 id="future">Future Work</h3>
<h3 id="tunnel.mixing">Mixing/batching</h3>
<p>What strategies could be used at the gateway and at each hop for delaying,
reordering, rerouting, or padding messages? To what extent should this be done
automatically, how much should be configured as a per tunnel or per hop setting,
and how should the tunnel's creator (and in turn, user) control this operation?
All of this is left as unknown, to be worked out for a distant future release.
<h3>Padding</h3>
<p>The padding strategies can be used on a variety of levels, addressing the
exposure of message size information to different adversaries.
The current fixed tunnel message size is 1024 bytes. Within this however, the fragmented
messages themselves are not padded by the tunnel at all, though for end to end
messages, they may be padded as part of the garlic wrapping.</p>
<h3>WRED</h3>
<p>
WRED strategies have a significant impact on end-to-end performance,
and prevention of network congestion collapse.
The current WRED strategy should be carefully evaluated and improved.
</p>
{% endblock %}

View File

@@ -0,0 +1,534 @@
{% extends "global/layout.html" %}
{% block title %}Old Tunnel Implementation{% endblock %}
{% block content %}
<b>Note: Obsolete - NOT used! Replaced in 0.6.1.10 - see <a href="tunnel-alt.html">tunnel-alt.html</a> for the current implementation</b>
<br>
<pre>
1) <a href="#tunnel.overview">Tunnel overview</a>
2) <a href="#tunnel.operation">Tunnel operation</a>
2.1) <a href="#tunnel.preprocessing">Message preprocessing</a>
2.2) <a href="#tunnel.gateway">Gateway processing</a>
2.3) <a href="#tunnel.participant">Participant processing</a>
2.4) <a href="#tunnel.endpoint">Endpoint processing</a>
2.5) <a href="#tunnel.padding">Padding</a>
2.6) <a href="#tunnel.fragmentation">Tunnel fragmentation</a>
2.7) <a href="#tunnel.alternatives">Alternatives</a>
2.7.1) <a href="#tunnel.nochecksum">Don't use a checksum block</a>
2.7.2) <a href="#tunnel.reroute">Adjust tunnel processing midstream</a>
2.7.3) <a href="#tunnel.bidirectional">Use bidirectional tunnels</a>
2.7.4) <a href="#tunnel.smallerhashes">Use smaller hashes</a>
3) <a href="#tunnel.building">Tunnel building</a>
3.1) <a href="#tunnel.peerselection">Peer selection</a>
3.1.1) <a href="#tunnel.selection.exploratory">Exploratory tunnel peer selection</a>
3.1.2) <a href="#tunnel.selection.client">Client tunnel peer selection</a>
3.2) <a href="#tunnel.request">Request delivery</a>
3.3) <a href="#tunnel.pooling">Pooling</a>
3.4) <a href="#tunnel.building.alternatives">Alternatives</a>
3.4.1) <a href="#tunnel.building.telescoping">Telescopic building</a>
3.4.2) <a href="#tunnel.building.nonexploratory">Non-exploratory tunnels for management</a>
4) <a href="#tunnel.throttling">Tunnel throttling</a>
5) <a href="#tunnel.mixing">Mixing/batching</a>
</pre>
<h2>1) <a name="tunnel.overview">Tunnel overview</a></h2>
<p>Within I2P, messages are passed in one direction through a virtual
tunnel of peers, using whatever means are available to pass the
message on to the next hop. Messages arrive at the tunnel's
gateway, get bundled up for the path, and are forwarded on to the
next hop in the tunnel, which processes and verifies the validity
of the message and sends it on to the next hop, and so on, until
it reaches the tunnel endpoint. That endpoint takes the messages
bundled up by the gateway and forwards them as instructed - either
to another router, to another tunnel on another router, or locally.</p>
<p>Tunnels all work the same, but can be segmented into two different
groups - inbound tunnels and outbound tunnels. The inbound tunnels
have an untrusted gateway which passes messages down towards the
tunnel creator, which serves as the tunnel endpoint. For outbound
tunnels, the tunnel creator serves as the gateway, passing messages
out to the remote endpoint.</p>
<p>The tunnel's creator selects exactly which peers will participate
in the tunnel, and provides each with the necessary configuration
data. They may vary in length from 0 hops (where the gateway
is also the endpoint) to 7 hops (where there are 6 peers after
the gateway and before the endpoint). It is the intent to make
it hard for either participants or third parties to determine
the length of a tunnel, or even for colluding participants to
determine whether they are a part of the same tunnel at all
(barring the situation where colluding peers are next to each other
in the tunnel). Messages that have been corrupted are also dropped
as soon as possible, reducing network load.</p>
<p>Beyond their length, there are additional configurable parameters
for each tunnel that can be used, such as a throttle on the size or
frequency of messages delivered, how padding should be used, how
long a tunnel should be in operation, whether to inject chaff
messages, whether to use fragmentation, and what, if any, batching
strategies should be employed.</p>
<p>In practice, a series of tunnel pools are used for different
purposes - each local client destination has its own set of inbound
tunnels and outbound tunnels, configured to meet its anonymity and
performance needs. In addition, the router itself maintains a series
of pools for participating in the network database and for managing
the tunnels themselves.</p>
<p>I2P is an inherently packet switched network, even with these
tunnels, allowing it to take advantage of multiple tunnels running
in parallel, increasing resilience and balancing load. Outside of
the core I2P layer, there is an optional end to end streaming library
available for client applications, exposing TCP-esque operation,
including message reordering, retransmission, congestion control, etc.</p>
<h2>2) <a name="tunnel.operation">Tunnel operation</a></h2>
<p>Tunnel operation has four distinct processes, taken on by various
peers in the tunnel. First, the tunnel gateway accumulates a number
of tunnel messages and preprocesses them into something for tunnel
delivery. Next, that gateway encrypts that preprocessed data, then
forwards it to the first hop. That peer, and subsequent tunnel
participants, unwrap a layer of the encryption, verifying the
integrity of the message, then forward it on to the next peer.
Eventually, the message arrives at the endpoint where the messages
bundled by the gateway are split out again and forwarded on as
requested.</p>
<p>Tunnel IDs are 4 byte numbers used at each hop - participants know what
tunnel ID to listen for messages with and what tunnel ID they should be forwarded
on as to the next hop. Tunnels themselves are short lived (10 minutes at the
moment), but depending upon the tunnel's purpose, and though subsequent tunnels
may be built using the same sequence of peers, each hop's tunnel ID will change.</p>
<h3>2.1) <a name="tunnel.preprocessing">Message preprocessing</a></h3>
<p>When the gateway wants to deliver data through the tunnel, it first
gathers zero or more I2NP messages (no more than 32KB worth),
selects how much padding will be used, and decides how each I2NP
message should be handled by the tunnel endpoint, encoding that
data into the raw tunnel payload:</p>
<ul>
<li>2 byte unsigned integer specifying the # of padding bytes</li>
<li>that many random bytes</li>
<li>a series of zero or more { instructions, message } pairs</li>
</ul>
<p>The instructions are encoded as follows:</p>
<ul>
<li>1 byte value:<pre>
bits 0-1: delivery type
(0x0 = LOCAL, 0x01 = TUNNEL, 0x02 = ROUTER)
bit 2: delay included? (1 = true, 0 = false)
bit 3: fragmented? (1 = true, 0 = false)
bit 4: extended options? (1 = true, 0 = false)
bits 5-7: reserved</pre></li>
<li>if the delivery type was TUNNEL, a 4 byte tunnel ID</li>
<li>if the delivery type was TUNNEL or ROUTER, a 32 byte router hash</li>
<li>if the delay included flag is true, a 1 byte value:<pre>
bit 0: type (0 = strict, 1 = randomized)
bits 1-7: delay exponent (2^value minutes)</pre></li>
<li>if the fragmented flag is true, a 4 byte message ID, and a 1 byte value:<pre>
bits 0-6: fragment number
bit 7: is last? (1 = true, 0 = false)</pre></li>
<li>if the extended options flag is true:<pre>
= a 1 byte option size (in bytes)
= that many bytes</pre></li>
<li>2 byte size of the I2NP message</li>
</ul>
<p>The I2NP message is encoded in its standard form, and the
preprocessed payload must be padded to a multiple of 16 bytes.</p>
<h3>2.2) <a name="tunnel.gateway">Gateway processing</a></h3>
<p>After the preprocessing of messages into a padded payload, the gateway
encrypts the payload with the eight keys, building a checksum block so
that each peer can verify the integrity of the payload at any time, as
well as an end to end verification block for the tunnel endpoint to
verify the integrity of the checksum block. The specific details follow.</p>
<p>The encryption used is such that decryption
merely requires running over the data with AES in CBC mode, calculating the
SHA256 of a certain fixed portion of the message (bytes 16 through $size-144),
and searching for the first 16 bytes of that hash in the checksum block. There is a fixed number
of hops defined (8 peers) so that we can verify the message
without either leaking the position in the tunnel or having the message
continually "shrink" as layers are peeled off. For tunnels shorter than 8
hops, the tunnel creator will take the place of the excess hops, decrypting
with their keys (for outbound tunnels, this is done at the beginning, and for
inbound tunnels, the end).</p>
<p>The hard part in the encryption is building that entangled checksum block,
which requires essentially finding out what the hash of the payload will look
like at each step, randomly ordering those hashes, then building a matrix of
what each of those randomly ordered hashes will look like at each step. The
gateway itself must pretend that it is one of the peers within the checksum
block so that the first hop cannot tell that the previous hop was the gateway.
To visualize this a bit:</p>
<table border="1">
<tr><td colspan="2"></td>
<td><b>IV</b></td><td><b>Payload</b></td>
<td><b>eH[0]</b></td><td><b>eH[1]</b></td>
<td><b>eH[2]</b></td><td><b>eH[3]</b></td>
<td><b>eH[4]</b></td><td><b>eH[5]</b></td>
<td><b>eH[6]</b></td><td><b>eH[7]</b></td>
<td><b>V</b></td>
</tr>
<tr><td rowspan="2"><b>peer0</b><br /><font size="-2">key=K[0]</font></td><td><b>recv</b></td>
<td colspan="11"><hr /></td>
</tr>
<tr><td><b>send</b></td>
<td rowspan="2">IV[0]</td><td rowspan="2">P[0]</td>
<td rowspan="2"></td><td rowspan="2"></td><td rowspan="2"></td><td rowspan="2">H(P[0])</td>
<td rowspan="2"></td><td rowspan="2"></td><td rowspan="2"></td><td rowspan="2"></td>
<td rowspan="2">V[0]</td>
</tr>
<tr><td rowspan="2"><b>peer1</b><br /><font size="-2">key=K[1]</font></td><td><b>recv</b></td>
</tr>
<tr><td><b>send</b></td>
<td rowspan="2">IV[1]</td><td rowspan="2">P[1]</td>
<td rowspan="2"></td><td rowspan="2"></td><td rowspan="2"></td><td rowspan="2"></td>
<td rowspan="2"></td><td rowspan="2"></td><td rowspan="2">H(P[1])</td><td rowspan="2"></td>
<td rowspan="2">V[1]</td>
</tr>
<tr><td rowspan="2"><b>peer2</b><br /><font size="-2">key=K[2]</font></td><td><b>recv</b></td>
</tr>
<tr><td><b>send</b></td>
<td rowspan="2">IV[2]</td><td rowspan="2">P[2]</td>
<td rowspan="2"></td><td rowspan="2"></td><td rowspan="2"></td><td rowspan="2"></td>
<td rowspan="2"></td><td rowspan="2"></td><td rowspan="2"></td><td rowspan="2">H(P[2])</td>
<td rowspan="2">V[2]</td>
</tr>
<tr><td rowspan="2"><b>peer3</b><br /><font size="-2">key=K[3]</font></td><td><b>recv</b></td>
</tr>
<tr><td><b>send</b></td>
<td rowspan="2">IV[3]</td><td rowspan="2">P[3]</td>
<td rowspan="2">H(P[3])</td><td rowspan="2"></td><td rowspan="2"></td><td rowspan="2"></td>
<td rowspan="2"></td><td rowspan="2"></td><td rowspan="2"></td><td rowspan="2"></td>
<td rowspan="2">V[3]</td>
</tr>
<tr><td rowspan="2"><b>peer4</b><br /><font size="-2">key=K[4]</font></td><td><b>recv</b></td>
</tr>
<tr><td><b>send</b></td>
<td rowspan="2">IV[4]</td><td rowspan="2">P[4]</td>
<td rowspan="2"></td><td rowspan="2"></td><td rowspan="2">H(P[4])</td><td rowspan="2"></td>
<td rowspan="2"></td><td rowspan="2"></td><td rowspan="2"></td><td rowspan="2"></td>
<td rowspan="2">V[4]</td>
</tr>
<tr><td rowspan="2"><b>peer5</b><br /><font size="-2">key=K[5]</font></td><td><b>recv</b></td>
</tr>
<tr><td><b>send</b></td>
<td rowspan="2">IV[5]</td><td rowspan="2">P[5]</td>
<td rowspan="2"></td><td rowspan="2">H(P[5])</td><td rowspan="2"></td><td rowspan="2"></td>
<td rowspan="2"></td><td rowspan="2"></td><td rowspan="2"></td><td rowspan="2"></td>
<td rowspan="2">V[5]</td>
</tr>
<tr><td rowspan="2"><b>peer6</b><br /><font size="-2">key=K[6]</font></td><td><b>recv</b></td>
</tr>
<tr><td><b>send</b></td>
<td rowspan="2">IV[6]</td><td rowspan="2">P[6]</td>
<td rowspan="2"></td><td rowspan="2"></td><td rowspan="2"></td><td rowspan="2"></td>
<td rowspan="2"></td><td rowspan="2">H(P[6])</td><td rowspan="2"></td><td rowspan="2"></td>
<td rowspan="2">V[6]</td>
</tr>
<tr><td rowspan="2"><b>peer7</b><br /><font size="-2">key=K[7]</font></td><td><b>recv</b></td>
</tr>
<tr><td><b>send</b></td>
<td>IV[7]</td><td>P[7]</td>
<td></td><td></td><td></td><td></td><td>H(P[7])</td><td></td><td></td><td></td>
<td>V[7]</td>
</tr>
</table>
<p>In the above, P[7] is the same as the original data being passed through the
tunnel (the preprocessed messages), and V[7] is the first 16 bytes of the SHA256 of eH[0-7] as seen on
peer7 after decryption. For
cells in the matrix "higher up" than the hash, their value is derived by encrypting
the cell below it with the key for the peer below it, using the end of the column
to the left of it as the IV. For cells in the matrix "lower down" than the hash,
they're equal to the cell above them, decrypted by the current peer's key, using
the end of the previous encrypted block on that row.</p>
<p>With this randomized matrix of checksum blocks, each peer will be able to find
the hash of the payload, or if it is not there, know that the message is corrupt.
The entanglement by using CBC mode increases the difficulty in tagging the
checksum blocks themselves, but it is still possible for that tagging to go
briefly undetected if the columns after the tagged data have already been used
to check the payload at a peer. In any case, the tunnel endpoint (peer 7) knows
for certain whether any of the checksum blocks have been tagged, as that would
corrupt the verification block (V[7]).</p>
<p>The IV[0] is a random 16 byte value, and IV[i] is the first 16 bytes of
H(D(IV[i-1], K[i-1]) xor IV_WHITENER). We don't use the same IV along the path, as that would
allow trivial collusion, and we use the hash of the decrypted value to propagate
the IV so as to hamper key leakage. IV_WHITENER is a fixed 16 byte value.</p>
<p>When the gateway wants to send the message, they export the right row for the
peer who is the first hop (usually the peer1.recv row) and forward that entirely.</p>
<h3>2.3) <a name="tunnel.participant">Participant processing</a></h3>
<p>When a participant in a tunnel receives a message, they decrypt a layer with their
tunnel key using AES256 in CBC mode with the first 16 bytes as the IV. They then
calculate the hash of what they see as the payload (bytes 16 through $size-144) and
search for that first 16 bytes of that hash within the decrypted checksum block. If no match is found, the
message is discarded. Otherwise, the IV is updated by decrypting it, XORing that value
with the IV_WHITENER, and replacing it with the first 16 bytes of its hash. The
resulting message is then forwarded on to the next peer for processing.</p>
<p>To prevent replay attacks at the tunnel level, each participant keeps track of
the IVs received during the tunnel's lifetime, rejecting duplicates. The memory
usage required should be minor, as each tunnel has only a very short lifespan (10m
at the moment). A constant 100KBps through a tunnel with full 32KB messages would
give 1875 messages, requiring less than 30KB of memory. Gateways and endpoints
handle replay by tracking the message IDs and expirations on the I2NP messages
contained in the tunnel.</p>
<h3>2.4) <a name="tunnel.endpoint">Endpoint processing</a></h3>
<p>When a message reaches the tunnel endpoint, they decrypts and verifies it like
a normal participant. If the checksum block has a valid match, the endpoint then
computes the hash of the checksum block itself (as seen after decryption) and compares
that to the decrypted verification hash (the last 16 bytes). If that verification
hash does not match, the endpoint takes note of the tagging attempt by one of the
tunnel participants and perhaps discards the message.</p>
<p>At this point, the tunnel endpoint has the preprocessed data sent by the gateway,
which it may then parse out into the included I2NP messages and forwards them as
requested in their delivery instructions.</p>
<h3>2.5) <a name="tunnel.padding">Padding</a></h3>
<p>Several tunnel padding strategies are possible, each with their own merits:</p>
<ul>
<li>No padding</li>
<li>Padding to a random size</li>
<li>Padding to a fixed size</li>
<li>Padding to the closest KB</li>
<li>Padding to the closest exponential size (2^n bytes)</li>
</ul>
<p><i>Which to use? no padding is most efficient, random padding is what
we have now, fixed size would either be an extreme waste or force us to
implement fragmentation. Padding to the closest exponential size (ala Freenet)
seems promising. Perhaps we should gather some stats on the net as to what size
messages are, then see what costs and benefits would arise from different
strategies?</i></p>
<h3>2.6) <a name="tunnel.fragmentation">Tunnel fragmentation</a></h3>
<p>For various padding and mixing schemes, it may be useful from an anonymity
perspective to fragment a single I2NP message into multiple parts, each delivered
separately through different tunnel messages. The endpoint may or may not
support that fragmentation (discarding or hanging on to fragments as needed),
and handling fragmentation will not immediately be implemented.</p>
<h3>2.7) <a name="tunnel.alternatives">Alternatives</a></h3>
<h4>2.7.1) <a name="tunnel.nochecksum">Don't use a checksum block</a></h4>
<p>One alternative to the above process is to remove the checksum block
completely and replace the verification hash with a plain hash of the payload.
This would simplify processing at the tunnel gateway and save 144 bytes of
bandwidth at each hop. On the other hand, attackers within the tunnel could
trivially adjust the message size to one which is easily traceable by
colluding external observers in addition to later tunnel participants. The
corruption would also incur the waste of the entire bandwidth necessary to
pass on the message. Without the per-hop validation, it would also be possible
to consume excess network resources by building extremely long tunnels, or by
building loops into the tunnel.</p>
<h4>2.7.2) <a name="tunnel.reroute">Adjust tunnel processing midstream</a></h4>
<p>While the simple tunnel routing algorithm should be sufficient for most cases,
there are three alternatives that can be explored:</p>
<ul>
<li>Delay a message within a tunnel at an arbitrary hop for either a specified
amount of time or a randomized period. This could be achieved by replacing the
hash in the checksum block with e.g. the first 8 bytes of the hash, followed by
some delay instructions. Alternately, the instructions could tell the
participant to actually interpret the raw payload as it is, and either discard
the message or continue to forward it down the path (where it would be
interpreted by the endpoint as a chaff message). The later part of this would
require the gateway to adjust its encryption algorithm to produce the cleartext
payload on a different hop, but it shouldn't be much trouble.</li>
<li>Allow routers participating in a tunnel to remix the message before
forwarding it on - bouncing it through one of that peer's own outbound tunnels,
bearing instructions for delivery to the next hop. This could be used in either
a controlled manner (with en-route instructions like the delays above) or
probabilistically.</li>
<li>Implement code for the tunnel creator to redefine a peer's "next hop" in
the tunnel, allowing further dynamic redirection.</li>
</ul>
<h4>2.7.3) <a name="tunnel.bidirectional">Use bidirectional tunnels</a></h4>
<p>The current strategy of using two separate tunnels for inbound and outbound
communication is not the only technique available, and it does have anonymity
implications. On the positive side, by using separate tunnels it lessens the
traffic data exposed for analysis to participants in a tunnel - for instance,
peers in an outbound tunnel from a web browser would only see the traffic of
an HTTP GET, while the peers in an inbound tunnel would see the payload
delivered along the tunnel. With bidirectional tunnels, all participants would
have access to the fact that e.g. 1KB was sent in one direction, then 100KB
in the other. On the negative side, using unidirectional tunnels means that
there are two sets of peers which need to be profiled and accounted for, and
additional care must be taken to address the increased speed of predecessor
attacks. The tunnel pooling and building process outlined below should
minimize the worries of the predecessor attack, though if it were desired,
it wouldn't be much trouble to build both the inbound and outbound tunnels
along the same peers.</p>
<h4>2.7.4) <a name="tunnel.smallerhashes">Use smaller blocksize</a></h4>
<p>At the moment, our use of AES limits our block size to 16 bytes, which
in turn provides the minimum size for each of the checksum block columns.
If another algorithm was used with a smaller block size, or could otherwise
allow the safe building of the checksum block with smaller portions of the
hash, it might be worth exploring. The 16 bytes used now at each hop should
be more than sufficient.</p>
<h2>3) <a name="tunnel.building">Tunnel building</a></h2>
<p>When building a tunnel, the creator must send a request with the necessary
configuration data to each of the hops, then wait for the potential participant
to reply stating that they either agree or do not agree. These tunnel request
messages and their replies are garlic wrapped so that only the router who knows
the key can decrypt it, and the path taken in both directions is tunnel routed
as well. There are three important dimensions to keep in mind when producing
the tunnels: what peers are used (and where), how the requests are sent (and
replies received), and how they are maintained.</p>
<h3>3.1) <a name="tunnel.peerselection">Peer selection</a></h3>
<p>Beyond the two types of tunnels - inbound and outbound - there are two styles
of peer selection used for different tunnels - exploratory and client.
Exploratory tunnels are used for both network database maintenance and tunnel
maintenance, while client tunnels are used for end to end client messages. </p>
<h4>3.1.1) <a name="tunnel.selection.exploratory">Exploratory tunnel peer selection</a></h4>
<p>Exploratory tunnels are built out of a random selection of peers from a subset
of the network. The particular subset varies on the local router and on what their
tunnel routing needs are. In general, the exploratory tunnels are built out of
randomly selected peers who are in the peer's "not failing but active" profile
category. The secondary purpose of the tunnels, beyond merely tunnel routing,
is to find underutilized high capacity peers so that they can be promoted for
use in client tunnels.</p>
<h4>3.1.2) <a name="tunnel.selection.client">Client tunnel peer selection</a></h4>
<p>Client tunnels are built with a more stringent set of requirements - the local
router will select peers out of its "fast and high capacity" profile category so
that performance and reliability will meet the needs of the client application.
However, there are several important details beyond that basic selection that
should be adhered to, depending upon the client's anonymity needs.</p>
<p>For some clients who are worried about adversaries mounting a predecessor
attack, the tunnel selection can keep the peers selected in a strict order -
if A, B, and C are in a tunnel, the hop after A is always B, and the hop after
B is always C. A less strict ordering is also possible, assuring that while
the hop after A may be B, B may never be before A. Other configuration options
include the ability for just the inbound tunnel gateways and outbound tunnel
endpoints to be fixed, or rotated on an MTBF rate.</p>
<h3>3.2) <a name="tunnel.request">Request delivery</a></h3>
<p>As mentioned above, once the tunnel creator knows what peers should go into
a tunnel and in what order, the creator builds a series of tunnel request
messages, each containing the necessary information for that peer. For instance,
participating tunnels will be given the 4 byte tunnel ID on which they are to
receive messages, the 4 byte tunnel ID on which they are to send out the messages,
the 32 byte hash of the next hop's identity, and the 32 byte layer key used to
remove a layer from the tunnel. Of course, outbound tunnel endpoints are not
given any "next hop" or "next tunnel ID" information. Inbound tunnel gateways
are however given the 8 layer keys in the order they should be encrypted (as
described above). To allow replies, the request contains a random session tag
and a random session key with which the peer may garlic encrypt their decision,
as well as the tunnel to which that garlic should be sent. In addition to the
above information, various client specific options may be included, such as
what throttling to place on the tunnel, what padding or batch strategies to use,
etc.</p>
<p>After building all of the request messages, they are garlic wrapped for the
target router and sent out an exploratory tunnel. Upon receipt, that peer
determines whether they can or will participate, creating a reply message and
both garlic wrapping and tunnel routing the response with the supplied
information. Upon receipt of the reply at the tunnel creator, the tunnel is
considered valid on that hop (if accepted). Once all peers have accepted, the
tunnel is active.</p>
<h3>3.3) <a name="tunnel.pooling">Pooling</a></h3>
<p>To allow efficient operation, the router maintains a series of tunnel pools,
each managing a group of tunnels used for a specific purpose with their own
configuration. When a tunnel is needed for that purpose, the router selects one
out of the appropriate pool at random. Overall, there are two exploratory tunnel
pools - one inbound and one outbound - each using the router's exploration
defaults. In addition, there is a pair of pools for each local destination -
one inbound and one outbound tunnel. Those pools use the configuration specified
when the local destination connected to the router, or the router's defaults if
not specified.</p>
<p>Each pool has within its configuration a few key settings, defining how many
tunnels to keep active, how many backup tunnels to maintain in case of failure,
how frequently to test the tunnels, how long the tunnels should be, whether those
lengths should be randomized, how often replacement tunnels should be built, as
well as any of the other settings allowed when configuring individual tunnels.</p>
<h3>3.4) <a name="tunnel.building.alternatives">Alternatives</a></h3>
<h4>3.4.1) <a name="tunnel.building.telescoping">Telescopic building</a></h4>
<p>One question that may arise regarding the use of the exploratory tunnels for
sending and receiving tunnel creation messages is how that impacts the tunnel's
vulnerability to predecessor attacks. While the endpoints and gateways of
those tunnels will be randomly distributed across the network (perhaps even
including the tunnel creator in that set), another alternative is to use the
tunnel pathways themselves to pass along the request and response, as is done
in <a href="http://www.torproject.org/">TOR</a>. This, however, may lead to leaks
during tunnel creation, allowing peers to discover how many hops there are later
on in the tunnel by monitoring the timing or packet count as the tunnel is
built. Techniques could be used to minimize this issue, such as using each of
the hops as endpoints (per <a href="#tunnel.reroute">2.7.2</a>) for a random
number of messages before continuing on to build the next hop.</p>
<h4>3.4.2) <a name="tunnel.building.nonexploratory">Non-exploratory tunnels for management</a></h4>
<p>A second alternative to the tunnel building process is to give the router
an additional set of non-exploratory inbound and outbound pools, using those for
the tunnel request and response. Assuming the router has a well integrated view
of the network, this should not be necessary, but if the router was partitioned
in some way, using non-exploratory pools for tunnel management would reduce the
leakage of information about what peers are in the router's partition.</p>
<h2>4) <a name="tunnel.throttling">Tunnel throttling</a></h2>
<p>Even though the tunnels within I2P bear a resemblance to a circuit switched
network, everything within I2P is strictly message based - tunnels are merely
accounting tricks to help organize the delivery of messages. No assumptions are
made regarding reliability or ordering of messages, and retransmissions are left
to higher levels (e.g. I2P's client layer streaming library). This allows I2P
to take advantage of throttling techniques available to both packet switched and
circuit switched networks. For instance, each router may keep track of the
moving average of how much data each tunnel is using, combine that with all of
the averages used by other tunnels the router is participating in, and be able
to accept or reject additional tunnel participation requests based on its
capacity and utilization. On the other hand, each router can simply drop
messages that are beyond its capacity, exploiting the research used on the
normal Internet.</p>
<h2>5) <a name="tunnel.mixing">Mixing/batching</a></h2>
<p>What strategies should be used at the gateway and at each hop for delaying,
reordering, rerouting, or padding messages? To what extent should this be done
automatically, how much should be configured as a per tunnel or per hop setting,
and how should the tunnel's creator (and in turn, user) control this operation?
All of this is left as unknown, to be worked out for
<a href="http://www.i2p.net/roadmap#3.0">I2P 3.0</a></p>
{% endblock %}

View File

@@ -0,0 +1,138 @@
{% extends "global/layout.html" %}
{% block title %}Unidirectional Tunnels{% endblock %}
{% block content %}
<p>
Updated July 2011 for release 0.8.7
</p>
<h2>Overview</h2>
<p>
This page describes the origins and design of I2P's unidirectional tunnels.
For further infomrmation see:
<ul>
<li>
<a href="{{ site_url('docs/how/tunnelrouting') }}">tunnel overview page</a>
<li>
<a href="{{ site_url('docs/tunnels/implementation') }}">tunnel specification</a>
</li><li>
<a href="{{ site_url('docs/spec/tunnel_creation') }}">tunnel creation specification</a>
</li><li>
<a href="{{ site_url('docs/discussions/tunnel') }}">tunnel design discussion</a>
</li><li>
<a href="{{ site_url('docs/how/peerselection') }}">peer selection</a>
</li><li>
<a href="{{ url_for('meetings_show', id=125) }}">Meeting 125 (~13:12-13:30)</a>
</li>
</ul>
</p>
<h2>Review</h2>
<p>
While we aren't aware of any published research on the advantages of
unidirecdtional tunnels,
they appear to make it harder to detect a
request/response pattern, which is quite possible to detect over a
bidirectional tunnel.
Several apps and protocols, notably HTTP,
do transfer data in such manner. Having the traffic follow the same
route to its destination and back could make it easier for an
attacker who has only timing and traffic volume data to infer the path a
tunnel is taking.
Having the response come back along a different path arguably
makes it harder.
</p><p>
When dealing with
an internal adversary or most external adversaries, I2P's undirectional tunnels
expose half as much traffic data than would be exposed with bidirectional circuits
by simply looking at the flows themselves - an HTTP request and response would
follow the same path in Tor, while in I2P the packets making up the request
would go out through one or more outbound tunnels and the packets making up
the response would come back through one or more different inbound tunnels.
</p><p>
The strategy of using two separate tunnels for inbound and outbound
communication is not the only technique available, and it does have anonymity
implications. On the positive side, by using separate tunnels it lessens the
traffic data exposed for analysis to participants in a tunnel - for instance,
peers in an outbound tunnel from a web browser would only see the traffic of
an HTTP GET, while the peers in an inbound tunnel would see the payload
delivered along the tunnel. With bidirectional tunnels, all participants would
have access to the fact that e.g. 1KB was sent in one direction, then 100KB
in the other. On the negative side, using unidirectional tunnels means that
there are two sets of peers which need to be profiled and accounted for, and
additional care must be taken to address the increased speed of predecessor
attacks. The tunnel pooling and building process
(peer selection and ordering strategies)
should minimize the worries of the predecessor attack.
</p>
<h2>Anonymity</h2>
<p>
A recent
<a href="http://grothoff.org/christian/i2p.pdf">paper by Hermann and Grothoff</a>
declared that I2P's unidirectional tunnels "seems to be a bad design decision".
The paper's main point is that
deanonymizations on unidirectional tunnels take a longer time, which is an
advantage, but that an attacker can be more certain in the unidirectional case.
Therefore, the paper claims it isn't an advantage at all, but a disadvantage, at least
with long-living eepsites.
</p><p>
This conclusion is not fully supported by the paper. Unidirectional tunnels clearly
mitigate other attacks and it's not clear how to trade off the risk of the
attack in the paper
with attacks on a bidirectional tunnel architecture.
</p><p>
This conclusion is based on an arbitrary certainty vs. time weighting
(tradeoff) that may not be applicable in all cases. For
example, somebody could make a list of possible IPs then issue subpoenas to
each. Or the attacker could DDoS each in turn and via a simple
intersection attack see if the eepsite goes down or is slowed down. So close
may be good enough, or time may be more important.
The conclusion is based on a specific weighting of the importance of certainty
vs. time, and that weighting may be wrong, and it's definitely debatable,
especially in a real world with subpoenas, search warrants, and other methods
available for final confirmation.
</p><p>
A full analysis of the tradeoffs of unidirectional vs. bidirectional
tunnels is clearly outside the scope of the paper, and has not been done
elsewhere. For example, how does this attack compare to the numerous possible
timing attacks published about onion-routed networks? Clearly the authors have not
done that analysis, if it's even possible to do it
effectively.
</p><p>
Tor uses bidirectional tunnels and has had a lot of academic review. I2P
uses unidirectional tunnels and has had very little review. Does the lack of a
research paper defending unidirectional tunnels mean that it is a poor design
choice, or just that it needs more study? Timing attacks and
distributed attacks are difficult to defend against in both I2P and Tor. The
design intent (see references above) was that unidirectional tunnels are more
resistant to timing attacks. However, the paper presents a somewhat different type of timing
attack. Is this attack, innovative as it is, sufficient to label I2P's
tunnel architecture (and thus I2P as a whole) a "bad design", and by
implication clearly inferior to Tor, or is it just a design alternative that
clearly needs further investigation and analysis? There are several other reasons
to consider I2P currently inferior to Tor and other projects (small network
size, lack of funding, lack of review) but is unidirectional tunnels really a
reason?
</p><p>
In summary, "bad design decision" is apparently (since the paper does
not label bidirectional tunnels "bad") shorthand for "unidirectional
tunnels are unequivocally inferior to bidirectional tunnels", yet this
conclusion is not supported by the paper.
</p>
{% endblock %}