If You Must Use Signal, Use Molly

While I’m critical towards the Signal messenger, I understand that network effects are strong and even though many people would much rather prefer a different platform, it’s not easy to get friends and family onto something better. In this brief write-up, I’ll introduce an alternative Signal client to make using Signal at least slightly less troublesome.

If You Must Use Signal, Use Molly

If you’re a regular on this journal, you might know that I’m not exactly a big fan of Signal and prefer to use more free (as in free speech, not free beer) and ideally decentralized messengers. While Signal is widely praised for being focused on privacy and security, there are many things to criticize:

The centralized control over its servers and the development process, its collection of metadata (Attachment A in Our Response), its vendor lock-in that makes it hard to switch phones and pretty much impossible to switch ecosystems (e.g. iOS to Android) without losing all message data, its awful Electron-based desktop client, and last but not least the phone number requirement, which still is a requirement, even with the new usernames feature.

Fun fact: Signal has not updated the Big Brother page since the end of 2021. On that page, Signal promised to disclose transcripts of their communication with government law enforcement agencies. The time frame in which Signal stopped publishing on this page interestingly coincides with the global roll-out of MobileCoin.

While I can afford to be relatively strict in regard to the communication platforms that I’m using, many people cannot, due to their dependence on peers who are often unwilling to move to a different platform. This network effect is particularly strong with messengers like Apple Messages (formerly known as iMessage) and, especially in the global south, as well as underdeveloped regions, WhatsApp. For the handful of people who however made the switch to Signal, it’s a hard sell to install yet another messenger for communicating with their only tinfoil-hatter friend, who detests WhatsApp and isn’t particularly happy with Signal either.

Especially with the introduction of Stories and MobileCoin, many people seemingly tried to leave the Signal ecosystem but eventually returned due to the network effect. This brief write-up is targeted at those who need to use Signal even though they aren’t particularly keen on it and are looking for ways to make having Signal installed on their phone less troubling.

Let me introduce Molly, the independent Signal fork for Android.

Molly

Molly is an independently developed fork of the Signal for Android app, that aims to fix some of the most pressing issues of the official client. It’s basically a hardened version, offering features that the official Signal app does not have and probably never will.

Let’s dive into Molly’s feature set and compare the most critical ones with the official Signal Android app.

Info: When I refer to Molly, I’m referring to the Molly-FOSS app.

Encryption at Rest

The official Signal app uses an SQLCipher database to store data like contacts, chat history, and attachments, using a random AES-256 key that is generated when the app is run for the first time.

This key is stored in the Shared Preferences, which are XML files stored along with the database itself. The official Signal app relies on Android’s KeyStore to be available to wrap the otherwise plain-text key before writing it into the XML files.

Molly on the other hand encrypts Shared Preferences using AES-256-CBC, where the preference name and encrypted value are hashed with HMAC-SHA256 and stored together with the encrypted value. The Shared Preferences encryption key is protected with a dedicated passphrase set by the user, and run through Argon2id (KDF) with a random salt. The passphrase is wiped from memory after hashing it and the KDF algorithm is calibrated so that one attempt takes approximately three seconds.

Additionally, to discourage brute-force attacks, the output of Argon2 is entangled with 256-bit MAC keys tied to the Android (6.0 or newer) KeyStore. On devices with hardware-backed crypto services, the MAC key is generated randomly inside the Secure Element when Molly sets up the encryption. The key never leaves the Secure Element chip.

Last but not least, Molly prevents users from creating weak passphrases by detecting common patterns (words found in a dictionary, common character substitutions, common patterns, and repeated sequences) and outputting hints for improving passphrase security.

Push Notifications

If you’re like me and you run a privacy-focused Android ROM that doesn’t integrate with any of Google’s cloud services, like Google Cloud Messaging/Firebase Cloud Messaging (or GCM/FCM), you know that getting push notifications to work is tricky. Up until recently, most apps that offered a way for push notifications outside of GCM/FCM typically kept a persistent network connection to their servers open, and retrieved notifications from there.

If you’re refusing to use the Google Play Store and instead download the Signal APK directly from signal.org this is what you’ll get: A Signal app that will stay alive in the background even after you close it, and that will listen for new messages by keeping a connection to the Signal servers (WebSocket) open. As you can imagine, this isn’t exactly the most efficient way to do it and will have a noticeable impact on your battery life – especially as soon as you also have other apps doing the same.

Luckily these days there are other ways to have push notifications in place without depending on any big tech cloud service: UnifiedPush.

With UnifiedPush, the so-called distributor app keeps a single connection to a user-chosen (and ideally self-hosted) push server open and tunnels push notifications for all apps that support UnifiedPush through that single connection. This way, your phone only has to maintain a single open connection rather than one for each that might offer push notifications outside of GCM/FCM.

One successful example of this is the Element/Element X which can use UnifiedPush for push notifications. The official Signal Android app, however, does not support UnifiedPush and probably never will. Because that’s what you get when development is centralized and driven by probably pRoDuCt MaNaGeRs, who lack an understanding of why things like these are important to people.

