Next: Handshake protocol, Previous: Verifier structure, Up: Developer manual
[PktLen] + ENCn(SERIAL) + ENC(KEY, ENCn(SERIAL), DATA_SIZE+DATA+NOISE) + AUTH(ENCn(SERIAL) + ENC(KEY, ENCn(SERIAL), DATA_SIZE+DATA+NOISE))
All transport and handshake messages are indistinguishable from pseudo random noise, except when using TCP connections.
PktLen
is used only with TCP connections. It is big-endian
uint16 length of the whole packet (except PktLen
itself).
SERIAL
is message’s serial number. Odds are reserved for
client(->server) messages, evens for server(->client) messages.
ENCn
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 is compact and fast enough. Salsa20 is PRF
function and requires much more code to create PRP from it.
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).
ENC
is Salsa20 stream cipher, with established session KEY
and obfuscated SERIAL
used as a nonce. First 256 bits of
Salsa20’s output is used as Poly1305 authentication key, next 256 bits
are ignored. All remaining output is XORed with the data, encrypting it.
DATA_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 output are used as a one-time key for AUTH
.
To prevent replay attacks we must remember received SERIAL
s and
if meet one, then drop it. Basically we could just store latest number
and check if received one is greater, but because of UDP packets
reordering this can lead to valid packets dropping and overall
performance degradation. We store up to 256 seen nonces in hash
structure, in two swapping buckets.
Next: Handshake protocol, Previous: Verifier structure, Up: Developer manual