Next: , Previous: , Up: Developer  


Transport protocol

     NONCE = 64bit(ZEROS) || 64bit(MAC(MAC_KEY, SERIAL))
   PAYLOAD = DATA || PAD [|| ZEROS]
CIPHERTEXT = ENCRYPT(KEY, NONCE, PAYLOAD)
       TAG = AUTH(AUTH_KEY, CIPHERTEXT || NONCE)
   MESSAGE = TAG || CIPHERTEXT || NONCE

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

MAC is BLAKE2b-MAC used to obfuscate SERIAL. MAC’s key MAC_KEY is the first 256-bit of ChaCha20’s output with established common key and zero nonce (message nonces start from 1).

MAC_KEY = 256bit(ENCRYPT(KEY, 0))

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

DATA is padded using ISO/IEC 7816-4 format (PAD (0x80 byte) with optional ZEROS following), to fill up packet to conceal payload packet length.

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

AUTH_KEY = 256bit(ENCRYPT(KEY, NONCE))

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

In encryptionless mode this scheme is slightly different:

  NONCE = MAC(MAC_KEY, SERIAL)
ENCODED = ENCLESS(DATA || PAD || ZEROS)
 PACKET = ENCODED || NONCE

ENCLESS is AONT and chaffing function. There is no need in explicit separate authentication.