We at Virgil Security are pretty hardcore privacy geeks. So when we meet teams like the Hushed crew who are just as focused on protecting the privacy of people around the world, we get pretty excited to work together.
Hushed provides private, temporary numbers and anonymous user-to-user messaging. They have been around for 5 years and have over 6 million downloads in 70+ countries.
Learn how they implemented Virgil’s end-to-end encryption SDK below.
From the Hushed team:
This technical post walks you through our key decisions and learnings in our end-to-end encryption implementation journey. We feel that if we had a similar post to read at the time, it would have saved us time and a couple of gotchas, so in an effort to make your journey smoother, we’re sharing our learnings.
At Hushed, we believe in the right of a person to be private and, to a large degree, anonymous as well. This core belief is deeply wired into all essential parts of our app; we don’t require the user to sign up with a valid email address or phone number to verify their identity. We do not keep or share any information other than what is necessary for the app to function, i.e. you can re-download your SMS messages and call history but when you delete it, we delete the information from our servers as well.
In that spirit we wanted to offer a messaging feature that was anonymous to the degree a user chooses to be and offers strong guarantees about the privacy of their messages as well.
Among the requirements for our messenger were the following:
- End-to-end encryption so we can’t be compelled to give access to a user’s message content
- Compromising a key shouldn’t compromise the whole conversation (forward secrecy)
- Private keys and/or passwords would never be sent to our server
- Secure and reliable platform for storing the public encryption keys
- The least information possible about the user and their communications would be stored
- Encrypted communication should only be stored on our servers for as long as it is needed for message delivery
- Support multiple profiles on one device concurrently
We evaluated a number of different open-source and proprietary projects in our search for a platform and technology that enables us to achieve all these requirements. A preference was given to open-source projects that had been rigorously tested.
One of the obvious choices is libSignal by Open Whisper Systems which has strong end-to-end encryption and forward secrecy. However, their open-source license was incompatible with our business requirements and we found their closed-source licensing and review process to be cumbersome, slow and unsupportive of moving our goals forward in a reasonable time-frame.
Virgil Security offered us the right mix of privacy, security, and expertise for our messaging product. Their licenses and pricing worked for our use-case, and they gave us plenty of developer support to ensure a high-quality product.
Hushed uses secure Websockets (WSS) with JSON web-token-based authentication (JWT) and push notifications to deliver messages to the mobile clients. We use WSS when either one or both parties are actively engaged in a conversation and push notifications to notify a user of new messages when they are offline.
One of the benefits of using WSS is that it allows Hushed to support “is typing” and “has read” style interaction patterns. These messages are relayed as transient messages via WSS only to online devices.
When a user sends messages to another user we have to set up or reestablish an encrypted session between the devices of both users (note that this is not the same as verifying the other user’s identity). The diagrams below illustrate that workflow from both the sending and the receiving side.
The “Get keys for recipient from the server” is actually a two step process. First, it grabs the Virgil registration ID for the recipient from our server. The client then requests the registration information (the public keys required to establish a secure connection) from Virgil’s servers using the retrieved ID.
Since private keys are not shared, we needed to handle tying a specific Virgil registration to a preferred device (and then the preferred device to the account) within our database. This was a trade-off of allowing a user to only have a single device capable of decrypting a message (security), and dropping multi-device support (for now at least).
A key benefit to inserting ourselves in the registration process means that we also get the chance to broadcast to users when a participant in one of their conversations has changed registration information (changed devices, re-installed, etc.) and a simple message is shown. For the security conscious this means that they can check that their session is still secure via a readable key.
End-to-end encrypted group messaging is an interesting topic with a couple of approaches that can be used.
- Client-side fan-out: The client is responsible for sending a message to each participant using their own established connection. This provides more security but a lot more failure points for message sending as well and difficulties providing a clean User Experience when a message did not successfully send to all of the participants.
- Server-side fan-out: The client sends a single message to the server and the server is responsible for sending out the message where each member encrypts messages using a key (sender key) shared through a one-to-one conversation.
We decided to use server-side fan-out as this simplified the message sending process from a technical perspective. Some consideration needed to be put into how you maintain forward secrecy which just involves rotating the sender keys periodically and on certain events (i.e. when a member joins or leaves a group) so that messages not intended for a recipient can’t be decrypted.
As you can see in our group message sending flow, it very closely mirrors the one-to-one messaging flow and leverages it to maintain our goals of forward secrecy and end-to-end encryption.
Work in Progress…
The above gives you insight into some of the core motivations and decision behind our implementation of end-to-end encrypted messaging.
While we are happy with the current platform there are still a couple of areas that at the time of writing of this post were still open areas for improvement in later versions:
- True multi-device support
- Backup of user-content
But hey, we keep our roadmap in a bottomless jar, so there’s always room for delivering new capabilities for our users as well.