MITM Risks in Signal? Mitigation + Monologue

Update 11/25: I was made aware that Signal has some proprietary anti-spam code and added the TLDR.

A More Technical TLDR

I never know how much jargon I should include or how much I should explain, and as long as I’m writing I’m enjoying myself meaning I’ve been all over the place. But here’s a shortened version for those familiar with encryption.

A vanilla implementation of the Signal protocol relies on public key infrastructure to perform a handshake between devices. As you may know, a public key server can certify that any device/key belongs to an account if you have nothing more to go on than a phone number. Furthermore, at any point the server may say keys have changed and direct you to start communicating with a device other than the one you expect.

To mitigate this, the Signal app (as well as many other implementations of the protocol) permits you to verify hashes of public keys in person, verifying no shenanigans are occurring. Further, in the event keys are changed, most clients will notify you.

A quick disclaimer

I use Signal regularly. It works well and sure beats SMS, Google Chat, Telegram, or messages on Facebook via the website - which I also use because I won’t disassociate with family or friends who only use any of the latter four to communicate. As much as I’d love to exclusively be on something like Session or Briar, I don’t use either because I don’t know anybody using them - I can hardly even convince people to use Signal.

Anyway, Signal is super easy to use, works with or without Google Play services, and does a decent job at providing E2E encryption. I’m not here to say that you should stop using Signal, though if you want to avoid it that’s not wrong either. Here I’d like to talk about some potential downsides to Signal’s phone number requirement, specifically how it exchanges and handles keys based on accounts instead of keys themselves and how you can mitigate them.

Last, I’m not a cryptography expert. I have a basic understanding of cryptography, and the Signal Protocol itself, but if you asked me to compare the elliptic curve Diffie Hellman algorithm to an alternative or something like that I’m not your guy. As always if I got something wrong, or in the future something is changed, don’t hesitate to reach out to correct me.


My brother once jokingly described Signal as the place where paranoid people chat. I straightened my tin foil hat and said otherwise. But seriously, the Signal Protocol has become the standard of encrypted messengers - it’s even built into Facebook Messenger. It’s okay, but for the paranoid of us like your’s truly there are two potential trade-offs where the Signal Protocol’s ease of use comes at the cost of a chance your encryption keys are messed with and you can’t be sure you’re really using end to end encryption unless you specifically verify it.

To start an encrypted chat on the Signal protocol, your device contacts the servers of the messenger maker requesting the public key of who you’re looking to communicate with to provide a copy. The devices then use their private/public key pairs to decide on a shared key to use, and until the key changes both devices continue to the agreed upon symetric encryption key for the messages you send, preventing anybody but those two devices from reading the message.

Two things might have stood out: contacts the server for the public key and until it changes, so let’s delve into those a bit - starting with the key handshake that makes E2E encryption possible.

Handshakes

Keys are everything in encryption. In simpler implementations, you trade public keys with somebody you trust, e.g. PGP or Session. You know you have the right key from the person you expect because you got it straight from them. In the case of something like web traffic, you expect that you have the right key from the website you’re visiting because it’s signed by a (hopefully) reliable certificate authority. In the Signal Protocol, however: if you don’t identify somebody by their public key and instead ask a server what (111)-111-1234’s public key(s) are, you need to trust that the server is providing you with the right public key.

The buck stops there on the protocol, but it’s not where it ends app-wise. If you don’t want to rely on the server’s promise of acting nice, in the Signal app itself you can click on a contact to verify safety numbers (public key hashes) with the other person and confirm there’s no funny business going on in between. Theoretically the app could give fake info when you check the keys, but if you review the source code and compile it yourself you can be certain it’s not doing that. Now I don’t actually wear a tin foil hat - I only joke about doing so on the internet - so I haven’t reviewed/compiled but I trust that since the client is libre and has been audited the keys it displays are correct. But if you’ve never compared the key fingerprints, or are on an app that is using the Signal Protocol but doesn’t allow you to compare keys, then there is no guarantee that you’re actually communicating with E2E encryption. However, as long as you have compared keys in person and trust the client you can sleep easy knowing that you’re probably safe.