Molly, on the other hand, fully supports push notifications via UnifiedPush and hence does not need to include all the garbage code that is GCM/FCM related. All you need for that is a distributor app and a server running MollySocket.

I am using Conversations as a distributor on my Android since it’s connected to my XMPP account anyway, but you’re free to pick nfty for a more lightweight alternative that doesn’t require any account.

For the MollySocket server component, you could make use of an OpenBSD VPS on Vultr, which would let you run MollySocket as well as other similar services, like xbsapi. Installation of MollySocket is as easy as it gets on OpenBSD.

Installation of MollySocket on OpenBSD

First, make sure to have the rust package installed:

host# pkg_add rust

With that in place, simply use cargo to fetch the source and build the binary:

host# cargo install mollysocket --locked

Hint: If you encounter a weird Multi error, make sure to run ulimit -n 1024 and re-run the cargo command.

With MollySocket installed in ~/.cargo/bin/, you can now mv ~/.cargo/bin/mollysocket /usr/local/bin/mollysocket and create its configuration at /etc/mollysocket.toml:

db = '/var/run/mollysocket.db'
allowed_endpoints = ['*']
allowed_uuids = ['YOUR_UUID']
host = "127.0.0.1"
port = 8020

You can find out your UUID by going into Molly’s settings (click your avatar icon) and opening Notifications -> UnifiedPush. If you want multiple devices/UUIDs to connect to your MollySocket instance, add multiple UUIDs in single quotes, separated by commas.

Next, you should set up relayd as an HTTPS endpoint and reverse-proxy for MollySocket:

table <molly-default-host> { 127.0.0.1 }

http protocol molly-https {
  match request header append "X-Real-IP" value "$REMOTE_ADDR"
  match request header append "Host" value "$HOST"
  match request header append "X-Forwarded-For" value "$REMOTE_ADDR"
  match request header append "X-Forwarded-By" value "$SERVER_ADDR:$SERVER_PORT"
  match request path "/*" forward to <molly-default-host>

  tcp { nodelay, sack, backlog 128 }

  tls keypair YOUR_TLS_KEYPAIR_NAME_HERE
  tls { no tlsv1.0, ciphers HIGH }
}

relay molly-https-relay {
  listen on egress port 8083 tls
  protocol molly-https
  forward to <molly-default-host> port 8020
}

Make sure to set the correct tls keypair name of your own SSL certificate. It is usually under /etc/ssl/private/<name>.key and you only need to specify its name, without the .key extension. If you are not familiar with how to use acme-client to get an SSL certificate under OpenBSD, please refer to my write-up on running your own LastPass on OpenBSD.

With this in place, all that’s left is to create an rc file for MollySocket under /etc/rc.d/mollysocket:

#!/bin/ksh

daemon="/usr/local/bin/mollysocket"
daemon_flags="-c /etc/mollysocket.toml server"

. /etc/rc.d/rc.subr

rc_reload=YES

rc_cmd $1

You can now enable and start mollysocket and relayd:

host# rcctl enable mollysocket
host# rcctl start mollysocket
host# rcctl enable relayd
host# rcctl start relayd

In Molly on Android you can now configure your UnifiedPush Server URL to https://YOUR_HOST:8083/ and Molly should display a checkmark next to it, as well as the Status “OK”. Your push notifications should now be working through UnifiedPush, on your infrastructure!

Tor Support

Molly supports the use of a SOCKS proxy as well as Tor via Orbot. This can be easily configured in Settings -> Network and adds another layer of privacy.

RAM Shredding

Unlike the official Signal App, Molly implements an anti-forensic feature to protect against RAM acquisition and analysis, that even other Signal forks envy. To quote Oscar Mira, one of the main developers of Molly:

Basically, when Molly get locked:

  • Clears the database encryption keys from memory
  • Kills the JVM and restart itself
  • Runs the WipeMemoryService in the background

Then the wipe service allocates large chunks of memory and overwrites them with random data, until there is no more free RAM available in the device. Then it frees everything and finalize. It takes a few seconds to complete, and you can see a notification and the progress bar.

All of this is to prevent forensic RAM analysis after Molly is locked. It’s somehow a workaround to the known issue of JVM apps to overwrite its own memory.

Automatic Locking

Molly locks down the app automatically after a customizable period: The database is put back to rest (encrypted) and the RAM is shredded.

Automatic Backups

Unlike the official Signal app, Molly can backup your data automatically, and periodically. These backups can be written into e.g. a Syncthing synchronized folder to replicate them onto different devices/machines/servers. This way you can restore all Signal data in case you ever lose your phone or decide to accidentally wipe it.


If you like what Molly offers and would like to migrate from the official Signal app to it, there’s a step-by-step tutorial in the official Molly Wiki on how to do so.

Happy messaging, and remember: Use Tor. Use Signal Molly.


Enjoyed this? Support me via Monero, Bitcoin, Lightning, or Ethereum!  More info.