unMessage

What is it?

Overview

unMessage is a peer-to-peer instant messaging application designed to enhance privacy and anonymity.

Warning

unMessage is alpha software. While every effort has been made to make sure unMessage operates in a secure and bug-free fashion, the code has not been audited. Please do not use unMessage for any activity that your life depends upon.

Features

Installation

Make sure that you have the following:

# If using Debian/Ubuntu
$ sudo apt-get install build-essential gcc libffi-dev python-dev tor tkinter

# If using Fedora
$ sudo yum install gcc libffi-devel python-devel redhat-rpm-config tor tkinter

If you use pip and setuptools (probably installed automatically with pip), you can easily install unMessage with:

$ sudo pip install unmessage

Launch unMessage with any of the commands:

$ unmessage-gui # graphical user interface (GUI)
$ unmessage-cli # command-line interface (CLI)
$ unmessage # last interface used

Updating

If you installed unMessage with pip, you can also use it for updates:

$ sudo pip install --upgrade unmessage

Usage

unMessage offers usage instructions for both interfaces: Graphical User Interface (GUI) and Command-line Interface (CLI).

Persistence

All files used by unMessage are saved in ~/.config/unMessage/

Graphical User Interface (GUI)

Launch unMessage’s GUI with:

$ unmessage-gui

You are taken to the Start Peer tab and you are required to pick any name you wish to use and press Start:

_images/start-gui.png

Start Peer window

Tor is launched and if this is the first time you use that name, your Onion Service and Double Ratchet keys are created and you are ready to receive and send requests to initialize conversations. unMessage displays this bootstrap process:

_images/bootstrap-gui.png

Bootstrap window

The Copy buttons at the top bar can be used to copy information the other peers need to send you requests. You must share both your identity address and key:

charlie@jt6zabesvrhxvhee.onion:50001 v4kU6s+NuJW/Znbjz0AxoI9Gvl1XDS5eiOTm6cE38E4=

Sending Requests

Press the New chat button at the top bar to open the Request window. Provide the identity address and key of the peer you wish to contact:

_images/req-send-gui.png

Outbound request window

An identity address is provided in the format <name>@<onion address>, where the <name> is only a local identifier of the peer and you can pick any name you wish to call them.

Receiving Requests

Inbound requests are notified in a new window with the information of the peer who sent the request:

_images/req-accept-gui.png

Inbound request window

As mentioned previously, peer names are local and when accepting a request you can pick another one to call them instead of using the one they sent.

Chatting

unMessage creates tabs for each peer you have a conversation with. Within each tab, besides composing messages and sending (clicking Send or pressing the Enter key) there are some actions available.

_images/msg-gui.png

Chat tab

Notifying Presence

If you wish to notify the peer whenever you go online or offline, check Send Presence and unMessage will start to send them notifications of these events.

Verifying

If you have some secure communication channel established with the other peer, ask them for their unMessage public identity key. Click Verify and enter the key:

_images/verify-gui.png

Verification window

If the key matches, the peer will be verified and now you have established a verified and secure communication channel:

_images/level-verify-gui.png

Verified conversation

Authenticating

The authentication of a conversation works by prompting both peers for a secret (which was exchanged through some other secure channel) and if the secrets provided match, they are sure they are chatting with the right person. Click Authenticate and provide the secret:

_images/auth-gui.png

Authentication window

An authentication session is created when the secrets are exchanged and is valid until one of the peers disconnect. When it happens, the conversation is not authenticated anymore and a new session must be initialized when the peers reconnect.

_images/level-auth-gui.png

Authenticated conversation

Assuming that one of the peers might be an attacker, this process is done with the Socialist Millionaire Protocol by comparing the secrets without actually disclosing them.

Authentication Levels

As noticed, unMessage conversations have three authentication levels:

  1. Unverified Conversation
  2. Verified Conversation
  3. Athenticated Conversation

When the conversation is established, its level is Unverified Conversation because unMessage does not know if you are sure that the peer’s identity key is actually theirs.

If you follow the Verifying section, the level changes to Verified Conversation and it persists for as long the conversation exists.

If you follow the Authenticating section, the level changes to Athenticated Conversation and it persists for as long the session exists. Once the session is over, the level drops to the identity key’s verification level: Unverified/Verified.

Important

The Authenticated level is stronger than the Verified level because the former is a short term verification that lasts only until the peers disconnect, while the latter is long term that lasts until the conversation is deleted (manually, by the user). That means that with a short term verification you are able to authenticate the peer at that exact time, while a long term verification means that you authenticated the peer in the past, but is not aware of a compromise in the future.

This feature aims to increase unMessage’s security by identifying an attack that is not covered by the scope of the Double Ratchet Algorithm: compromised keys.

