Onion packet format
The onion-packet has two, fixed-size parts:
The header which includes authenticated-encrypted routing messages
The body which is encrypted with layers of ChaCha20, with intentionally no integrity protection.
One important thing to note is that the encoding within the fixed-size body is not specified here, but it must have some sort of end-to-end integrity protection. The onion packet format will not help with that, at all.
Box encryption
Box encryption (named after the similar construction from NaCl) is a generic way of encrypting a message, with integrity protection, so that only the owner of a particular X25519 secret key can read it.
The format is:
32 bytes: a X25519 ephemeral public key from the sender
?? bytes: encrypted message, with ChaCha20Poly1305 (RFC 8439), encrypted with the key derived from blake3-hashing the X25519 shared secret computed from the sender's ephemeral key and the X25519 key of the recipient, and an all-zero nonce.
Header format
The header for a message whose first hop is "Rob" will have:
69 bytes: 21 bytes box-encrypted to Rob's X25519 public key. The first byte is a flag for how to interpret the next 20 bytes:
Byte 1 = 1 indicates we need to forward the message to the next hop. The next 20 bytes is the fingerprint for next hop.
Byte 1 = 0 indicates the packet is addressed to us.
If the next 20 bytes are all zeros, it means this packet is an ungarbled normal packet.
Otherwise, it is a reply packet that is garbled through using a reply block. Bytes 1 through 8 (inclusive) is a 64-bit reply block identifier that we will use to pair this packet with the keys we stored from when we generated the reply block, which we will use to de-garble the message body.
621 bytes: ChaCha20-encrypted (no authentication, no nonce) with
KDF(s, "header")
wheres
is the shared-secret between the sender and our X25519 keys.The rest of the headers
As much randomness to pad the entire header to 690 bytes
The padding of the header to 690 bytes is done to keep the header size fixed, which helps with anonymity and prevents traffic analysis. The maximum route length is 10 hops, so subsequent peeled header is exactly 69 bytes smaller than the previous one, but with 69 bytes more random noise added to the back. This means the intermediary nodes have no idea where they are in the route.
Body format
The body is ChaCha20-encrypted at every layer of the onion with KDF(s, "body")
, and is always exactly 8192 bytes in length.
Key-derivation function
The function KDF
is implemented by using blake3
's keyed-hash mode, with the "key" being padded to 32 bytes with _
. For instance, KDF(s, "header")
means blake3-hashing s
with the key "header__________________________"
.
Last updated