Files
i2p.www/i2p2www/pages/site/docs/how/elgamal-aes.html
2016-01-12 23:03:32 +00:00

414 lines
16 KiB
HTML

{% extends "global/layout.html" %}
{% block title %}{% trans %}ElGamal/AES + SessionTag Encryption{% endtrans %}{% endblock %}
{% block lastupdated %}{% trans %}January 2016{% endtrans %}{% endblock %}
{% block accuratefor %}0.9.24{% endblock %}
{% block content %}
<h2>{% trans %}Overview{% endtrans %}</h2>
<p>{% trans -%}
ElGamal/AES+SessionTags is used for end-to-end encryption.
{%- endtrans %}</p>
<p>{% trans -%}
As an unreliable, unordered, message based system, I2P uses a simple combination
of asymmetric and symmetric encryption algorithms to provide data confidentiality
and integrity to garlic messages. As a whole, the combination is referred
to as ElGamal/AES+SessionTags, but that is an excessively verbose way to describe
the use of 2048bit ElGamal, AES256, SHA256, and 32 byte nonces.
{%- endtrans %}</p>
<p>{% trans -%}
The first time a router wants to encrypt a garlic message to another router,
they encrypt the keying material for an AES256 session key with ElGamal and
append the AES256/CBC encrypted payload after that encrypted ElGamal block.
In addition to the encrypted payload, the AES encrypted section contains the
payload length, the SHA256 hash of the unencrypted payload, as well as a number
of "session tags" - random 32 byte nonces. The next time the sender wants
to encrypt a garlic message to another router, rather than ElGamal encrypt
a new session key they simply pick one of the previously delivered session
tags and AES encrypt the payload like before, using the session key used with
that session tag, prepended with the session tag itself. When a router receives
a garlic encrypted message, they check the first 32 bytes to see if it matches
an available session tag - if it does, they simply AES decrypt the message,
but if it does not, they ElGamal decrypt the first block.
{%- endtrans %}</p>
<p>{% trans -%}
Each session tag can be used only once so as to prevent internal adversaries
from unnecessarily correlating different messages as being between the same
routers. The sender of an ElGamal/AES+SessionTag encrypted message chooses
when and how many tags to deliver, prestocking the recipient with enough tags
to cover a volley of messages. Garlic messages may detect the successful tag
delivery by bundling a small additional message as a clove (a "delivery status
message") - when the garlic message arrives at the intended recipient and
is decrypted successfully, this small delivery status message is one of the
cloves exposed and has instructions for the recipient to send the clove back
to the original sender (through an inbound tunnel, of course). When the original
sender receives this delivery status message, they know that the session tags
bundled in the garlic message were successfully delivered.
{%- endtrans %}</p>
<p>{% trans -%}
Session tags themselves have a short lifetime, after which they are
discarded if not used. In addition, the quantity stored for each key is limited,
as are the number of keys themselves - if too many arrive, either new or old
messages may be dropped. The sender keeps track whether messages using session
tags are getting through, and if there isn't sufficient communication it may
drop the ones previously assumed to be properly delivered, reverting back
to the full expensive ElGamal encryption.
A session will continue to exist until all its tags are exhausted or expire.
{%- endtrans %}</p>
<p>{% trans -%}
Sessions are unidirectional. Tags are delivered from Alice to Bob,
and Alice then uses the tags, one by one, in subsequent messages to Bob.
{%- endtrans %}</p>
<p>{% trans -%}
Sessions may be established between Destinations, between Routers, or
between a Router and a Destination.
Each Router and Destination maintains its own Session Key Manager to
keep track of Session Keys and Session Tags.
Separate Session Key Managers prevents correlation of multiple Destinations
to each other or a Router by adversaries.
{%- endtrans %}</p>
<h2>{% trans %}Message Reception{% endtrans %}</h2>
<p>{% trans -%}
Each message received has one of two
the two possible conditions:</p>
{%- endtrans %}</p>
<ol>
<li>{% trans %}It is part of an existing session and contains a Session Tag and an AES encrypted block{% endtrans %}</li>
<li>{% trans %}It is for a new session and contains both ElGamal and AES encrypted blocks{% endtrans %}</li>
</ol>
<p>{% trans -%}
When a router receives a message, it will first assume it is from
an existing session and attempt to look up the Session Tag and decrypt the following data using AES.
If that fails, it will assume it is for a new session and attempt to
decrypt it using ElGamal.
{%- endtrans %}</p>
<h2 id="new">{% trans %}New Session Message Specification{% endtrans %}</h2>
<p>{% trans -%}
A New Session ElGamal Message contains two parts, an encrypted ElGamal block
and an encrypted AES block.
{%- endtrans %}</p>
<p>{% trans -%}
The encrypted message contains:
{%- endtrans %}</p>
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| |
+ +
| ElGamal Encrypted Block |
~ ~
| |
+ +----+----+----+----+----+----+
| | |
+----+----+ +
| |
+ +
| AES Encrypted Block |
~ ~
| |
+ +----+----+----+----+----+----+
| +
+----+----+
{% endhighlight %}
<h3>{% trans %}ElGamal Block{% endtrans %}</h3>
<p>{% trans -%}
The encrypted ElGamal Block is always 514 bytes long.
{%- endtrans %}</p>
<p>{% trans -%}
The unencrypted ElGamal data is 222 bytes long, containing:
{%- endtrans %}</p>
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| |
+ +
| Session Key |
+ +
| |
+ +
| |
+----+----+----+----+----+----+----+----+
| |
+ +
| Pre-IV |
+ +
| |
+ +
| |
+----+----+----+----+----+----+----+----+
+ +
| |
+ +
| 158 bytes random padding |
~ ~
| |
+ +----+----+
| |
+----+----+----+----+----+----+
{% endhighlight %}
<p>{% trans commonstructures=site_url('docs/spec/common-structures') -%}
The 32-byte
<a href="{{ commonstructures }}#type_SessionKey">Session Key</a>
is the identifier for the session.
The 32-byte Pre-IV will be used to generate the IV for the AES block that follows;
the IV is the first 16 bytes of the SHA-256 Hash of the Pre-IV.
{%- endtrans %}</p>
<p>{% trans cryptography=site_url('docs/how/cryptography') -%}
The 222 byte payload is encrypted
<a href="{{ cryptography }}#elgamal">using ElGamal</a>
and the encrypted block is 514 bytes long.
</p>
{%- endtrans %}</p>
<h3 id="aes">{% trans %}AES Block{% endtrans %}</h3>
<p>{% trans -%}
The unencrypted data in the AES block contains the following:
{%- endtrans %}</p>
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
|tag count| |
+----+----+ +
| |
+ +
| Session Tags |
~ ~
| |
+ +
| |
+ +----+----+----+----+----+----+
| | payload size | |
+----+----+----+----+----+----+ +
| |
+ +
| Payload Hash |
+ +
| |
+ +----+----+
| |flag| |
+----+----+----+----+----+----+----+ +
| |
+ +
| New Session Key (opt.) |
+ +
| |
+ +----+
| | |
+----+----+----+----+----+----+----+ +
| |
+ +
| Payload |
~ ~
| |
+ +----//---+----+
| | |
+----+----+----//---+----+ +
| Padding to 16 bytes |
+----+----+----+----+----+----+----+----+
{% endhighlight %}
<h4>Definition</h4>
{% highlight lang='dataspec' %}
tag count: {% trans commonstructures=site_url('docs/spec/common-structures') -%}
2-byte <a href="{{ commonstructures }}#type_Integer">Integer</a>, 0-200
{%- endtrans %}
Session Tags: {% trans commonstructures=site_url('docs/spec/common-structures') -%}
That many 32-byte <a href="{{ commonstructures }}#type_SessionTag">Session Tags</a>
{%- endtrans %}
payload size: {% trans commonstructures=site_url('docs/spec/common-structures') -%}
4-byte <a href="{{ commonstructures }}#type_Integer">Integer</a>
{%- endtrans %}
Payload Hash: {% trans commonstructures=site_url('docs/spec/common-structures') -%}
The 32-byte <a href="{{ commonstructures }}#type_Hash">SHA256 Hash</a> of the payload
{%- endtrans %}
flag: {% trans -%}
A one-byte value. Normally == 0. If == 0x01, a Session Key follows
{%- endtrans %}
New Session Key: {% trans commonstructures=site_url('docs/spec/common-structures') -%}
A 32-byte <a href="{{ commonstructures }}#type_SessionKey">Session Key</a>,
to replace the old key, and is only present if preceding flag is 0x01
{%- endtrans %}
Payload: {% trans %}the data{% endtrans %}
Padding: {% trans -%}
Random data to a multiple of 16 bytes for the total length.
May contain more than the minimum required padding.
{%- endtrans %}
{% endhighlight %}
{% trans %}Minimum length: 48 bytes{% endtrans %}
<p>{% trans cryptography=site_url('docs/how/cryptography') -%}
The data is then <a href="{{ cryptography }}">AES Encrypted</a>,
using the session key and IV (calculated from the pre-IV) from the ElGamal section.
The encrypted AES Block length is variable but is always a multiple of 16 bytes.
</p>
{%- endtrans %}</p>
<h4>{% trans %}Notes{% endtrans %}</h4>
<ul>
<li>{% trans i2np=site_url('docs/protocol/i2np') -%}
Actual max payload length, and max block length, is less than 64 KB; see the <a href="{{ i2np }}">I2NP Overview</a>.
{%- endtrans %}</li>
<li>{% trans %}New Session Key is currently unused and is never present.{% endtrans %}</li>
</ul>
<h2 id="existing">{% trans %}Existing Session Message Specification{% endtrans %}</h2>
<p>{% trans -%}
The session tags delivered successfully are remembered for a
brief period (15 minutes currently) until they are used or discarded.
A tag is used by packaging one in an Existing Session Message that
contains only an AES encrypted block, and is not preceded by an
ElGamal block.
{%- endtrans %}</p>
<p>{% trans -%}
The existing session message is
as follows:
{%- endtrans %}</p>
{% highlight lang='dataspec' %}
+----+----+----+----+----+----+----+----+
| |
+ +
| Session Tag |
+ +
| |
+ +
| |
+----+----+----+----+----+----+----+----+
| |
+ +
| AES Encrypted Block |
~ ~
| |
+ +
| |
+----+----+----+----+----+----+----+----+
{% endhighlight %}
<h4>Definition</h4>
{% highlight lang='dataspec' %}
Session Tag: {% trans commonstructures=site_url('docs/spec/common-structures') -%}
A 32-byte <a href="{{ commonstructures }}#type_SessionTag">Session Tag</a>
previously delivered in an AES block
{%- endtrans %}
AES Encrypyted Block: {% trans %}As specified <a href="#aes">above</a>.{% endtrans %}
{% endhighlight %}
<p>{% trans -%}
The session tag also serves as
the pre-IV. The IV is the first 16 bytes of the SHA-256 Hash of the sessionTag.
{%- endtrans %}</p>
<p>{% trans -%}
To decode a message from an existing session, a router looks up the Session Tag to find an
associated Session Key. If the Session Tag is found, the AES block is decrypted using the associated Session Key.
If the tag is not found, the message is assumed to be a <a href="#new">New Session Message</a>.
{%- endtrans %}</p>
<h2 id="config">{% trans %}Session Tag Configuration Options{% endtrans %}</h2>
<p>{% trans i2cp=site_url('docs/protocol/i2cp'),
i2cpspec=site_url('docs/spec/i2cp') -%}
As of release 0.9.2, the client may configure the default number of Session Tags to send
and the low tag threshold for the current session.
For brief streaming connections or datagrams, these options may be used to significantly reduce bandwidth.
See the <a href="{{ i2cp }}#options">I2CP options specification</a> for details.
The session settings may also be overridden on a per-message basis.
See the <a href="{{ i2cpspec }}#msg_SendMessageExpires">I2CP Send Message Expires specification</a> for details.
{%- endtrans %}</p>
<h2 id="future">{% trans %}Future Work{% endtrans %}</h2>
<p>{% trans -%}
There are many possible areas to tune the Session Key Manager's algorithms;
some may interact with the streaming library behavior, or have significant
impact on overall performance.
{%- endtrans %}</p>
<ul>
<li>{% trans -%}
The number of tags delivered could depend on message size, keeping in mind
the eventual padding to 1KB at the tunnel message layer.
{%- endtrans %}</li>
<li>{% trans -%}
Clients could send an estimate of session lifetime to the router, as an advisory
on the number of tags required.
{%- endtrans %}</li>
<li>{% trans -%}
Delivery of too few tags causes the router to fall back to an expensive ElGamal encryption.
{%- endtrans %}</li>
<li>{% trans -%}
The router may assume delivery of Session Tags, or await acknowledgement before using them;
there are tradeoffs for each strategy.
{%- endtrans %}</li>
<li>{% trans -%}
For very brief messages, almost the full 222 bytes of the pre-IV and padding fields in the ElGamal block
could be used for the entire message, instead of establishing a session.
{%- endtrans %}</li>
<li>{% trans -%}
Evaluate padding strategy; currently we pad to a minimum of 128 bytes.
Would be better to add a few tags to small messages than pad.
{%- endtrans %}</li>
<li>{% trans -%}
Perhaps things could be more efficient if the Session Tag system was bidirectional,
so tags delivered in the 'forward' path could be used in the 'reverse' path,
thus avoiding ElGamal in the initial response.
The router currently plays some tricks like this when sending
tunnel test messages to itself.
{%- endtrans %}</li>
<li>{% trans futureperf=site_url('about/performance/future') -%}
Change from Session Tags to
<a href="{{ futureperf }}#prng">a synchronized PRNG</a>.
{%- endtrans %}</li>
<li>{% trans tunnelmessage=site_url('docs/spec/tunnel-message') -%}
Several of these ideas may require a new I2NP message type, or
set a flag in the
<a href="{{ tunnelmessage }}#struct_TunnelMessageDeliveryInstructions">Delivery Instructions</a>,
or set a magic number in the first few bytes of the Session Key field
and accept a small risk of the random Session Key matching the magic number.
{%- endtrans %}</li>
</ul>
{% endblock %}