@node Packet @unnumbered Packet format All packets are @url{https://tools.ietf.org/html/rfc4506, XDR}-encoded structures. @menu * Plain packet: Plain. * Encrypted packet: Encrypted. @end menu @node Plain @section Plain packet Plain packet contains either the whole file, or file request (freq), or transition packet or exec message. It is called "plain", because it contains plaintext, but plain packets would never be stored on your hard drive. @verbatim HEADER +--------------------------------------+--...---+ | MAGIC | TYPE | NICE | PATHLEN | PATH | PAYLOAD| +--------------------------------------+--...---+ @end verbatim @multitable @columnfractions 0.2 0.3 0.5 @headitem @tab XDR type @tab Value @item Magic number @tab 8-byte, fixed length opaque data @tab @verb{|N N C P P 0x00 0x00 0x03|} @item Payload type @tab unsigned integer @tab 0 (file), 1 (freq), 2 (exec), 3 (transition), 4 (exec-fat) @item Niceness @tab unsigned integer @tab 1-255, preferred packet @ref{Niceness, niceness} level @item Path length @tab unsigned integer @tab actual length of @emph{path} field's payload @item Path @tab 255 byte, fixed length opaque data @tab @itemize @item UTF-8 encoded destination path for file transfer @item UTF-8 encoded source path for file request @item UTF-8 encoded, zero byte separated, exec's arguments @item Node's id the transition packet must be relayed on @end itemize @end multitable Path has fixed size because of hiding its actual length -- it is valuable metadata. Payload is appended to the header -- it is not stored as XDR field, because XDR has no ability to pass more than 4 GiB of opaque data. Moreover most XDR libraries store fields in the memory in practice. Depending on the packet's type, payload could store: @itemize @item File contents @item Destination path for freq @item @url{https://facebook.github.io/zstd/, Zstandard} compressed exec body @item Whole encrypted packet we need to relay on @item Uncompressed exec body @end itemize Also depending on packet's type, niceness level means: @itemize @item Preferable niceness level for files sent by freq @item @env{NNCP_NICE} variable's value passed during @ref{CfgExec} invocation. @end itemize @node Encrypted @section Encrypted packet 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: @verbatim +------------ HEADER --------------------+ +------------- ENCRYPTED -------------+ / \ / \ +--------------------------------------------+------+---------+----------...---+------+ | MAGIC | NICE | SENDER | RCPT | EPUB | SIGN | SIZE | BLOCK 0 | BLOCK 1 ... | JUNK | +-------------------------------------/------\------+---------+----------...---+------+ / \ +-------------------------------------+ | MAGIC | NICE | SENDER | RCPT | EPUB | +-------------------------------------+ @end verbatim @multitable @columnfractions 0.2 0.3 0.5 @headitem @tab XDR type @tab Value @item Magic number @tab 8-byte, fixed length opaque data @tab @verb{|N N C P E 0x00 0x00 0x05|} @item Niceness @tab unsigned integer @tab 1-255, packet @ref{Niceness, niceness} level @item Sender @tab 32-byte, fixed length opaque data @tab Sender node's id @item Recipient @tab 32-byte, fixed length opaque data @tab Recipient node's id @item Exchange public key @tab 32-byte, fixed length opaque data @tab Ephemeral curve25519 public key @item Signature @tab 64-byte, fixed length opaque data @tab ed25519 signature for that packet's header over all previous fields. @end multitable All following encryption is done in AEAD mode using @url{https://cr.yp.to/chacha.html, ChaCha20}-@url{https://en.wikipedia.org/wiki/Poly1305, Poly1305} algorithms. Authenticated data is BLAKE3-256 hash of the unsigned portion of the header (the same data used in the signature). Size is XDR-encoded unsigned hyper integer, carrying the payload size, encrypted as a single AEAD-block (with the tag) independently from the following blocks. It is encoded with the zero nonce. Payload with possible padding is divided on 128 KiB blocks blocks. They are encrypted with the same authenticated data and increasing big-endian 64-bit nonce, starting at 1. Each node has static @strong{exchange} and @strong{signature} keypairs. When node A want to send encrypted packet to node B, it: @enumerate @item generates ephemeral @url{http://cr.yp.to/ecdh.html, curve25519} keypair @item prepares structure for signing @item signs that structure using private @url{http://ed25519.cr.yp.to/, ed25519} signature key @item takes remote node's exchange public key and performs Diffie-Hellman computation on this remote static public key and private ephemeral one @item derives 32-bytes AEAD encryption key with BLAKE3 derivation function. Source key is the derived ephemeral key. Context is @verb{|N N C P E 0x00 0x00 0x05|} magic number @item calculates authenticated data: it is BLAKE3-256 hash of the unsigned header (same used for signing) @item encrypts size, appends its authenticated ciphertext to the header (with authenticated data, nonce=0) @item encrypts each payload block, appending its authenticated ciphertext (with authenticated data, nonce starting at 1, increasing with each block) @item possibly appends any kind of "junk" noise data to hide real payload's size from the adversary (generated using BLAKE3 XOF, with the key derived from the ephemeral one and context string of @verb{|N N C P E 0x00 0x00 0x05 P A D|}) @end enumerate