The simple symmetric protocol based on the UDP transport with automatic encryption and authentication (ETA) based on known public keys of the local and remote nodes.
The protocol allow sending authenticated datagrams between nodes using minimal transport control just enough to exchange keys as needed.
Each node has it's own session key that is initially unknown to other parties and is subject to change without notification. Each node also have its public key that is known to all other nodes and does not change without notification.
Data are packed into binary compact form of blocks. Packet carries following information:
- Sender node ID, nodeId: int
- Receiver node ID, nodeId: int
- Block (serial) ID, blockId: int
- Block type: int
- Blockpayload: depends on the type
The packet is encrypted using Boss encoder. The initial serial should be a random number to reduce the collision probability during unexpected protocol restart.
|0||DATA||Encrypted and authenticated data transfer. The remote should decrypt, check and pass the data to the consumer. Payload is array of binary arrays. Empty data allowed, used to check/maintain connection.||Byte payload|
|1||ACK||ACK. Acknowledge reception of a packets with a given IDs||Int  ids|
|2||NACK||NACK. Packet with given ids are not receiver (decryption failed|
|4||WELCOME||Accept handshake start||rnonce: random 64 byte sequence|
|5||KEY_REQ||Request session key||(rnonce, lnonce) signed with the local party private key|
|6||SESSION||Transmit session key||(lnonce, session_key) signed by remote party private key and encrypted with local party public key.|
The data used in the protocol description:
|rnonce||Remote nonce. Random 64 bytes, used to ensure local node possesses its private key|
|lnonce||Local nonce. Random 64 bytes, used to ensure remote node possesses its private key.|
|nodeId||Integer, 32 bits, used to identify node in the protocol and/or block|
|blockId||Integer, 32 bits, serial number used to identify DATA block. Measures should be taken to reduce collision probability on occasional restart (use random starting id).|
|session_key||32 bytes symmetric key used to construct session's SymmetricKey.|
|payload||Array of binary chunks to be transmitted between nodes using ETA (HMAC/AES256), using SymmetricKey class.|
Protocol is described from a local node point of view. Local node (local) tries to connect and send data to the remote node (remote). The protocol transmits data only to one direction, from local to remote. To achieve duplex mode, remote node also creates the same protocol to the local.
To encrypt and authenticate transmitted data local node constructs a session key and uses ETA encryption and authentication with it. The CTR-type AES encryption is used to reduce block size. Key generation, packing, encryption and decryption are implemented in the SymmetricKey class which must be used to process keys and encryption.
The local party should generate new session keys periodically, but not too often as guaranteed strength is more than one year..
The protocol has two phases: handshake and data exchange. Usually the local starts with the handshake unless it knows the actual session key assumes it is still valid.
This procedure starts by sender when:
- Sender knows no session key for remote
- Sender can't decrypt data from the remote (HMAC fails with the current session key
The procedure is started by the local party:
|HELLO||Local node asks remote to provide the session key|
|Remote node generates new random nonce, rnonce, to check local node operates its private key||WELCOME,rnonce|
|KEY_REQ,signed(rnonce,lnonce)||Local node generates own nonce, lnonce, signs (lnonce, rnonce) an signs it with its private key|
|Remote node checks signature and rnonce. On error does nothing1. Transmit session_key||SESSION,encrypted(session_key,lnonce)|
|Local node checks signatures and goes to exchange mode.|
Local node transmits data to the remote using ETA and session_key received during the handshake.
Local node protocol adapter (local) receives binary data blocks from the sending queue, packs them into the payload so the full transmitting buffer size should not exceed the maximum size DatagramAdapter. MAX_PACKET_SIZE, usually 512 bytes. Local does not wait for the input data to reach any minimum size and sends them as soon as possible.
Each data block receives sequential blockId, is packed with local and remote node ids and transmitted as an UDP datagram to the remote node listening port. The sent block is kept by the sender in the retransmitted queue until receiving the ACK with its number. Not ACK'd block should be retransmitted after a specified timeout. After maximum attempts to retransmit the block it is discarded. The local node does not transmit data blocks in the handshake mode (buffers them) and/or if the retransmit queue reach some capacity.
If the local party receives NACK, it turns to handshake immediately, keeping suspended retransmit queue, clearing retransmit attempts counters in it.
Overflow condition. If the sending queue grows above the maximum size, the overflow flag is set, and oldest data are removed from the buffer. Overflow mode does not alter retransmission queue but silently discards oldest data from the sending queue.
MAX_QUEUE_SIZEmaxmimum number of data blocks in the sending queue after which oldest items are discarded and overflow flag is set. Defaults to 50.
RETRANSMIT_MAX_ATTEMPTSmax number of attempts to re-transmit a block, defaults to 10
RETRANSMIT_TIME, time between attempts to re-transmit a DATA block
All data should be encoded with BOSS conserving space as much as possible. Recommended block structure is the array:
Where payload object is in turn an array with corresponding data, for exmaple, WELCOME block could be encoded like:
[101,717,4,[<64 random bytes>]]
Where 101 is a sending node id and 717 is a receiving node it.
Note that BOSS effectively packs integer depending its magnitude, so small packed integer would take 1 byte, and big ones usually take as many bytes as needed to keep all significant bits + 1 header byte. So it is practical to use small integers for IDs.
For the reason of reducing packed data size it is desirable to avoid usage of the key-value pairs (maps) in data in favor of arrays as described above.