With WhatsApp being bought by Facebook, people are looking for alternative secure messaging systems. Telegram appears to be very popular at the moment, but its security is under heavy debate. (Summary: it uses non standard protocols.) Someone suggested Threema as an alternative, so I decided to install it. Threema is quite user friendly. It allows, for example, to create new contacts by scanning a QR code. If you meet someone in person who also has Threema installed on his smartphone, this is an easy way to exchange contact details. But there is something wrong the way Threema implements it.
In this image you see part of the “My ID” page in the Threema app.
You can see my Threema ID (KWKWSZ5X), the fingerprint and the QR code. Scanning the QR with a separate program reveals its contents:
So it starts with my Threema ID, followed by a 32 byte value. Presumably this is my public key. The number of bytes corresponds to the size of the public keys when using the NaCl cryptographic library (which Threema uses). Moreover, the first 16 bytes of the SHA256 digest of this value correspond to my fingerprint
The problem is that the contents of the QR code are not signed. This means I can create a QR code of my own that (provided the values make sense) will be accepted when importing a new contact by scanning this QR. Specifically, I can create a QR code containing an arbitrary Threema ID and my own public key. Anybody who trusts me and scans a QR code I show, will import my public key for this ID. (I can make this look very convincing by showing a picture of my “My ID” page, with the malicious QR code photoshopped inside it.) As a consequence, I can decrypt any messages sent to this ID. (For this to work in practice I also have to be a man in the middle between the sender and the Threema servers. Although this communication is additionally protected using SSL/TLS, with this recent bug in Apple’s implementation of SSL/TLS, this is certainly possible.)
So lets try to attach my public key to the ID of the Threema test account ECHOECHO. I created the following QR code
from the following data
When scanning this QR code Threema (luckily) reports an error, mentioning that the ID it read does not match the key returned by the server for that ID. (Threema refuses to import ID’s from scanned QR codes when it is not connected to the Internet.)
So the attack appears to be stopped, because some checks are made in the background.
You might wonder: why embed the public key in the QR code, if you are going to check with the key stored on the server to see if they match anyway? Why not simply retrieve the key from the server, and only embed the Threema ID in the QR code? It is simpler, achieves the same end result, and you do not run the risk of ‘forgetting’ this (important) check later on. This seems to make sense, but actually is the wrong way around the problem.
Threema makes two mistakes in my opinion:
- When ‘pairing’ devices using QR codes, both parties are assumed to trust each other. This is quite a big leap of faith, especially when considering more casual encounters at conferences or business meetings.
- Threema appears to use the ID as the primary key to which both public keys and linked identities (like your email address or mobile phone number) are connected. Distinguishing and using public keys and IDs like this is not a good idea. Carl Ellison wrote
a few beautiful papers about this in 1998 and 1999. The essence is that wherever you would use an ID, you should use simply the public key itself. Adding separate IDs create a useless extra level of indirection that can lead to exploitable errors (like the attack outlined above).
In other words: public keys should serve both as identifiers (allowing the messaging service to deliver the message at the right destination) and as a means to encrypt the message before it is send.
Then, to be able to communicate securely with someone else, I first need to be able to obtain that person’s public key (and not get someone else’s). Secondly, I need to be able to store that public key in a local contact list and associate it with something that identifies that person to me. This second part is important so I can retrieve the public key for that person whenever I want to send a message to him. In general, people do not have global identifiers. Whatever identifies a certain person to someone depends: some people I only know by nickname, or first name, for example. Phone numbers or email adresses may actually change ownership, so do not qualify as proper identifiers. This is why using a global identifier like the Threema ID is a bad idea. It does not identify a person to anyone at all.
In general, reliably getting someone’s public key is actually quite hard. You often need to trust some intermediary, like a public key directory. QR codes can be used to exchange public keys directly, without such a trusted third party. They allow me to personally hand over my public key to you. (And I have no incentive to give you any other public key for which I don’t have the corresponding private key. All it would achieve is that I cannot decrypt a message you send me.)
So what would be a better and still user friendly way to allow user B to learn user A’s contact information? How about the following.
- The app embeds user A’s public key in a QR code and displays it.
- User B presses the “scan new contact” button, and scans the QR code. The app retrieves the public key from the scan.
- B generates a random, user readable, nonce. It encrypts this together with his own public key against A’s key, and sends it (using A’s public key as identifier) to A. It also displays it to user B.
- A decrypts the message, and also displays the nonce.
- User B verifies that both nonces displayed on both devices are the same. If so, B is convinced that A controls (i.e. has access to the corresponding private key for) the public key it sent.
- The app asks user B to enter the identifier by which user B knows user A. The app may allow B to take a picture of A, to store along with the contact info.
Also allow users to embed the QR code everywhere they wish (on websites, blogs, stickers etc.) to strengthen the link between a user’s identity and the public key embedded in the QR code. Allow the app to verify a key already stored in the contact list against a scanned QR code.
Conclusion: there is something strange with the way Threema uses QR codes to exchange contact details. This does not appear to create a real security risk, but it does suggest that the way real identities, Threema IDs, and public keys are linked should be rethought.
(Update: the original protocol to verify that that A actually controls the private key was wrong.)