To add someone as a contact you have to meet up in person and scan QR codes from each other's screens. The QR codes contain data that allows your devices to connect to each other and verify that they're connected to the right device.
The devices exchange public keys and derive a shared secret. Then they upgrade to a secure connection, exchange Briar identities, and verify that the identity they've received belongs to the user of the other device.
An identity consists of a nickname that you choose when creating your account, and a public key that's used for signing messages. There's nothing to stop users from choosing the same nickname, so we call it a nickname rather than a username.
Once the devices have exchanged and verified identities, you and the other user are added to each other's contact lists.
Connecting to contacts
Your device will only connect to your contacts, not to any other users, and it will only accept connections from your contacts.
You can communicate with your contacts over various transports: the Android version of Briar supports Tor, wifi and Bluetooth, and the desktop version will also support memory sticks and dialup modems (useful during internet blackouts).
Your device exchanges data with your contacts' devices about how to connect over each transport. For example, when you're connected to wifi, your phone opens a socket and listens for connections, and it sends the IP address and port number of the socket to your contacts so they can connect if they're on the same wifi network.
Each transport is implemented as a plugin, which has a simple interface for making and accepting connections. Plugins aren't responsible for authenticating the devices they communicate with or securing the data that's transferred. They just make connections.
The security of the data (authentication, confidentiality, integrity and forward secrecy) is handled by the transport security protocol, BTP. The same protocol is used for all transports.
BTP is an obfuscated protocol: to anyone except the intended sender and recipient, all data is indistinguishable from random. So BTP's first job is to let the recipient know who sent the data, so the recipient can use the right key to authenticate and decrypt it.
This is done by attaching a pseudo-random tag to the data. The sender and recipient generate identical sequences of tags, and the sender uses each tag for one stream of data. The recipient recognises the tag, removes it from her sequence, and uses the corresponding key to authenticate and decrypt the stream.
Each tag is only used once, and nobody except the sender and recipient can distinguish the tags from random.
The recipient keeps a sliding window containing the next few expected tags, so she can recognise streams that arrive out of order if the transport loses or reorders connections.
The sender and recipient keep two keys for each transport: one for generating tags and the other for authenticating and encrypting streams. These keys are rotated periodically to provide forward secrecy.
The length of the rotation period depends on the latency of the transport. (We don't want to delete a key while a stream is still on its way from the sender to recipient, otherwise the recipient won't be able to recognise or decrypt it.)
The rotation period also depends on the maximum possible clock difference between the devices. (We don't want to delete a key that our contact's still using due to an inaccurate clock.)
Clocks on consumer devices can be very inaccurate because people don't always set the right timezone, so the rotation period is at least 24 hours for all transports. For high-latency transports like memory sticks (which might be hidden in someone's shoe and smuggled across a border) we'll use a longer rotation period, maybe 4 weeks.
Once the recipient has recognised the tag, she uses the corresponding key to authenticate and decrypt the stream header, which contains a single-use key for authenticating and decrypting the rest of the stream.
BTP streams can carry any kind of data, but we use them to carry a data sync protocol called BSP. Its job is to synchronise chunks of immutable data between pairs of devices.
Each chunk of data is called a message, and it's addressed to a group. A group is just a label that devices can subscribe to. It works much like a Usenet newsgroup.
You can create a group that's just stored on your own device, or shared with one other user, or with a known set of users, or an open-ended set of users that may contain people you don't know.
BSP doesn't understand the content of messages or the purpose of each group. It just syncs the messages in the group with whichever contacts you've chosen to share the group with.
It does this by exchanging four types of record with your contacts: offers, requests, messages and acks.
An offer contains the unique IDs of some messages in groups you've shared with the contact. The contact responds by requesting any messages she hasn't seen and acking any messages she has seen. You send any messages the contact requested, and the contact acks them.
When operating over a unidirectional transport like memory sticks, we skip the offer and request stages and just send any messages the contact hasn't previously acked. This cuts down the number of round-trips.
If we don't get a response to an offer or message after a certain amount of time, we assume it was lost and retransmit it. The timeout depends on the latency of the transport and the number of times we've offered or sent the message.
BSP doesn't know what a valid message looks like for each group, or how to determine the relationships between messages. All of that is handled by a sync client, which is an application (or part of an application) that makes use of BSP and BTP to sync data with contacts.
For example, private messaging is a sync client. When the sync layer receives a message addressed to one of the client's groups, it passes the message to the client for validation. The client parses the message, extracts any dependencies on other messages and returns them to the sync layer. When all the dependencies have been received, the message is passed back to the client for processing (this is called delivery).
The client is also responsible for deciding which groups to share with which contacts. This is how Briar handles sharing blogs, forums and private groups, and ensures that private messages are only shared with a single contact.