Encryption and Authentication
See
OldPacketFormat for details of the current packet format and why it needs to change!
During handshaking, the peers establish three keys for each direction of the connection: the encryption key, the authentication key, and the IV key. Different keys
must be used in each direction.
Each plaintext packet starts with a unique, non-wrapping
sequence number. This is distinct from the
payload number described below - if a packet is retransmitted, it will have the same payload number as the original, but a new sequence number.
The IV for encryption is obtained by encrypting the unique sequence number with the IV key. This is equivalent to using a block cipher in CTR mode as a pseudo-random number generator to generate the IVs. The IVs are guaranteed to be unique.
The packet is encrypted in CFB mode using its unique IV and the encryption key. A MAC is then calculated over the encrypted packet using the authentication key, and the MAC is prepended to the encrypted packet.
There is no need to send the packet's unique sequence number in plaintext - the receiver can calculate the IV in advance and the packet is encrypted using a stream cipher, so the receiver can calculate the
ciphertext sequence number in advance. The receiver simply looks for the ciphertext sequence numbers of the next few expected packets instead of looking for the plaintext sequence numbers. This makes it harder for eavesdroppers to identify Freenet traffic, because no part of the packet is in plaintext. A window of 64 sequence numbers should be sufficient to cope with reordering at the IP layer (IPSec uses 32). Note that it is possible, though unlikely, for two packets in the window to have the same ciphertext sequence number due to the random nature of the IVs - the receiver
must detect this case and try both possibilities.
Packet Format
Each packet contains:
- A count of the number of acks (unsigned byte).
- Zero or more acks. Each ack echoes the payload number of a packet received in the other direction.
- These are encoded as follows: The first (lowest) ack is a full 4-byte unsigned value; subsequent acks are 2 byte unsigned offsets from this (add to the first to get the ack number).
- For each ack, the time in milliseconds that the ack was queued for, so we can accurately determine the round-trip time (2 bytes each).
- A count of the number of payload messages (unsigned byte). If there are no payload messages, skip the following.
- A 4-byte payload number. This number will be used by the receiver to acknowledge receipt of the packet, and unlike the unique sequence number it will not change if the packet is retransmitted. However, apart from retransmissions the payload number should be unique and non-wrapping.
- Freenet messages follow the payload number. Each message starts with 2 bytes indicating its type followed by 2 bytes indicating its length. Messages are never split across more than one packet.
Duplicate Detection
The receiver detects duplicate packets by keeping a bitmap of received payload numbers. The bitmap contains up to 2^16 entries, starting with the lowest payload number not yet received. The sender
must not send payload number n+2^16 until payload number n has been acknowledged - however, it must still send acks when necessary (packets that contain acks but no Freenet messages do not require payload numbers).
Coalescing
In the current code, hold acknowledgements and messages for up to 100ms before sending. In future it would be useful to be able to make this a function of the round-trip time, so we need an accurate delay time in the packets. Also, some messages may be less urgent than others.