162 lines
8.0 KiB
HTML
162 lines
8.0 KiB
HTML
![]() |
<code>$Id: tunnel-alt.html,v 1.9 2005/07/27 14:04:07 jrandom Exp $</code>
|
||
|
<pre>
|
||
|
1) <a href="#tunnelCreate.overview">Tunnel creation</a>
|
||
|
1.1) <a href="#tunnelCreate.requestRecord">Tunnel creation request record</a>
|
||
|
1.2) <a href="#tunnelCreate.hopProcessing">Hop processing</a>
|
||
|
1.3) <a href="#tunnelCreate.replyRecord">Tunnel creation reply record</a>
|
||
|
1.4) <a href="#tunnelCreate.requestPreparation">Request preparation</a>
|
||
|
1.5) <a href="#tunnelCreate.requestDelivery">Request delivery</a>
|
||
|
1.6) <a href="#tunnelCreate.endpointHandling">Endpoint handling</a>
|
||
|
1.7) <a href="#tunnelCreate.replyProcessing">Reply processing</a>
|
||
|
2) <a href="#tunnelCreate.notes">Notes</a>
|
||
|
</pre>
|
||
|
|
||
|
<h2 id="tunnelCreate.overview">1) Tunnel creation encryption:</h2>
|
||
|
|
||
|
<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 fixed number of records (8) - one for each potential peer in
|
||
|
the tunnel. Individual records are asymmetrically encrypted to be
|
||
|
read only by a specific peer along the path, while an additional
|
||
|
symmetric layer of encryption is added at each hop so as to expose
|
||
|
the asymmetrically encrypted record only at the appropriate time.</p>
|
||
|
|
||
|
<h3 id="tunnelCreate.requestRecord">1.1) Tunnel creation request record</h3>
|
||
|
|
||
|
<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: reply IV
|
||
|
byte 184: flags
|
||
|
bytes 185-188: request time (in hours since the epoch)
|
||
|
bytes 189-222: 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.</p>
|
||
|
|
||
|
<p>The flags field currently has two bits defined:</p><pre>
|
||
|
bit 0: if set, allow messages from anyone
|
||
|
bit 1: if set, allow messages to anyone, and send the reply to the
|
||
|
specified next hop in a tunnel message</pre>
|
||
|
|
||
|
<p>That cleartext record is ElGamal 2048 encrypted with the hop's
|
||
|
public encryption key and formatted into a 528 byte record:</p><pre>
|
||
|
bytes 0-15: SHA-256-128 of the current hop's router identity
|
||
|
bytes 16-527: ElGamal-2048 encrypted request record</pre>
|
||
|
|
||
|
<p>Since the cleartext uses the full field, there is no need for
|
||
|
additional padding beyond <code>SHA256(cleartext) + cleartext</code>.</p>
|
||
|
|
||
|
<h3 id="tunnelCreate.hopProcessing">1.2) Hop processing</h3>
|
||
|
|
||
|
<p>When a hop receives a TunnelBuildMessage, it looks through the 8
|
||
|
records contained within it for one starting with their own identity
|
||
|
hash (trimmed to 8 bytes). It then decryptes 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 and making sure the request
|
||
|
time is within an hour of current. 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 AES-256/CBC
|
||
|
encrypted with the included reply key and IV (though each is
|
||
|
encrypted separately, rather than chained across records).</p>
|
||
|
|
||
|
<h3 id="tunnelCreate.replyRecord">1.3) Tunnel creation reply record</h3>
|
||
|
|
||
|
<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. The reply is encrypted with the AES session
|
||
|
key delivered to it in the encrypted block, padded with random data
|
||
|
until it reaches the full record size:</p><pre>
|
||
|
AES-256-CBC(SHA-256(padding+status) + padding + status, key, IV)</pre>
|
||
|
|
||
|
<h3 id="tunnelCreate.requestPreparation">1.4) Request preparation</h3>
|
||
|
|
||
|
<p>When building a new request, all of the records must first be
|
||
|
built and asymmetrically encrypted. Each record should then be
|
||
|
decrypted with the reply keys and IVs of the hops earlier in the
|
||
|
path. 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">1.5) Request 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
|
||
|
(and during startup, when no outbound tunnel exists yet, a fake 0
|
||
|
hop outbound tunnel is used).</p>
|
||
|
|
||
|
<h3 id="tunnelCreate.endpointHandling">1.6) Endpoint handling</h3>
|
||
|
|
||
|
<p>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 TunnelBuildReplyMessage and delivers it to the
|
||
|
reply tunnel specified within the request record. That reply tunnel
|
||
|
forwards the reply records down to the tunnel creator for
|
||
|
processing, as below.</p>
|
||
|
|
||
|
<p>When the request reaches the inbound endpoint (also known as the
|
||
|
tunnel creator), the router processes each of the replies, as below.</p>
|
||
|
|
||
|
<h3 id="tunnelCreate.replyProcessing">1.7) Reply 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>
|
||
|
|
||
|
<h2 id="tunnelCreate.notes">2) Notes</h2>
|
||
|
<ul>
|
||
|
<li>This 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 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 later replaced by a hashcash function of up to 2^64
|
||
|
cost. This will not immediately be pursued, however.</li>
|
||
|
<li>This 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>
|
||
|
<li>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://dev.i2p.net/pipermail/i2p/2005-October/001073.html">Summary</a></li>
|
||
|
<li><a href="http://dev.i2p.net/pipermail/i2p/2005-October/001064.html">Reasoning</a></li>
|
||
|
</ul></li>
|
||
|
</ul>
|