Overview of the protocol: 1) Do a DH key exchange to create the keyset. Any public/private keys are used here. 2) Encrypt all traffic with the created keyset. DH key exhange: 1) both sides creates a private key * a node can alternatively use preset one for identification 2) both sides compute the public key from the private key and then sends it (this number is sent as a little endian integer, byte length = 1024 / 8) 3) both sides then generate the shared key from this * a node can verify the received public key against an expected public key Encryption/decryption key set: The protocol uses a set of keys which are rotated through regularly The number keys in the key set is currently 2. Creation encryption/decryption keys: The keyset is first initialize to zero. The new key material is then xorred into the keyset with the key material being wrapped to the length of the keyset. The blowfish encryption/decryption keys are initialized with the first 128 bits (16 bytes) of the keyset. //this is the shared key from the DH key exchange //format is big endian uint8 sharedkey[bitlength / 8]; for(i = 0; i < bitlength / 8; i++) { keyset[i % KEYSETSIZE] ^= sharedkey[i]; } Packet format: Header: 2 bytes - little endian packet body length 6 bytes - ignored/garbage * A packet body length of zero signals that there is new key material and to perform a key rotation. The packet's body length is actually 16 bytes. See below for details of key rotation Body: x bytes - the data of the packet n bytes - padding to bring the body's size upto a multiple 8 bytes (padding is not used in the CRC) Key rotation: After receiving (or sending) the key material of a key rotation packet the new key is xorred with the next key in the key set. The key set is then rotated. (First (current) key becomes last, second (next) key becomes the first (current), etc) Blowfish is then initialized with the new key on the decryption (or encryption if key rotation was sent) side. Combine new key material: +-------+ |new key|--+ +-------+ | (xor) | 1 2 v +-----+ +-----+ |Key A| |Key B| +-----+ +-----+ Rotate key set: +---------+ | | 1 | 2 v +-----+ +-----+ |Key B|<--|Key A| +-----+ +-----+ Encryption/Decryption: Although both encryption/decryption start out with the same key it is expected for the two to diverge from each other over time thus the encryption and decrpytion must maintain different keysets and counters. Encryption: The encryption's counter is xorred with the data and the counter is then incremented (see below). The data is then encrypted using blowfish using the first key of the encryption keyset. counter | +-------+ | | data | | +-------+ | | | (xor)<---+ | v /-----\ (encrypt) \-----/ | v +-------+ |E(data)| +-------+ Decryption: The data is decrypted using blowfish using the first key of the decryption keyset. The encryption's counter is xorred with the data and the counter is then incremented (see below). +-------+ |E(data)| +-------+ | v /-----\ (decrypt) \-----/ | (xor)<---+ | | v | +-------+ | | data | | +-------+ | | counter Encryption/decryption Counter: A counter when first used it set to all zeroes. uint8 counter[8] = {0, 0, 0, 0, 0, 0, 0, 0}; A counter is incremented by doing: void bigendianIncrement(uint8 *buffer, size_t length); bigendianIncrement(counter, 8);