yujiri.xyz

The Sufec protocol

Me and my friends are making a messaging protocol and calling it Simple User Friendly Encrypted Chat.

Rationale

Secure messengers have been popping up like crazy in recent years. Matrix. Signal. Threema. Wire. Session. Briar. Tox. Jami. I can't even list all the ones I investigated in my search before deciding to make another. Sufec is necessary because all of these have fallen short in one or more ways:

Et cetera.

Use cases

One thing Sufec tries to do that most secure messengers don't is replace email. You can message a Sufec user without having to "send a contact request" or "invite them to a DM"; "conversations" or "rooms" are not even first-class things.

Besides the general impetus to minimize the number of applications necessary for digital life, a pressing reason to want to replace email is that it's ubiquitously used for sensitive things such as password reset codes. That our society's standard is to send such things unencrypted is a travesty.

Sufec has no provisions for unencrypted messaging; we think that belongs in a different protocol.

What Sufec is not

Security model

Sufec should provide:

Protocol

Sufec is formally a federated protocol, similar to email. A user has a *homeserver* through which they receive messages, and a long-term public/private key pair, whose public part is their ID. There are no human-readable usernames as there are in email; your Sufec address is `<id>@<server>`, not `<name>@<server>`.

Unless otherwise stated, all numbers are serialized in big-endian format.

Handshake

Each Sufec message is encrypted with a key derived from the long-term key pair and an ephemeral key pair from each party (this is based on the Signal handshake and is supposed to have the same properties):

Explanation of the Signal handshake

(This is where the handshake differs from Signal, by the simplistic use of XOR instead of a special key derivation function. I conjecture that XOR is as secure as any other way of combining them, since all inputs are secret, it's irreversible, and produces no statistical anomalies such as non-uniform probability distribution.)

Connecting to a homeserver

Every interaction with a homeserver starts by connecting to it over TCP port 49002. The server sends its public key for transport encryption, which the client handles with TOFU (trust on first use) policy: remember the public key when connecting to a server for the first time, and alert the user on subsequent connections to the same server if the key ever changes.

While reading the sections for each type of conversation you can have with a homeserver after receiving its public key, bear in mind:

Sending a message

1. Send a byte with value 1 to indicate you are connecting to send.

2. Randomly generate a symmetric session key, anonymously encrypt it to the server's public key, and send. This doesn't authenticate the client because sending is meant to be anonymous. From this point on, all transmissions are encrypted with the session key.

3. Send the ID of the recipient.

4. The server concatenates the ephemeral keys of each device the recipient has linked, encrypts that with the session key, and sends it (preceded by its length). If the recipient ID is not found, the server should respond with 0 for the length, indicating "0 linked devices", and the client should abort and show an error message.

5. For each of those keys: encrypt the message with that key (as described in the Handshake section), then anonymously encrypt the following concatenation to the recipient's ID (so their homeserver can't read the metadata), then send the result as a single encrypted unit (preceded by its length):

6. Once it receives such a payload for each key, the server sends an arbitrary 1-byte receipt to indicate delivery was successful.

Receiving messages

1. Send a byte with value 0 to indicate you are connecting to receive.

2. Encrypt your ID anonymously to the server's key and send that.

3. Do a handshake with your ID and the server's key to arrive at a symmetric session key. From this point on, all transmissions are encrypted with the session key.

4. Generate a new ephemeral keypair for receiving, and send your device ID followed by your new ephemeral key.

5. The server will send you any messages that were stored for you. Each message is sent as the following concatenation (preceded by its length):

6. After each message, you send back an arbitrary 1-byte receipt to indicate the receipt was successful.

The connection stays open and the server will send any new messages that arrive.

When an unrecognized client connects to receive, the server should treat this as a registration and create the mailbox.

Add a device

To add a new device to your account, simply copy over the long-term private key and have the new device generate its own device ID. The new device can then connect to the homeserver in receiving mode and on seeing the unrecognized device ID, it will treat this as a newly linked device. From then on incoming messages will be stored until both devices have downloaded them.

Remove a device

You can use any device that has your private key to tell your homeserver to forget about another.

1. Send a byte with value 2 to indicate you are connecting to forget a device.

2. Performs steps 2-3 from Receiving messages.

3. Send the device ID you want to forget.

4. The server sends back an arbitrary 1-byte receipt to indicate the device was forgotten.

