2 @section Encrypted packet
4 Encrypted packets are the only files found in spools, in exchangeable
5 storages and that are synchronized between TCP daemons.
7 Each encrypted packet has the following header:
10 +------------ HEADER --------------------+ +------ ENCRYPTED -----+
12 +--------------------------------------------+---------+----------...---+-----...--+
13 | MAGIC | NICE | SENDER | RCPT | EPUB | SIGN | BLOCK 0 | BLOCK 1 ... | OPAD |
14 +-------------------------------------/------\---------+----------...---+-----...--+
16 +-------------------------------------+
17 | MAGIC | NICE | SENDER | RCPT | EPUB |
18 +-------------------------------------+
21 @multitable @columnfractions 0.2 0.3 0.5
22 @headitem @tab XDR type @tab Value
23 @item Magic number @tab
24 8-byte, fixed length opaque data @tab
25 @verb{|N N C P E 0x00 0x00 0x06|}
28 1-255, packet @ref{Niceness, niceness} level
30 32-byte, fixed length opaque data @tab
33 32-byte, fixed length opaque data @tab
35 @item Exchange public key @tab
36 32-byte, fixed length opaque data @tab
37 Ephemeral curve25519 public key
39 64-byte, fixed length opaque data @tab
40 ed25519 signature for that packet's header over all previous fields.
43 Each @code{BLOCK} is AEAD-encrypted 128 KiB data. Last block can have
44 smaller size. They are encrypted in AEAD mode using
45 @url{https://cr.yp.to/chacha.html, ChaCha20}-@url{https://en.wikipedia.org/wiki/Poly1305, Poly1305}
46 algorithms. Authenticated data is BLAKE3-256 hash of the unsigned
47 portion of the header (the same data used in the signature). Nonce is
48 block's sequence number (64-bit integer starting at 0).
50 Concatenated plaintext of those blocks hold the following stream of data:
53 +-----------+--------+---------------------+--------+
54 | PAYLOAD | SIZE | REST (OF PAYLOAD) | IPAD |
55 +-----------+--------+---------------------+--------+
58 +-- always aligned to the beginning of block
61 Where @code{SIZE} is following XDR structure:
63 @multitable @columnfractions 0.2 0.3 0.5
64 @headitem @tab XDR type @tab Value
66 unsigned hyper integer @tab
67 Full payload size. @code{len(PAYLOAD) + len(REST)}
69 unsigned hyper integer @tab
70 Full padding size. @code{len(IPAD) + len(OPAD)}
73 @code{SIZE} is always at the beginning of the block. So payload and rest
74 of it have variable length. Block containing @code{SIZE} is encrypted
75 with the different key (@code{key=size}), to distinguish it from the
76 "ordinary" ones (@code{key=full}).
78 @code{IPAD} contains zeros and is shorter than single block. Padding is fully
79 optional and is used only to hide the payload full size.
81 It is acceptable to have either @code{PAYLOAD} or @code{REST} of it of
82 zero length. For example:
85 +------+-------------+
86 | SIZE | PAYLOAD ... |
87 +------+-------------+
91 +------+-------------+------+
92 | SIZE | PAYLOAD ... | IPAD |
93 +------+-------------+------+
94 \--------- BLOCK --------/
97 +--------------------------+ +------+-------------------+
98 | PAYLOAD | .. | SIZE | IPAD ... |
99 +--------------------------+ +------+-------------------+
100 \--------- BLOCK --------/ \--------- BLOCK --------/
103 +--------------------------+ +------+-------------------+
104 | PAYLOAD | .. | SIZE | PAYLOAD ... |
105 +--------------------------+ +------+-------------------+
106 \--------- BLOCK --------/ \--------- BLOCK --------/
109 +--------------------------+ +------+-------------+------+
110 | PAYLOAD | .. | SIZE | PAYLOAD ... | IPAD |
111 +--------------------------+ +------+-------------+------+
112 \--------- BLOCK --------/ \--------- BLOCK --------/
115 +--------------------------+ +------+-------------------+ +--------------------------+
116 | PAYLOAD | .. | SIZE | PAYLOAD ... | .. | PAYLOAD ... |
117 +--------------------------+ +------+-------------------+ +--------------------------+
118 \--------- BLOCK --------/ \--------- BLOCK --------/ \--------- BLOCK --------/
119 key=full key=size key=full
121 +--------------------------+ +------+-------------------+ +-------------+-------------+
122 | PAYLOAD | .. | SIZE | PAYLOAD ... | .. | PAYLOAD ... | IPAD ... |
123 +--------------------------+ +------+-------------------+ +-------------+------------+
124 \--------- BLOCK --------/ \--------- BLOCK --------/ \--------- BLOCK --------/
125 key=full key=size key=full
128 @code{OPAD} is appended if @code{IPAD} (inside the block) has not enough
129 length. @code{OPAD} is just an output of the XOF function. No encryption
130 and explicit authentication is applied to it. XOF is just faster and can
131 be computed deterministically on both ends -- you just have to
132 authenticate its length.
134 Each node has static @strong{exchange} and @strong{signature} keypairs.
135 When node A want to send encrypted packet to node B, it:
138 @item generates ephemeral @url{http://cr.yp.to/ecdh.html, curve25519} keypair
139 @item prepares structure for signing
140 @item signs that structure using private
141 @url{http://ed25519.cr.yp.to/, ed25519} signature key
142 @item takes remote node's exchange public key and performs
143 Diffie-Hellman computation on this remote static public key and
144 private ephemeral one
145 @item derives three keys using BLAKE3 derivation function from the
146 curve25519-derived ephemeral source key:
148 @item @code{key=full} with the context of:
149 @verb{|N N C P E 0x00 0x00 0x06 <SP> F U L L|}
150 @item @code{key=size} with the context of:
151 @verb{|N N C P E 0x00 0x00 0x06 <SP> S I Z E|}
152 @item @code{key=pad} with the context of:
153 @verb{|N N C P E 0x00 0x00 0x06 <SP> P A D|}
155 @item calculates authenticated data: it is BLAKE3-256 hash of the
156 unsigned header (same used for signing)
157 @item reads the payload by 128 KiB chunks. If it is enough data to fill
158 the entire 128 KiB block, then encrypt the chunk with
160 @item if there is not enough data, then payload is reaching the end.
162 @item prepend @code{SIZE} structure to the finishing chunk of data.
163 All sizes at that time are known
164 @item produce block with @code{SIZE} even if there is no payload
166 @item append remaining payload to the @code{SIZE}, if it is left
167 @item if there is padding, then fill current block to the end with
169 @item encrypt the block with @code{key=size} key
171 @item if there is more padding left (@code{OPAD}), then generate it with
172 BLAKE3 XOF function using the @code{key=pad} key