Files
i2p.i2p-bote/doc/techdoc.txt
2011-03-03 03:38:55 +00:00

694 lines
44 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
I2P-Bote Technical Documentation
--------------------------------
1) Introduction
I2P-Bote is a serverless pseudonymous email exchange service for the I2P network. Emails are stored
encrypted in a Kademlia DHT formed by all I2P-bote nodes.
There is a web interface that lets the user send/read email and change settings.
An SMTP/POP interface to use with an email client is planned for the future.
Email can be sent through a number of other nodes (relays) for increased anonymity, or directly to a set
of storage nodes for faster delivery. Receiving email through relays is not yet implemented.
All nodes are created equal. There are no "supernodes" or designated relay/storage nodes.
Everybody acts as a potential relay and storage node. At some point in the
future, the maximum amount of disk space used for relayed/stored email packets will be user-configurable.
Before an email is sent, it is broken up into packets 30 kb or smaller and encrypted with the recipient's
public key. The packets are then stored in the DHT.
Email packets are stored redundantly in a Kademlia DHT (distributed hash table).
Stored email packets and relay packets are kept for at least 100 days, during which the recipient can
download them. If a node runs out of email storage space, and there are no old packets that can be deleted,
the node refuses storage requests.
Below is a diagram of how an email packet is routed from a sender to a recipient:
.-------. .-------. .--------.
| Relay | ----> | Relay | ----> | Storer | --------------------.
_ `-------' `-------' `--------' `\
/` |
/ |
.--------. / .-------. .-------. .--------. |
| Sender | -----> | Relay | ---> | Relay | ----> | Storer | -------------. |
`--------' \ `-------' `-------' `--------' `\ |
\ | |
_\/ | |
.-------. .-------. .--------. | |
| Relay | ----> | Relay | ----> | Storer | ------. | |
`-------' `-------' `--------' `\ | |
| | |
V V V
.--------------- Kademlia DHT -------------------------.
| .---------. |
| .---------. | Storage | |
| | Storage | .---------. | Node | |
| | Node | | Storage | `---------' |
| `---------' | Node | |
| `---------' .---------. |
| .---------. .---------. | Storage | |
| | Storage | | Storage | .---------. | Node | |
| | Node | | Node | | Storage | `---------' |
| `---------' `---------' | Node | |
| `---------' |
`------------------------------------------------------'
| | |
.-------. .-------. .---------. _' | |
| Relay | <----- | Relay | <---- | Fetcher | <---' | |
/ `-------' `-------' `---------' | |
/ | |
\/_ | |
.-----------. .-------. .-------. .---------. _' |
| Recipient | <---- | Relay | <--- | Relay | <---- | Fetcher | <----------' |
`-----------' _ `-------' `-------' `---------' |
|\ |
\ |
\ .-------. .-------. .---------. _'
| Relay | <----- | Relay | <---- | Fetcher | <-----------------'
`-------' `-------' `---------'
The number of relays for sending or retrieving an email is user-configurable.
For higher performance (but reduced anonymity), it is possible to use no relays and no storers/fetchers,
i.e. sender and recipient talk to the storage nodes directly. If both sender and recipient chose not to use
relays, the diagram looks like this:
.--------.
| Sender | ----------------------------.
`--------' `\
|
V
.--------------- Kademlia DHT -------------------------.
| .---------. |
| .---------. | Storage | |
| | Storage | .---------. | Node | |
| | Node | | Storage | `---------' |
| `---------' | Node | |
| `---------' .---------. |
| .---------. .---------. | Storage | |
| | Storage | | Storage | .---------. | Node | |
| | Node | | Node | | Storage | `---------' |
| `---------' `---------' | Node | |
| `---------' |
`------------------------------------------------------'
|
|
.-----------. _'
| Recipient | <-------------------------'
`-----------'
I2P-Bote uses base64 strings for addresses. They are called email destinations and can be between 86 and 512
characters long, depending on the type of encryption the user chooses.
The code is licensed under the GPL. The author can be reached via I2PMail at HungryHobo@mail.i2p,
or via I2P-Bote at:
hobo37SEJsEMfQHwcpVlvEgnrERGFz34GC1yjVyuRvl1QHnTi0UAoOtrLP~qkFY0oL59BBqj5sCep0RA8I5G8n
- either in German or English.
2. Kademlia
The Kademlia implementation used by I2P-Bote differs from standard Kademlia in several ways:
* Items can be deleted from the DHT
* No caching of DHT items because they are only retrieved once and then deleted
* I2P-Bote uses sibling lists (s-buckets) as suggested in the S/Kademlia paper
There are two types of data that is stored in the DHT: Email Packets and Index Packets. A third data type
will be added for the address directory when it is implemented.
Index packets contain the DHT keys of one or more email packets. The DHT key of an index packet is the
SHA-256 hash of the Email Destination the email packets are destined for.
To check for new email for a given Email Destination, I2P-Bote first queries the DHT for index packets for that
Email Destination, then queries the DHT for all email packet keys in the index packets. When a complete set of
email packets has been received, the email is reconstructed and placed in the inbox.
To delete an email packet, or an entry in an index packet, the delete request must contain the correct
verification code (the delete verification hash). The verification code is the SHA-256 hash of another block of
data called the delete authorization which is encrypted in the email packet. This means no third party can delete
the packet until the recipient has decrypted the packet and sent out a delete request containing the delete
authorization.
Note that once a delete request for a given email packet has been received by a node that is storing the
email packet, the node knows the delete authorization code and can propagate the delete request to other nodes
that don't know yet that the packet has been deleted.
To delete an index packet entry, a delete verification hash is required as well. It is the same hash as the one
for the email packet which the index packet entry points to.
3. Packet Types
As of release 0.2.5, the protocol version is 4. It is incompatible to earlier versions.
Version 4 clients will talk to higher versions. There will be at least one more protocol version at some point
in the future; this version will be backwards compatible to version 4.
All packets start with one byte for the packet type, followed by one byte for the packet version.
Strings in packets are UTF8 encoded.
3.1. Data Packets
These are always sent wrapped in a Communication Packet (see 3.1).
E denotes an encrypted field.
Supported encryption and signature algorithms:
ALG=1: ElGamal-2048 / DSA-1024 / AES-256 / SHA-256 (same as the I2P router uses)
ALG=2: ECDH-256 / ECDSA-256 / AES-256 / SHA-256
ALG=3: ECDH-521 / ECDSA-521 / AES-256 / SHA-256
Packet Type | Field | Data Type | Description
--------------------+-------+------------+------------------------------------------------------------------
Email Packet, | | | An email or email fragment, one recipient. Part of
encrypted | | | the packet is encrypted with the recipient's key.
| TYPE | 1 byte | Value = 'E'
| VER | 1 byte | Protocol version
| KEY | 32 bytes | DHT key of the packet, SHA-256 hash of LEN+DATA
| TIM | 4 bytes | The time the packet was stored on a storage node
| DV | 32 bytes | Delete verification hash, SHA-256 hash of DA
| ALG | 1 byte | Encryption algorithm used
| LEN | 2 bytes | Length of DA+DATA together
| DA | 32 bytes E | Delete authorization key, randomly generated
| DATA | byte[] E | An Unencrypted Email Packet
--------------------+-------+------------+------------------------------------------------------------------
Email Packet, | | | Storage format for the Incomplete Email Folder
unencrypted | | |
| TYPE | 1 byte | Value = 'U'
| VER | 1 byte | Protocol version
| MSID | 32 bytes | Message ID in binary format
| DA | 32 bytes | Delete authorization key, randomly generated
| FRID | 2 bytes | Fragment Index of this packet (0..NFR-1)
| NFR | 2 bytes | Number of fragments in the email
| MLEN | 2 bytes | Length of the MSG field
| MSG | byte[] | email content (MLEN bytes)
--------------------+-------+------------+------------------------------------------------------------------
Index Packet | | | Contains the DHT keys of one or more Email Packets, a
| | | Delete Verification Hash, and time stamp for each DHT key.
| TYPE | 1 byte | Value = 'I'
| VER | 1 byte | Protocol version
| DH | 32 bytes | SHA-256 hash of the recipient's email destination
| NP | 4 bytes | Number of entries in the packet
| KEY1 | 32 bytes | DHT key of the first Email Packet
| DV1 | 32 bytes | Delete verification hash for KEY1
| | | (SHA-256 hash of DA in the email packet)
| TIM1 | 4 bytes | The time the key KEY1 was added
| KEY2 | 32 bytes | DHT key of the second Email Packet
| DV2 | 32 bytes | Delete verification hash for KEY2
| | | (SHA-256 hash of DA in the email packet)
| TIM2 | 4 bytes | The time the key KEY2 was added
| ... | ... | ...
| KEYn | 32 bytes | DHT key of the n-th Email Packet
| DVn | 32 bytes | Delete verification hash for KEYn
| | | (SHA-256 hash of DA in the email packet)
| TIMn | 4 bytes | The time the key KEYn was added
--------------------+-------+------------+------------------------------------------------------------------
Deletion Info | | | Contains information about deleted DHT items, which can be
Packet | | | Email Packets or Index Packet entries.
| TYPE | 1 byte | Value = 'T'
| VER | 1 byte | Protocol version
| NP | 4 bytes | Number of entries in the packet
| KEY1 | 32 bytes | First DHT key
| DA1 | 32 bytes | Delete Authorization for KEY1
| TIM1 | 4 bytes | The time the key KEY1 was added
| KEY2 | 32 bytes | Second DHT key
| DA2 | 32 bytes | Delete Authorization for KEY2
| TIM2 | 4 bytes | The time the key KEY2 was added
| ... | ... | ...
| KEYn | 32 bytes | The n-th DHT key
| DAn | 32 bytes | Delete Authorization for KEYn
| TIMn | 4 bytes | The time the key KEYn was added
--------------------+-------+------------+------------------------------------------------------------------
Peer List | | | Response to a Find Close Peers Request or a Peer List Request
| TYPE | 1 byte | Value = 'P'
| VER | 1 byte | Protocol version
| NUMP | 2 bytes | Number of peers in the list
| P1 | 384 bytes | Destination key
| P2 | 384 bytes | Destination key
| ... | ... | ...
| Pn | 384 bytes | Destination key
--------------------+-------+------------+------------------------------------------------------------------
Directory Entry | | | A name/Email Destination mapping
| TYPE | 1 byte | Value = 'M'
| VER | 1 byte | Protocol version
| NLEN | 2 bytes | Length of the NAME field, max 50
| NAME | byte[] | Name in UTF8
| DLEN | 2 bytes | Length of the DEST field
| DEST | byte[] | Email destination, 8 bit encoded (not base64)
| PLEN | 2 bytes | Length of PIC, max 25,000
| PIC | byte[] | User picture in a browser-compatible format (JPG, PNG, GIF)
| TLEN | 2 bytes | Length of the TEXT field, max 2000
| TEXT | byte[] | User defined text in UTF8
--------------------+-------+------------+------------------------------------------------------------------
3.2. Communication Packets
Communication packets are used for sending data between two I2P-Bote nodes.
They contain a data packet, see 3.1.
All Communication Packets start with a four-byte prefix, followed by one byte for the packet type,
one byte for the packet version, and a 32-byte Correlation ID.
Packet Type | Field | Data Type | Description
--------------------+-------+------------+------------------------------------------------------------------
Relay Request | | | A packet that tells the receiver to communicate with a peer,
| | | or peers, on behalf of the sender. It contains an I2P
| | | destination, a delay time, and a Communication Packet.
| PFX | 4 bytes | Packet prefix, must be 0x6D 0x30 0x52 0xE9
| TYPE | 1 byte | Value = 'R'
| VER | 1 byte | Protocol version
| CID | 32 bytes | Correlation ID, used for responses
| HLEN | 2 bytes | HashCash length
| HK | byte[] | HashCash token (HLEN bytes)
| DLY | 4 bytes | Delay in seconds before sending
| NEXT | 384 bytes | Destination to forward the packet to
| RET | Ret. Chain | An empty or non-empty Return Chain
| DLEN | 2 bytes | Length of the DATA field in bytes
| DATA | byte[] E | Encrypted with the recipient's public key. Can contain another
| | | Relay Request, a Store Request, or a Deletion Query.
| PAD | byte[] | Optional padding
--------------------+-------+------------+------------------------------------------------------------------
Relay Return | | | Contains a Return Chain and a payload. The final destination
Request | | | is unknown to the sender or any of the hops.
(not implemented) | | | Used for responding to a relayed data packet.
| PFX | 4 bytes | Packet prefix, must be 0x6D 0x30 0x52 0xE9
| TYPE | 1 byte | Value = 'K'
| VER | 1 byte | Protocol version
| CID | 32 bytes | Correlation ID, used for confirmation between two relay peers.
| | | A new correlation ID is set at every hop.
| RET | Ret. Chain | A non-empty Return Chain
| DLEN | 2 bytes | Length of the DATA field in bytes
| DATA | byte[] E | The payload. AES256-encrypted at every hop in the return chain.
--------------------+-------+------------+------------------------------------------------------------------
Return Chain | | | Not a packet itself, but part of a Relay (Return) Request
| RL1 | 2 bytes | Length of RET1. Zero means an empty return chain, nothing follows.
| RET1 | RL1 bytes | Hop 1 in the return chain. Contains a zero byte, followed by the
| | | hop's I2P destination and an AES key to encrypt the payload with.
| RL2 | 2 bytes E| Length of RET2.
| RET2 | RL2 bytes E| Hop 2 in the return chain. Contains a zero byte, followed by the
| | | hop's I2P destination and an AES key to encrypt the payload with.
| | | This field is encrypted with the PK of hop 2.
| RL3 | 2 bytes E| Length of RET3.
| RET3 | RL3 bytes E| Hop 3 in the return chain. Contains a zero byte, followed by the
| | | hop's I2P destination and an AES key to encrypt the payload with.
| | | This field is encrypted with the PKs of hops 3 and 2.
| ... | ... | ...
| RLn | 2 bytes E| Length of RETn.
| RETn | RLn bytes E| Last hop in the return chain. Contains a zero byte, followed by the
| | | hop's I2P destination and an AES key to encrypt the payload with.
| | | This field is encrypted with the PKs of hops n...2.
| RLn+1 | 2 bytes E| Length of RETn+1.
| RETn+1| RLn+1 byt E| Number of hops (>0) followed by all AES256 keys (one per hop)
| RLn+2 | 2 bytes | Value=0 to indicate this is the end of the return chain
--------------------+-------+------------+------------------------------------------------------------------
Fetch Request | | | Request to a chain end point to retrieve an Index Packet or
| | | Email Packet.
| PFX | 4 bytes | Packet prefix, must be 0x6D 0x30 0x52 0xE9
| TYPE | 1 byte | Value = 'F'
| VER | 1 byte | Protocol version
| CID | 32 bytes | Correlation ID, used for responses
| DTYP | 1 byte | Type of data to retrieve
| KEY | 32 bytes | DHT key to look up
| KPR | 384 bytes | Email keypair of recipient
| RLEN | 2 bytes | Length of the RET field
| RET | byte[] | Relay packet, contains the return chain (RLEN bytes)
--------------------+-------+------------+------------------------------------------------------------------
Response Packet | | | Response to a Retrieve Request, Fetch Request,
| | | Find Close Peers Request, or a Peer List Request
| PFX | 4 bytes | Packet prefix, must be 0x6D 0x30 0x52 0xE9
| TYPE | 1 byte | Value = 'N'
| VER | 1 byte | Protocol version
| CID | 32 bytes | Correlation ID of the request packet
| STA | 1 byte | Status code:
| | | 0 = OK
| | | 1 = General error
| | | 2 = No data found
| | | 3 = Invalid packet
| | | 4 = Invalid HashCash
| | | 5 = Not enough HashCash provided
| | | 6 = No disk space left
| DLEN | 2 bytes | Length of the DATA field; can be 0 if no payload
| DATA | byte[] | A Data Packet
--------------------+-------+------------+------------------------------------------------------------------
Peer List Request | | | A request for a list of
| | | high-reachability relay peers
| PFX | 4 bytes | Packet prefix, must be 0x6D 0x30 0x52 0xE9
| TYPE | 1 byte | Value = 'A'
| VER | 1 byte | Protocol version
| CID | 32 bytes | Correlation ID, used for responses
--------------------+-------+------------+------------------------------------------------------------------
DHT Communication Packets
Packet Type | Field | Data Type | Description
--------------------+-------+------------+------------------------------------------------------------------
RetrieveRequest | | | A request to a peer to return a data item for a given DHT key
| | | and data type
| PFX | 4 bytes | Packet prefix, must be 0x6D 0x30 0x52 0xE9
| TYPE | 1 byte | Value = 'Q'
| VER | 1 byte | Protocol version
| CID | 32 bytes | Correlation ID, used for responses
| DTYP | 1 byte | Type of data to retrieve:
| | | 'I' = Index Packet
| | | 'E' = Email Packet
| | | 'M' = Directory Entry
| KEY | 32 bytes | DHT key to look up
--------------------+-------+------------+------------------------------------------------------------------
Deletion Query | | | A request to a peer to return a Deletion Info Packet for a given
(Not implemented) | | | DHT key and data type. No response is expected if the DHT item
| | | is not known to be deleted.
| PFX | 4 bytes | Packet prefix, must be 0x6D 0x30 0x52 0xE9
| TYPE | 1 byte | Value = 'L'
| VER | 1 byte | Protocol version
| CID | 32 bytes | Correlation ID, used for responses
| DTYP | 1 byte | Type of data to query for:
| | | 'I' = Index Packet
| | | 'E' = Email Packet
| | | 'M' = Directory Entry
| KEY | 32 bytes | DHT key to look up
--------------------+-------+------------+------------------------------------------------------------------
Store Request | | | DHT Store Request
| PFX | 4 bytes | Packet prefix, must be 0x6D 0x30 0x52 0xE9
| TYPE | 1 byte | Value = 'S'
| VER | 1 byte | Protocol version
| CID | 32 bytes | Correlation ID, used for responses
| HLEN | 2 bytes | HashCash length
| HK | byte[] | HashCash token (HLEN bytes)
| DLEN | 2 bytes | Length of the DATA field
| DATA | byte[] | Data packet to store (DLEN bytes).
| | | Can be an Index Packet, Email Packet, or Email Destination.
--------------------+-------+------------+------------------------------------------------------------------
Email Packet | | | Request to delete an Email Packet by DHT key
Delete Request | | |
| PFX | 4 bytes | Packet prefix, must be 0x6D 0x30 0x52 0xE9
| TYPE | 1 byte | Value = 'D'
| VER | 1 byte | Protocol version
| CID | 32 bytes | Correlation ID, used for responses
| KEY | 32 bytes | DHT key of the Email Packet to delete
| DA | 32 bytes | Delete Authorization (SHA-256 must equal DV in the email pkt)
--------------------+-------+------------+------------------------------------------------------------------
Index Packet | | | Request to remove one or more entries (Email Packet keys) from
Delete Request | | | an Index Packet
| PFX | 4 bytes | Packet prefix, must be 0x6D 0x30 0x52 0xE9
| TYPE | 1 byte | Value = 'X'
| VER | 1 byte | Protocol version
| CID | 32 bytes | Correlation ID, used for responses
| DH | 32 bytes | The Email Destination hash of the Index Packet
| N | 1 byte | Number of entries in the packet
| DHT1 | 32 bytes | First DHT key to remove
| DA1 | 32 bytes | Delete Authorization (SHA-256 must equal DV in the email packet
| | | referenced by DHT1)
| DHT2 | 32 bytes | Second DHT key to remove
| DA2 | 32 bytes | Delete Authorization (SHA-256 must equal DV in the email packet
| | | referenced by DHT2)
| ... | ... | ...
| DHTn | 32 bytes | n-th DHT key to remove
| DAn | 32 bytes | Delete Authorization (SHA-256 must equal DV in the email packet
| | | referenced by DHTn)
--------------------+-------+------------+------------------------------------------------------------------
Find Close Peers | | | Request for k peers close to a key
| PFX | 4 bytes | Packet prefix, must be 0x6D 0x30 0x52 0xE9
| TYPE | 1 byte | Value = 'C'
| VER | 1 byte | Protocol version
| CID | 32 bytes | Correlation ID, used for responses
| KEY | 32 bytes | DHT key
--------------------+-------+------------+------------------------------------------------------------------
4. Protocols
4.1. Storing a DHT item via relays
I2P nodes involved: A=Sender, R1...Rn=Relays, S1...Sm=Storage Nodes
1) A onion-encrypts the Store Request with the public keys of all hops, resulting in a Relay Packet.
2) A sends the Relay Packet to R1.
3) R1 decrypts the packet, waits a random amount of time, and sends it to R2.
4) R2 confirms delivery with R1.
5) Repeat until packet arrives at Rn.
6) Rn decrypts the Relay Packet into an Email Packet.
7) Rn sends the packet to S1,...,Sm through a Kademlia STORE
4.2. Return Chains
In order to make it impossible for two non-adjacent nodes on the return chain to identify Relay
Return Request packets, the payload and the entire Return Chain are re-encrypted at every hop.
A new Correlation ID is generated at every hop.
Here is a simplified diagram of how a Relay Return Packet is sent from one hop to the next:
(A) The packet is received. HOP1 through HOP3 contain encrypted data (encrypted with the public key
for the receiving I2P node):
+------------------- Relay Return Request --------------------------+
| |
| .-----KEY1-----. |
| .---KEY1---. | .---KEY2---. | |
| .-KEY1-. | .-KEY2-. | | | .-KEY3-. | | .---------. |
| | HOP1 | | | HOP2 | | | | | HOP2 | | | | PAYLOAD | |
| `------ | `------ | | | `------ | | `--------- |
| `---------- | `---------- | |
| `-------------- |
| |
+-------------------------------------------------------------------+
KEYx denotes a layer of encryption.
(B) The receiving node decrypts HOP1, HOP2, and HOP3. HOP1 is now in plain text. It contains the
destination of the next hop and an AES key.
+------------------- Relay Return Request --------------------------+
| |
| .-----KEY2-----. |
| .---KEY2---. | .---KEY3---. | |
| .------. | .------. | | | .------. | | .---------. |
| | HOP1 | | | HOP2 | | | | | HOP2 | | | | PAYLOAD | |
| `------ | `------ | | | `------ | | `--------- |
| `---------- | `---------- | |
| `-------------- |
| |
+-------------------------------------------------------------------+
(C) HOP1 is replaced with random data and moved to the end of the chain. The payload is encrypted with
the AES key from HOP1:
+------------------- Relay Return Request --------------------------+
| |
| .-----KEY2-----. |
| .---KEY2---. | .---KEY3---. | |
| | .------. | | | .------. | | .------. .---AES---. |
| | | HOP2 | | | | | HOP2 | | | | HOP1 | | PAYLOAD | |
| | `------ | | | `------ | | `------ `--------- |
| `---------- | `---------- | |
| `-------------- |
| |
+-------------------------------------------------------------------+
(D) The packet is sent to the next node in the chain.
4.3. Retrieving DHT items via relays (not implemented yet)
I2P nodes involved:
A=Address Owner
F=Fetcher
O1...On=Outbound Relays
I1...In=Inbound Relays,
S1...Sm=Storage Nodes
1) A builds a Relay Request containing a Retrieve Request and sends it to F via O1, O2, ..., On
as described in 4.1
2) F queries the DHT for the DHT item
3) F encrypts the DHT data with the public key for hop 1 of the return chain
4) F moves the (RL1,RET1) block of the return chain to the end (behind RETn+1)
5) F sends the results of steps 3) and 4) to I1
6) I1 decrypts all (RLx,RETx) blocks of the return chain and finds I2 and the AES key in the first block
7) I1 replaces (RL1,RET1) with random data that is encrypted with the PK for I2
8) I1 moves the (RL1,RET1) block of the return chain to the end (behind RETn+1)
9) I1 encrypts the payload with the AES key
10) I1 sends the results of steps 7) and 8) to I2
11) Repeat from 6) for I2, I3, ..., until the data reaches A (when the first byte of RET1 is non-zero)
12) A decrypts the (RL1,RET1) block which contains all AES keys
13) A decrypts the payload with the AES keys, starting from the last hop's key
14) The decrypted data contains the DHT data packet
4.4. Deleting an Email Packet
Every time a recipient receives an email packet directly from one or more storage nodes, it asks the
storage node(s) to delete the packet.
If the email packet is received through one or more relays, the recipient issues a delete request to
a (possibly different) relay endpoint, which entails an additional findClosestNodes lookup because the
endpoint has to find out which nodes are storing the packet.
The recipient also sends a delete request for index packet, asking the storage nodes to delete the DHT
key of the email packet. Each index packet node then removes the DHT key from the stored index packet,
and adds the DHT key to a list of deleted DHT keys it maintains for each index packet (plus the
delete verification hash).
The purpose of this is so a node that is about to replicate an email packet can find out if it missed
an earlier delete request for that packet, in which case the node "replicates" the delete request rather
than the packet itself.
This helps reduce storage space by removing old Email Packets from nodes that weren't online at the time
the delete request was sent initially.
4.5 Deleting an Index Packet Entry
Similar to deleting an email packet.
4.6. Replication
See comments at the beginning of src/i2p/bote/network/kademlia/ReplicateThread.java
5. Algorithms Used By Nodes Locally
5.1. Retrieving Email via relays
See also http://forum.i2p/viewtopic.php?p=19927#19927 ff.
1) Randomly choose a set of n relay nodes, R1...Rn (outgoing chain for request)
2) Randomly choose a set of m relay nodes, S1...Sm. (return chain / inbound mail chain)
- with Sm being the node closest to the receiver
and S1 the chain node closest to fetcher
3) Generate m+1 random 32-byte arrays (for XORing the return packets), X1...Xm+1
(This is done so the outgoing chain's endpoint or inbound first hop need
not know all inbound hops in order to perform hop-to-hop encryption. Each
hop will decrypt one 32-byte random array and encrypt the packet with it,
so it looks different at each hop without one node at the beginning
knowing all hops)
4) With Sm's public key, encrypt the local destination key and Xm+1
5) With Sm-1's public key, encrypt Sm's destination key, Xm, and the data from step 4)
6) With Sm-2's public key, encrypt Sm-1's destination key, Xm-1, and the data from step 5)
7) Repeat until the entire return chain, S1...Sm, has been onion-encrypted, and also include a
delay for each hop.
8) Add S1's destination key and X1 to the data from step 7)
9) Add the data (which is a Relay Packet) to a Retrieve Request packet.
10) Encrypt the resulting packet, using the public keys of relays Rn (Fetcher), Rn-1, ..., R1,
and add the destination key of the next relay each time. Also included is a delay for each relay.
11) Set a random Correlation ID on the packet at each layer
12) Add the packet to the relay packet folder.
13) When a reply packet is received, decrypt it first with the local node's private
decryption key, then with all the random keys X1...Xm+1.
6. Files
6.1. Encryption
The identities file, the address book, and all email files are encrypted with AES-256.
To generate the AES key from the password, scrypt (http://www.tarsnap.com/scrypt.html) is used.
The file format is:
Field | #bytes | Description
-------+--------+------------------------------------------------------------------
SOF | 4 | Start of file, contains the characters "IBef"
VER | 1 | Format version, must be 1
N | 4 | scrypt CPU cost parameter
r | 4 | scrypt memory cost parameter
p | 4 | scrypt parallelization parameter
SALT | 32 | Salt for scrypt
IV | 32 | IV for AES
DATA | | The encrypted data
6.2. Identities file
Stores all email identities the local user has created. One line per entry.
Format:
<base64 key><tab><public name>[<tab><description>][<tab><email address>]
The base64 key contains two public keys (encryption+signing) and two private
keys.
The identities file can optionally contain a line that contains the string
"Default", a space, and an Email Destination (i.e. two public keys). If the
Email Destination matches one of the identities, that identity is used as
the default.
6.3. Included .jar files and third-party source code
bcprov-ecc-jdk16-145.jar A stripped down version of the BouncyCastle library,
containing only the classes needed for ECC.
mailapi.jar Part of JavaMail
src/SevenZip/ An LZMA implementation from http://www.7-zip.org/sdk.html
src/net/sf/ntru An NTRU implementation from http://sf.net/projects/ntru/
src/com/lambdaworks/crypto/ An scrypt implementation from https://github.com/wg/scrypt/
7. Glossary of Terms
Email Destination
As the name implies, an Email Destination is an identifier by which somebody can be reached via I2P-Bote.
An Email Destination is a Base64 string containing a public encryption key and a signature verification key.
Example of a 512-character Email Destination (ElGamal-2048/DSA-2048):
uQtdwFHqbWHGyxZN8wChjWbCcgWrKuoBRNoziEpE8XDt8koHdJiskYXeUyq7JmpG
In8WKXY5LNue~62IXeZ-ppUYDdqi5V~9BZrcbpvgb5tjuu3ZRtHq9Vn6T9hOO1fa
FYZbK-FqHRiKm~lewFjSmfbBf1e6Fb~FLwQqUBTMtKYrRdO1d3xVIm2XXK83k1Da
-nufGASLaHJfsEkwMMDngg8uqRQmoj0THJb6vRfXzRw4qR5a0nj6dodeBfl2NgL9
HfOLInwrD67haJqjFJ8r~vVyOxRDJYFE8~f9b7k3N0YeyUK4RJSoiPXtTBLQ2RFQ
gOaKg4CuKHE0KCigBRU-Fhhc4weUzyU-g~rbTc2SWPlfvZ6n0voSvhvkZI9V52X3
SptDXk3fAEcwnC7lZzza6RNHurSMDMyOTmppAVz6BD8PB4o4RuWq7MQcnF9znElp
HX3Q10QdV3omVZJDNPxo-Wf~CpEd88C9ga4pS~QGIHSWtMPLFazeGeSHCnPzIRYD
Example of a 86-character Email Destination (ECC-256):
1Lcvly8no5of6juJKxqy-xA-MStM2c2XKorepH1oqs5yKBkg9-ZcG4G4kZY1E~2672cMA806l9EicQLmlehB1m
Email Address
Email Addresses in I2P-Bote are shortcuts for Email Destinations.
Email Address <--> Email Destination mappings are stored in two places: the local address book and the
distributed address directory (the latter not being implemented yet).
Email Identity
An Email Identity is an Email Destination plus a name you want to be known as when you use that identity.
Technically speaking, an Email Identity consists of four things:
* An Email Destination (i.e. two public keys)
* The two private keys for the Email Destination
* A public name which is shown to other people in emails
* A description which is not shown to anybody but you.
It helps you remember which Email Identity you use for which purpose.
An email identity is not required for sending emails (in that case only "Anonymous" can be selected in the
"sender" field).
I2P destination
The address of a I2P-Bote node on the I2P network. There is normally no need to know it.
I2P destinations and Email Destinations look similar, but are completely independent of each other.
8. To Do / Ideas
* If multiple Delete Verification Hashes and multiple encrypted AES session keys could be put into an
email packet, it wouldn't be necessary to store one email packet per recipient
* Keep email identities in a keystore (JKS)
* Deletion of emails after they have been sent: Sender knows the
delVerificationHashes of the packets and can delete the packets from the DHT.
* Once SMTP/POP3 is supported, allow a @host to be appended to email
destinations so email clients that insist on it, like Thunderbird, don't complain.
* Expire DHT items sooner (currently, expiration time = 100 days) and require
that senders resend emails before they expire, until the email has been picked up
* For each email in the "sent" folder, keep a list of email package keys
and periodically check to see if they have been deleted from the DHT.
When they are all deleted, show "email delivered" in the sent folder.
* ignore store requests for existing packets so malicious index nodes cannot replace email packets on other index nodes
* instead of republishing after T seconds, pick a random time from the interval [T-a, T+a];
the probability should be low at T-a and then increase
* Cache email dest - closest node mappings for faster Kademlia lookups
* Externally synchronize ArrayLists?
* identities: "publish to distributed address book" button, asks for an email address
* b32 email destinations in the distributed address book? could also be useful for getting around the address size limit in POP/SMTP
* <jsp:useBean> instead of zero-param JSP functions
* button to delete all packets with an invalid protocol version
* auto-refresh network.jsp
* show remaining time for the 3-min delay at startup
* Automatically create a different sender address for each recipient
* test relays and storage nodes periodically, ban nodes that break the contract
* optionally pad all packets to a system-wide fixed size
* Always use the same amount of bandwidth, testing nodes or sending dummy messages if necessary.
* Always keep incoming bandwidth the same as outgoing bandwidth (can this be done?)
* Pad packets before encrypting to prevent tagging attacks (only relay packets?)
* delivery confirmation to sender
* Turnkey outproxy feature?
* select different set of hops for each packet
* make minimum reachability configurable (currently 80%)
* mention that min/max delay = earliest/latest send time (explain that there is no guarantee for the send time being between min and max, it can be after max)
* On first run, offer to create a new email identity
* Folder structure on disk should reflect folders in app. All email folders visible to the user have the same root directory: [app dir]/folders.
* ask user for confirmation before deleting an email identity
* use a key store for email identities so they are not locally readable?
* prioritize packets in I2PSendQueue? Should PeerListRequests get higher priority than relay packets etc.?