Relaunching unMessage

unMessage remembers the last User Interface and Peer that you used. If you wish to use a shortcut, you may call:

unmessage

Command-line Interface (CLI)

To launch unMessage’s CLI, pick any name you wish to use and call it with:

$ unmessage-cli -name <name>

Tor is launched and if this is the first time you use that name, your Onion Service and Double Ratchet keys are created and you are ready to receive and send requests to initialize conversations. unMessage displays this bootstrap process:

_images/bootstrap-cli.png

Bootstrap lines

After unMessage is launched, you can call /help to display all the commands the CLI responds to:

_images/help-cli.png

/help command

The /peer, /onion and /key commands can be used to copy information the other peers need to send you requests. You must share both your identity address and key:

bob@a7riwene46w3vqhp.onion RefK+9vx3GZpclb/On95iJ1QnxqkUeq/JBYqK5gHFwo=

Sending Requests

Use the /req-send command to send a request, providing the identity address and key of the peer you wish to contact:

_images/req-send-cli.png

/req-send command

An identity address is provided in the format <name>@<onion address>, where the <name> is only a local identifier of the peer and you can pick any name you wish to call them.

Receiving Requests

Inbound requests are notified, with the information of the peer who sent the request:

_images/req-accept-cli.png

/req-accept command

As mentioned previously, peer names are local and when accepting a request you can pick another one to call them instead of using the one they sent.

Chatting

unMessage diplays each peer you have a conversation with by calling the /convs command.

_images/convs-cli.png

/convs command

To send a message to a peer, use the /msg command:

_images/msg-cli.png

/msg command

Notifying Presence

If you wish to notify the peer whenever you go online or offline, use the /pres-on command and unMessage will start to send them notifications of these events:

_images/pres-on-cli.png

/pres-on command

To disable, use the /pres-off command.

Verifying

If you have some secure communication channel established with the other peer, ask them for their unMessage public identity key. Use the /verify command and enter the key:

_images/verify-cli.png

/verify command

If the key matches, the peer will be verified and now you have established a verified and secure communication channel.

Authenticating

The authentication of a conversation works by prompting both peers for a secret (which was exchanged through some other secure channel) and if the secrets provided match, they are sure they are chatting with the right person. Call the /auth command and provide the secret:

_images/auth-cli.png

/auth command

An authentication session is created when the secrets are exchanged and is valid until one of the peers disconnect. When it happens, the conversation is not authenticated anymore and a new session must be initialized when the peers reconnect.

Assuming that one of the peers might be an attacker, this process is done with the Socialist Millionaire Protocol by comparing the secrets without actually disclosing them.

Authentication Levels

As noticed, the names of the peers are colored based on the conversation authentication levels:

  1. Unverified Conversation (red)
  2. Verified Conversation (green)
  3. Athenticated Conversation (cyan)

When the conversation is established, its level is Unverified Conversation because unMessage does not know if you are sure that the peer’s identity key is actually theirs.

If you follow the Verifying section, the level changes to Verified Conversation and it persists for as long the conversation exists.

If you follow the Authenticating section, the level changes to Athenticated Conversation and it persists for as long the session exists. Once the session is over, the level drops to the identity key’s verification level: Unverified/Verified.

Important

The Authenticated level is stronger than the Verified level because the former is a short term verification that lasts only until the peers disconnect, while the latter is long term that lasts until the conversation is deleted (manually, by the user). That means that with a short term verification you are able to authenticate the peer at that exact time, while a long term verification means that you authenticated the peer in the past, but is not aware of a compromise in the future.

This feature aims to increase unMessage’s security by identifying an attack that is not covered by the scope of the Double Ratchet Algorithm: compromised keys.

Relaunching unMessage

unMessage remembers the last User Interface and Peer that you used. If you wish to use a shortcut, you may call:

unmessage

Note

unMessage’s CLI is inspired by xmpp-client.

unMessage Protocol

The unMessage protocol is based on the Double Ratchet Algorithm to establish conversations and exchange messages privately and anonymously.

Note

unMessage uses Tor Onion Services to anonymously connect peers as we believe that it is the best transport for this kind of application, but other approaches such as posting the packets to a public mailing list should also work (as long as the packets are anonymously posted).

In the Double Ratchet Algorithm, a secret key must be agreed on to derive all the other keys involved in the conversation. The secret key used by unMessage is generated with the Triple Diffie-Hellman Key Agreement, using one party’s public identity and handshake keys, and another’s private identity and handshake keys.

Each party must have its mode assigned to as either Alice or Bob. The one who starts the initialization is Bob and can send messages right after the secret key is generated. As part of the initialization, Bob must send his public ratchet key to Alice so that she is able to start the Diffie-Hellman ratcheting and also send messages immediately.

