Devices
To facilitate end to end encryption in Towns, each(user, client instance) tuple is associated with a deviceId, which identifies that device and is used to establish peer-to-peer encrypted sessions for the purpose of sharing group message encryption keys.
Devices are objects storing key material created on the client and stored in the Towns Node on the user’s UserDeviceKey stream containing the following pair of keys:
- Curve25519 peer-to-peer encryption key - A long-lived Curve25519 asymmetric key pair is created with a new device of a user. The private portion of this key never leaves the device, while the public portion is stored in the user’s
UserDeviceKeystream. This key along with the following key are used by other user’s to establish secure and ephemeral p2p sessions. - Curve25519 fallback key - A second Curve25519 key pair is created using the encryption key and published to a user’s UserDeviceKey stream. For Alice to establish a new secure p2p encrypted session with Bob, Alice would use her encryption key along with Bob’s public key portion of his encryption key and fallback key.
Device lifecycle is outside of the purview of the Towns protocol and managed entirely by client implementations. However, given it is expected under the protocol that there exists a 1-1 relation between(user, client instance)tuples anddevices, the Towns Node performs periodic compaction criteria to stem the uncontrolled growth of user’s device key stream in storage.
Encryption Data Schemas
Encrypted data originating from messages or metadata, such as usernames, is described in the protocol with a protobuf message as follows.session_id is used to identify the keys associated with the ciphertext, which can be used to decrypt the same message multiple times. This is particularly useful in a group messaging application as it avoids the need to re-establish peer-to-peer encrypted sessions
for each message.
Peer to peer encryption sessions are only used to transmit session keys corresponding to message events and are described by the following protobuf in the protocol.
outbound sender’s session was created for. In general, peer-to-peer encrypted messages are encrypted in a per device basis.
Encryption Lifecycle
Below is an example of the encryption lifecycle between Alice and Bob who are co-members of a channel within a space.- Alice logs in to her client, creates a new
device, and joins a Space. - Bob who is already logged in and a member of the Space sees a
KeySolicitationmessage with adevice_keycorresponding to Alice’s device. - Bob validates that Alice
isEntitledto decryption keys for the channel stream that the solicitation event appeared in and creates a new p2p encryptedoutboundsession using Alice’s device key and fallback key to transmit the keys requested from his local cache. - Bob sends an
ackto the stream to notify other co-members of the channel that Alice’s request is being worked on. - Alice sees Bob’s message on her
UserToDevicekey stream and created a newinboundsession with Bob’s device key and fallback key obtained from hisUserDeviceKeystream. - Alice decrypts Bob’s message and extracts the key material storing it in her local cache.
- Alice attempts re-decrypting the channel messages that share the
session_idof the keys she now has in her possession.
Peer-to-peer encryption in Towns requires distinct sessionsoutbound,inboundfor encryption and decryption, respectively. Moreover, each message can only be decrypted once per established session.
Key Sharing
Active Sharing
Session keys to encrypt message events and metadata in Towns are created on an as-needed basis by clients. If a user is joining a channel and decides to subsequently send a message for the first time, they will create a new outbound session key to encrypt the message and send it to the member roster of the channel along with the message. The same key can be used as an inbound session key by other members to decrypt the message encrypted with that session.Passive Sharing
The above contrasts with passive key sharing, which is used to transmit keys that users are entitled to but do not have locally. When joining a channel for the first time, a user will sync stream events, but will need session keys to decrypt message events. The protocol supports an efficient key sharing scheme that has users place anKeySolicitation event on the stream, which any online member of the stream will see and conditionally service if the solicitator is an entitled member of the stream.
Data
The protocol allows for any stream to support key sharing by way ofKeySolicitation, and KeyFulfillment messages. Since fulfilling a solicitation requires creating a peer-to-peer encrypted session with the solicitator, the device_key and fallback_key are added to the payload to save a lookup against the UserDeviceKey stream. Fulfillments are synced by members of the same stream to avoid the worst case behavior of every member fulfilling every request in a duplicative manner.