Changed Keys

So you’ve opened a chat with someone and verified that the proper keys were swapped. Then the server says that keys are changed for that particular user. For example, in Signal Messanger since accounts are managed via phone numbers if somebody got ahold of a number belonging to an account they could hijack the account and send messages from it as if they were the original sender - but the exact way an account might change would vary depending on the messenger that implemented the protocol. Because the private keys are held on the device (assuming you’re on a trusted client) the hijacker would need to generate new keys, meaning other clients will be aware of it and the hijacker won’t be able to read messages sent to/from the account’s old keys.

What happens next will depend on the client’s response, so not all Signal Protocol messengers will respond the same, but Signal Messanger notifies you of the change. To find out exactly how Signal Messenger reacts when keys change, I created a new account and sent myself a message, deleted everything on the container the new account was created on, and then signed back into the new account only via SMS verification (no backups or PIN). On my regular account I immediately got the notification “Your safety number with x has changed” in the chat below the last message using the previous keys with a learn more button that stated:

Your safety number with x changed, likely because they reinstalled Signal or changed devices. Tap to Verify to confirm the new safety number. This is optional.

Further, because I verified the safety number I also got a banner at the top of the chat that warned me that the safety number is no longer verified.

Maybe a little bit vague for my preferences, given somebody who’s not familiar with how encryption works might ignore it since the warning only listed non-malicious causes of the change. But unlike the risk with the initial key exchange, you do get notified so there’s no risk (in the Signal App itself, which may vary among other implementations) that you find your encryption compromised without any indication.

Monologue

Keeping in mind I am by no means the leading expert in the field, nor do I have knowledge of the inner workings of the Signal Foundation, if I were in charge here’s what I would propose to change.

The first, and likely easiest to implement, would be to allow people to find each other based on public keys, or mathematical derivatives of them. Allowing the client to create a QR code and then giving people the option to add each other by scanning each other’s code would make an easy way to bypass any issues requiring you to trust the key servers and/or need to go through the same process later to verify keys. If this change was made people could still add each other via phone numbers (or usernames if they get rolled out), but scanning a public key to initiate a chat would go a long way in avoiding a potential malicious server breaking your encryption.

But, while I’m monologing about what I might change, there might be a few additional things I would consider. The next step would be to allow people to create accounts by generating a private key without a phone number, even if it was only as a “second-class citizen” within the network. Signal claims they require a phone number to cut out spam, and phone verification is one of their largest expenses, but it’s really hard to guess hashes or public keys. They could require a captcha or something similar to submit a public key to Signal’s servers, then only allow key-based accounts to communicate with other accounts via QR codes or manually entering public keys. Something like this could probably be setup to allow for less spam than their phone number-based accounts while still offering people the privacy and security benefits of not using an account based on a phone number.

Last, the most extreme thing I would do (and the least likely to happen IRL) would be to open up Signal more. Despite being open source (at least the client has always been, the server has been on and off, 2), Signal has had an anti third party client stance. But opening it up to third-party clients could allow people to connect to custom third-party servers (in a Matrix or Nostr style federalization) and communicate with other messenger platforms that use the protocol - or if you use key-based identification even open up clients to DHT style P2P communication. Third parties could even re-add the SMS support back that Signal took away. This would allow us a much more customizable setup that would lighten the load on Signal’s costs, but still allow the super simple setup of the default phone number-based identification if somebody wanted to stick to that.

Wrap Up

Thanks for coming to my TED talk. I’d like to wish you all a good night. Except one person, who I won’t tell which, so you’ll all be kept up at night wondering if you are who some random stranger didn’t wish a good night.

Anyway, as I said in my dropdown disclaimer, I still use Signal and am not telling you that you need to drop it - though if you’re interested in looking into alternatives I won’t stop you either. If nothing else, hopefully you enjoyed reading this and maybe learned a bit more about potential limitations to the protocol depending on how it’s setup, and how you can be sure you’re getting the most out of it.