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