Next: , Previous: , Up: Developer  


Transport protocol

TAG || ENCRYPTED || NONCE --> PACKET
 ^         ^          ^
 |         |          |
 |         |          +-------------+
 |         |                        |
 |         +-------------+          |
 |                       |          |
 +--< AUTH(AUTH_KEY, ENCRYPTED || NONCE)
                         ^          ^
                         |          |
+------------------------+          |
|                                   |
|                   +---------------+
|                   |
+--< ENCRYPT(KEY, NONCE, PAYLOAD)
                    ^       ^
                    |       |
                    |       +--< SIZE || DATA [|| NOISE]
                    |
                    +--< PRP(PRP_KEY, SERIAL)

SERIAL is message’s serial number. Odds are reserved for client(->server) messages, evens for server(->client) messages.

PRP is XTEA block cipher algorithm used here as PRP (pseudo random permutation function) to obfuscate SERIAL. Plaintext SERIAL state is kept in peers internal state, but encrypted before transmission.

XTEA’s encryption key is the first 128-bit of Salsa20’s output with established common key and zero nonce (message nonces start from 1).

PRP_KEY = ENCRYPT(KEY, 0, 128-bit)

ENCRYPT is Salsa20 stream cipher, with established session KEY and obfuscated SERIAL used as a nonce. 512 bit of Salsa20’s output is ignored and only remaining is XORed with ther data, encrypting it.

SIZE is big-endian uint16 storing length of the DATA.

NOISE is optional. It is just some junk data, intended to fill up packet to MTU size. This is useful for concealing payload packets length.

AUTH is Poly1305 authentication function. First 256 bits of Salsa20’s output are used as a one-time key for AUTH.

AUTH_KEY = ENCRYPT(KEY, NONCE, 256 bit)

To prevent replay attacks we must remember received SERIALs and drop when receiving duplicate ones.