unMessage conversations have the following stages:

  1. Request sent
  2. Request accepted
  3. Conversation established

In order to send requests, both parties must launch unMessage to generate their Onion Service and Double Ratchet keypairs. unMessage is a serverless application, so a peer who wishes to receive requests must send/publish their Onion Service address and Double Ratchet public identity key through some other communication channel.

unMessage assigns Bob to the one who sends a request and Alice to the one who receives it.

Important

In the following sections, the shared request key and conversation ID are described as the direct input of hash and encryption functions for simplicity. In fact, these keys are input of a Key Derivation Function (KDF) along with its respective salt, and the output keys of the KDF that are actually used by such functions.

Stage 1: Request sent

A request keypair is generated by Bob’s unMessage to derive a Diffie-Hellman shared request key using the private request key and Alice’s public identity key. The shared request key, is used to encrypt the following information needed by Alice to initialize a conversation with Bob:

  • Bob’s identity address
  • Bob’s identity public key
  • Bob’s handshake public key
  • Bob’s ratchet public key

This set composes the handshake packet, which after encrypted is used to compose the request packet:

  • IV
  • hash(IV + Alice’s public identity key + shared request key)
  • keyed_hash(shared request key, encrypted handshake packet)
  • public request key
  • encrypted handshake packet

The packet is then sent to Alice’s Onion Address and Stage 1 is completed.

Important

The handshake packet should be signed by the Onion Service and Double Ratchet keys so that a peer cannot advertise keys they do not own. This will be implemented in a future version of unMessage.

Stage 2: Request accepted

After receiving the request packet, Alice’s unMessage derives the shared request key using Alice’s private identity key and the public request key. The shared request key is hashed with the IV and the handshake packet to make sure that is indeed an unMessage request packet and the handshake packet can be decrypted. Alice is notified that the request was received from Bob and accepts it to initialize the Double Ratchet conversation.

Bob’s public identity and handshake keys sent in the handshake packet are used to generate the Double Ratchet secret key with Alice’s private identity and handshake keys (the former was generated when unMessage was launched by the first time and the latter when the request was accepted, to be used for this specific conversation). The Double Ratchet conversation is finally initialized using the secret key and Bob’s public ratchet key (also sent in the handshake packet). At this point, Stage 2 is completed and Alice can start sending encrypted messages. However, as Bob does not have Alice’s public handshake key, it is encrypted (using the shared request key) and sent along with the unMessage reply packet:

  • IV
  • hash(IV + Bob’s public identity key + shared request key)
  • keyed_hash(shared request key, encrypted handshake key + encrypted payload)
  • Alice’s encrypted public handshake key
  • encrypted payload

Stage 3: Conversation established

When messages from Alice are received, Bob’s unMessage hashes the shared request key with the IV and Alice’s encrypted public handshake key concatenated with the encrypted payload to make sure that is indeed an unMessage packet from Alice, and her public handshake key can be decrypted. Bob now can also generate the secret key with his private identity and handshake keys, and Alice’s public identity and handshake keys. With his part of the conversation initialized, he can start sending unMessage regular packets:

  • IV
  • hash(IV + Alice’s public identity key + conversation ID)
  • keyed_hash(conversation ID, encrypted payload)
  • encrypted payload

Stage 3 is completed when Alice receives a regular packet from Bob, which means that he was able to initialize the conversation with her public handshake key and there is no need to send reply packets anymore, so her unMessage also starts sending regular packets.

Identifying conversations

All of the identifying information of an unMessage packet is encrypted so that an attacker who intercepts it cannot tell who are the receiver and sender.

When a packet is received, unMessage assumes it is a regular packet and attempts to use all of the peer’s conversation IDs to derive the IV hash. If the hash matches the packet’s IV hash, unMessage identifies the sender and is able to decrypt the payload (after verifying its integrity). If the IV hash does not match, unMessage assumes the packet is a request packet and derives a shared request key using the public request key from the packet and the peer’s public identity key. unMessage attempts to use the shared request key and the IV to derive a hash that matches the packet’s IV hash. If it matches, unMessage checks the integrity of the rest of the packet and processes the request as described in Stage 2.

When unMessage fails to identify or check the integrity of packets, they are ignored.

Note

The IV hash also uses the receiver’s public identity key as part of the hash so that, for example, Alice can tell the difference between messages she sent to Bob and messages she received from Bob.

The IV hash is another implementation of an hSub.

Other

Changelog

unMessage 0.1.0, released 2017-01-22

  • Initial commit

Feedback

Please join us on #unMessage:anemone.me or #anemone:anemone.me with Matrix, #anemone at OFTC, or use the GitHub issue tracker to leave suggestions, bug reports, complaints or anything you feel will contribute to this application.