This is *not* a secure response to a lost or stolen device. Such a device, since it has your private key, would be able to re-add itself to your account, and even if it couldn't, it would still be able to send on your behalf, which your homeserver has no control over. If a device with your long-term private key is lost, you should generate a new identity.

The intended use of this feature is to tell your homeserver to stop storing messages for a device you don't or won't possess anymore, for example if you have a hard drive failure, if you reinstall your operating system and forgot to back up the relevant files, or if you are wiping a device preparing to give or sell it.

Message format

A Message is serialized as, in sequence:

In a group chat, each participant should, for each received message, include a hash of it with their next outgoing message, confirming that they received it. This is necessary to prevent a group member from spoofing the recipient list, secretly sending different messages to different people. For example, if A, B, and C are in a group chat and A sends a message to B that includes C in the recipient list but doesn't actually send the message to C, or sends a different message to C, then B will notice that they never receive a hash confirming that message from C, and C will notice that they never receive one from B.

In chats with only two members, this is not necessary so the number of included hashes can just be set to 0.

The exact input to hash is the serialized sender's address followed by the type indicator byte and message content.

Address format

An address is serialized as:

The homeserver name is expected to be a domain name, but can also be an IP address serialized in the standard way (dotted decimal for IPv4, bracketed colons for IPv6).

Cryptographic primitives

Sufec is based on libsodium, so:

Group chats

Group chats are implemented similarly to email: you just send your message to each recipient, and in the Message to each one, you include the list of *other* recipients. Client-side, messages with the same set of recipients can be sorted into "rooms", providing a UX not too different from what we expect from chat apps.

There is no moderation, no invite/leave/kick/ban commands, no questions about how to agree on what members are in a group.

Homeserver independence

One downside of most forms of federation is that you depend on your homeserver to interact with the network at all, and switching to a new one can be quite difficult since you need to message all your contacts and explain that you have a new address. One of the benefits of being `<id>@<server>` instead of `<name>@<server>` is that your ID is unspoofable, so when a Sufec client receives a messages from a recognized ID at a different server, it should automatically update its knowledge of that user's address (whereas in email, anybody could've made an account on a different server with the same username as your contact and tried to impersonate them). There is no need for out-of-band verification of your new identity.

Peer to peer usage

Although Sufec is a federated protocol, we intend it to be usable in a peer to peer way by having a client act as its own homeserver, and having `<id>@<ip address>` as an address. This is part of the reason for the emphasis on homeserver-independence: someone can use it in both ways, even in the same conversation, with minimal friction.

Linking a phone

Of course, one of the most convenient ways to link a phone is to have a desktop client that can show a QR code, and for every mobile client to be able to do this with every desktop client, we need a standard format for the data in the QR code. Our standard is the private key followed by the address, serialized as they are on the network.

Omitted features

Let's be straight up: Sufec is not going to have every feature you're used to having in modern chat apps. Matrix tried, and look how that turned out (there's only one client that actually implements all the features and it's... not good). Omitted features include, but are not limited to:

Omitted security and privacy properties

Note some properties one might expect that are absent:

Roadmap

Currently there is:

A Rust library

A TUI client

A server

A Java library (intended only for Android)

An Android client (at a minimally usable level)

A homeserver running most of the time with open registration: yujiri.xyz.

Our next objectives:

FAQ (these have not actually been asked)

Why not TLS for transport encryption?

Why not encrypt the intent indicator byte?

The conversation flows are sufficiently different that it would be trivial for a network eavesdropper to tell the difference anyway.

Why not use randomly generated nonces on the transport layer?

That would allow one nonce to be used twice. A network attacker, such as an evil ISP, could record certain messages, such as the 1-byte receipt you send after downloading a message successfully, and then hijack the connection and send the same receipt after each subsequent message, emptying your mailbox without letting you download the others.

Another solution would be to send not a 1-byte receipt but a hash of the downloaded message, but that would be more expensive (computation and data size) and have no relative benefit.

contact

subscribe via RSS

Proxied content from gemini://yujiri.xyz/sufec.gmi

Gemini request details:

Original URL
gemini://yujiri.xyz/sufec.gmi
Status code
Success
Meta
text/gemini; lang=en
Proxied by
kineto

Be advised that no attempt was made to verify the remote SSL certificate.

What is Gemini?