Protocol

The protocol is divided into two parts: message formats and the actual protocol. The protocol and message formats are under development, so this represents the current spec.

Messages

The RadioHead library’s RF95 driver limits messages to 251 bytes. Note that this driver sends unaddressed and unreliable datagrams; there are manager classes to implement reliability and encryption, but they’re not quite suitable. The firmware doesn’t define these, but a prototype message structure might look like:

struct Message {
    // Header
    uint8_t net;
    uint8_t from[4];
    uint8_t to[4];
    uint8_t type;
    uint8_t time[7];
    uint8_t signature[64];

    // Body
    uint8_t message[170];
}

The RF95 driver does provide CRC checks on packets, so that doesn’t need to be built in.

Addressing

The from and to fields are the 32-bit node IDs as stored in each node’s identity, sent little-endian. The from field should always contain a valid node ID, but a to address of 0 indicates a broadcast message. There is a further filter, net, that identifies which net (or group) the message is intended for. The net ID 0 indicates either all nets (for broadcast messages) or direct communications between only a pair of nodes.

Message security

A node’s identity key is used to sign all messages; the signature is done over all the other header fields and the message body. This is used to establish authenticity; nodes can use their address book to verify that the public key for a given node ID matches the signature.

Message traffic (e.g. messages not intended for control) are encrypted using a traffic encryption key (TEK), established with a key exchange sequence.

Nets are a little more complex: the node that establishes a net generates a TEK for the net, and sends this TEK to each node that is invited to the net. Other nodes can also send invites to the net by sending another node the net’s TEK.

TEKs have a limited lifetime: 90 days or 6500 messages (just over a megabyte of data). This limit is arbitrary and subject to change during the refinement and development of the protocol.

The address book

Nodes should maintain an address book (e.g. on the SD card) that contains entries correlating node IDs, public keys, TEK parameters, and optionally a friendly tag.

TEK parameters contain keys, messages counts, and rollover time:

struct TEKParameters {
        uint8_t       ready;
        uint8_t       key[32];
        uint16_t      count;
        datetime      expires;
};

The ready field should be set to true once the parameters have been filled in. It allows a faster check to determine if a key exchange with a valid TEK has occurred. The key field contains the TEK, count should store the message count, and expires contains the datetime when the key should be rolled.

The address book incorporates these parameters with the other node details:

struct Address {
        uint8_t               tag[15];
        uint8_t               pub[32];
        uint32_t              id;
        struct TEKParameters  tekp;
};

The tag field is used to store a user-friendly name for a node, which would be set in the node management software. The pub field contains the node’s public key, and id stores the node’s public key.

Message types

  • ADV: Advertisements are sent to net 0 with the broadcast node ID; this is how nodes share their public keys. The message body is the 32-byte Ed25519 public key for the node. Nodes may elect to send advertisements at regular intervals with a minimum of five minutes between advertisements.
  • WHO: Who requests are sent to ask all receiving nodes for their public keys (e.g. sent to the broadcast address). Alternatively, they may be addressed to a node to ask a specific node for its public key. Responses are optional; a node may elect not to respond (e.g. for power conservation).
  • KEXSYN: Key exchange sync is sent directly to another node to set up a traffic encryption key (TEK). The message is a 32-byte public key that the receiving node uses to derive a secret key and a 7-byte expiration on the key exchange.
  • KEXACK: Key exchange acknowledgement is sent by the node that receives a KEXSYN. It contains the public key to be used in deriving a TEK. Once this is sent, both sides have a TEK for direct messaging.
  • INVITE: invitation to join a group. Direct key exchange must be set up.
  • MSG: standard message.
  • REKEY: roll a TEK.

Open questions

  • What data structure makes the most sense for the address book, balancing usability with memory and program space requirements?
  • How should the address book deal with nets?
  • How should network reliability be handled? The system right now defaults to a UDP-esque model; would making it reliable require too much bandwidth or dwell time?