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’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 runulimit -n 1024
and re-run thecargo
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.