Skip to content

Binary Extensions (BEX) Draft

Joshua Achorn edited this page Nov 17, 2018 · 19 revisions

BEX is a proposed format designed to add additional functionality to Cryptodog.

Rather than replacing and/or modifying Multiparty and OTR, it uses them as a vehicle for the transmission of BEX metadata.

This is useful because many critical Cryptodog functions are unencrypted and expose metadata to passive network observers.

This draft has not yet been finalized. Feel free to offer suggestions, concerns and comments to improve it.

Format

[ 0-3 ] magic bytes
[ 4-? ] Submessage count (varint)
 [ ? + 0 ] Submessage header (varint)
 [ ? + ? ] Submessage data (length of header type)

BEX makes use of non-UTF8 binary messages (which are currently ignored by Cryptodog clients) to transmit metadata.

Since OTR does not support the transmission of 0 bytes, BEX over OTR must be encoded in Base64.

In this document, "varint" refers to a LEB-128 unsigned integer field.

"varint-prefixed string" refers to a UTF-8 encoded string prefixed by its length encoded as a varint.

Serialization of varints in JavaScript can be provided by this library: etc.

Each BEX message is prefixed with the "magic" bytes 0x04, 0x45, 0xFF to separate it from a regular Cryptodog text message.

Then, a message contains a length varint describing how many sub-messages it contains.

What follows is the submessages. Each submessage contains a header varint.

The value of this header determines the length of the submessage's body.

Submessage Types

  • 0: unknown / failure

Users should not ever send a unknown header, as it is a reserved value for handling non-BEX messages.

This message has no body.

  • 1: change color

This is a message a user sends when they want to change their display color.

This message's body is 3 bytes which are converted into a 6-character hexadecimal string, which is an HTML color code. For instance, a body 0xAA, 0xBB, 0xCC means the HTML color #AABBCC.

  • 2: ping

This message can be sent to a user to determine whether they are truly connected.

This message's body is a UUID.

  • 3: pong

This message can be sent to respond to a ping message.

This message's body is the same UUID sent in the ping message.

  • 4: composing notification

This is a message a user sends when they want to notify a peer that they are currently composing a text message.

This message has no body.

  • 5: paused notification

This is a message a user sends when they want to notify a peer that they have stopped typing.

This message has no body.

  • 6: file attachment

This message is sent when a user has uploaded a file ciphertext successfully to a BEX Attachment Server. (Refer to File Attachments to learn how to use this)

This message's body is as follows:

[0 - ?]   Prefix size (varint)
[0 - 32]  Encryption key (32 bytes)
[32 - 56] Encryption nonce (24 bytes)
[56 - ?]  File MIME type (varint-prefixed string)
[?  - ? + 16] File UUID      (16 bytes)
  • 7: text message

This message provides a special method for sending typed UTF-8 strings through BEX.

[0 - ?] Text type  (varint-prefixed string) (e.g. json, html, markdown)
[? - ?] Text value (varint-prefixed string)
  • 8: i am a bot

This message should be sent by bots to signify that they are bots, to avoid interpreting messages from other bots as commands, which can lead to an infinite cycle of bots requesting and replying to each other.

It also allows users to block all the bots in a given conversation, if they do not wish to view their messages or listen to their audio.

This message has no body.

  • 9: online status

A user sends this message to signal they are available to chat with.

This message has no body.

  • 10: away status

A user sends this message to signal they are unavailable to chat with.

This message has no body.

  • 11: elected as moderator

A user sends this message to signal they are now listening to a user's moderation commands.

This message's body is the nickname of the user that is now a moderator.

  • 12: Remove dead users

A moderator sends this message to tell their peers to remove all disconnected/borked users from view.

This message has no body.

  • 13: Set moderation table

A moderator can send this message to update a moderation table in their peer's clients.

[0 - ?] Table key    (varint-prefixed string)
[? - ?] Table length (varint)
 [? - ?] Table values (varint-prefixed string)
  • 14: Set lockdown level

A moderator can send this message to tell their peers' clients how to respond to unauthorized users.

If this message's body varint value is 0, nothing happens. If 1, only known buddies are displayed.

  • 30: WebRTC ICE Candidate

This message is used as a vehicle for WebRTC signaling data.

[0 - ?] Target user's nickname (varint-prefixed string)
[? - ?] ICE Candidate data (varint-prefixed string)
[? - ?] SDP MLine Index (varint)
[? - ?] SDP MID (varint-prefixed string)
  • 31: WebRTC SDP Offer

This message is used to signal a request to begin a WebRTC media connection to a peer.

[0 - ?] Target user's nickname (varint-prefixed string)
[? - ?] SDP Offer (varint-prefixed string)
  • 32: WebRTC SDP Answer

This message is used to signal a reply to a WebRTC SDP Offer message.

[0 - ?] Requesting user's nickname (varint-prefixed string)
[? - ?] SDP Answer (varint-prefixed string)

File Attachments

A reference Go implementation of a BEX Attachment Server can be found here: bex-attachment-server

To send a file, a user must first load it and determine its MIME type.

Choose a random integer between 2000 and 14000. This may serve as a bit of ciphertext padding to prevent the BEX Attachment Server from guessing what you are uploading based on file size.

Then, generate a 24-byte random nonce and a random 32-byte key.

Use the NaCl secretbox cryptosystem to seal the file data with the key and nonce.

Then, make a request to a BEX Attachment Server. Any Cryptodog conversation MUST have the same BEX Attachment Server URL to work.

Make a POST request to {Server URL}/upload?cl={the length of the encrypted ciphertext}

with the ciphertext as the request body.

If the upload was a success, the server will reply with 200 Status OK and a 16-byte UUID as the response.

The server may respond with the following HTTP status codes:

  • 400 Bad Request

If your request was malformed.

  • 429 Too Many Requests

If your IP has sent too many requests recently.

  • 409 Conflict

If the number of bytes received by the server did not match the ciphertext length URL parameter cl in the request.

What's the point of that parameter? HTTP already has Content-Length as a header, which should be sent with any POST upload. -GH

  • 500 Internal Server Error

If the server has run out of disk space and was unable to free any up, OR if the server is malfunctioning.

Once completed, you can send a BEX submessage like this:

 header:              file attachment (5).
 prefixSize:          (random padding varint)
 fileEncryptionKey:   (your 32-byte key)
 fileEncryptionNonce: (your 24-byte nonce)
 fileMIME:            (your file's mime type as a varint-prefixed string)
 fileID:              (the UUID you recieved from the server in binary form)

Receiving Attachments

Once you receive a BEX file attachment submessage,

You can request the Attachment Server like so:

GET /files/{fileID UUID in text representation}

If the response code is 200 OK, it will have the complete attachment's ciphertext. You can decrypt it using the NaCl secretbox cryptosystem and fields provided in the BEX submessage.

Truncate the plaintext's first prefixSize bytes. What remains is the file.

If the response code is 404 Not Found, the file has been deleted by the server to save disk space.