Next: Encrypted area packet, Previous: Plain packet, Up: Packet format [Index]
Encrypted packets are the only files found in spools, in exchangeable storages and that are synchronized between TCP daemons.
Each encrypted packet has the following header:
+------------ HEADER --------------------+ +------ ENCRYPTED -----+ / \ / \ +--------------------------------------------+---------+----------...---+-----...--+ | MAGIC | NICE | SENDER | RCPT | EPUB | SIGN | BLOCK 0 | BLOCK 1 ... | OPAD | +-------------------------------------/------\---------+----------...---+-----...--+ / \ +-------------------------------------+ | MAGIC | NICE | SENDER | RCPT | EPUB | +-------------------------------------+
XDR type | Value | |
---|---|---|
Magic number | 8-byte, fixed length opaque data | N N C P E 0x00 0x00 0x06 |
Niceness | unsigned integer | 1-255, packet niceness level |
Sender | 32-byte, fixed length opaque data | Sender node’s id |
Recipient | 32-byte, fixed length opaque data | Recipient node’s id |
Exchange public key | 32-byte, fixed length opaque data | Ephemeral curve25519 public key |
Signature | 64-byte, fixed length opaque data | ed25519 signature for that packet’s header over all previous fields. |
Each BLOCK
is AEAD-encrypted 128 KiB data. Last block can have
smaller size. They are encrypted in AEAD mode using
ChaCha20-Poly1305
algorithms. Authenticated data is BLAKE3-256 hash of the unsigned
portion of the header (the same data used in the signature). Nonce is
block’s sequence number (64-bit integer starting at 0).
Concatenated plaintext of those blocks hold the following stream of data:
+-----------+--------+---------------------+--------+ | PAYLOAD | SIZE | REST (OF PAYLOAD) | IPAD | +-----------+--------+---------------------+--------+ ^ | +-- always aligned to the beginning of block
Where SIZE
is following XDR structure:
XDR type | Value | |
---|---|---|
Payload | unsigned hyper integer | Full payload size. len(PAYLOAD) + len(REST) |
Pad | unsigned hyper integer | Full padding size. len(IPAD) + len(OPAD) |
SIZE
is always at the beginning of the block. So payload and rest
of it have variable length. Block containing SIZE
is encrypted
with the different key (key=size
), to distinguish it from the
"ordinary" ones (key=full
).
IPAD
contains zeros and is shorter than single block. Padding is fully
optional and is used only to hide the payload full size.
It is acceptable to have either PAYLOAD
or REST
of it of
zero length. For example:
+------+-------------+ | SIZE | PAYLOAD ... | +------+-------------+ \------ BLOCK -----/ key=size +------+-------------+------+ | SIZE | PAYLOAD ... | IPAD | +------+-------------+------+ \--------- BLOCK --------/ key=size +--------------------------+ +------+-------------------+ | PAYLOAD | .. | SIZE | IPAD ... | +--------------------------+ +------+-------------------+ \--------- BLOCK --------/ \--------- BLOCK --------/ key=full key=size +--------------------------+ +------+-------------------+ | PAYLOAD | .. | SIZE | PAYLOAD ... | +--------------------------+ +------+-------------------+ \--------- BLOCK --------/ \--------- BLOCK --------/ key=full key=size +--------------------------+ +------+-------------+------+ | PAYLOAD | .. | SIZE | PAYLOAD ... | IPAD | +--------------------------+ +------+-------------+------+ \--------- BLOCK --------/ \--------- BLOCK --------/ key=full key=size +--------------------------+ +------+-------------------+ +--------------------------+ | PAYLOAD | .. | SIZE | PAYLOAD ... | .. | PAYLOAD ... | +--------------------------+ +------+-------------------+ +--------------------------+ \--------- BLOCK --------/ \--------- BLOCK --------/ \--------- BLOCK --------/ key=full key=size key=full +--------------------------+ +------+-------------------+ +-------------+-------------+ | PAYLOAD | .. | SIZE | PAYLOAD ... | .. | PAYLOAD ... | IPAD ... | +--------------------------+ +------+-------------------+ +-------------+------------+ \--------- BLOCK --------/ \--------- BLOCK --------/ \--------- BLOCK --------/ key=full key=size key=full
OPAD
is appended if IPAD
(inside the block) has not enough
length. OPAD
is just an output of the XOF function. No encryption
and explicit authentication is applied to it. XOF is just faster and can
be computed deterministically on both ends – you just have to
authenticate its length.
Each node has static exchange and signature keypairs. When node A want to send encrypted packet to node B, it:
key=full
with the context of:
N N C P E 0x00 0x00 0x06 <SP> F U L L
key=size
with the context of:
N N C P E 0x00 0x00 0x06 <SP> S I Z E
key=pad
with the context of:
N N C P E 0x00 0x00 0x06 <SP> P A D
key=full
key
SIZE
structure to the finishing chunk of data.
All sizes at that time are known
SIZE
even if there is no payload
data left
SIZE
, if it is left
IPAD
)
key=size
key
OPAD
), then generate it with
BLAKE3 XOF function using the key=pad
key
Next: Encrypted area packet, Previous: Plain packet, Up: Packet format [Index]