How to implement end-to-end encryption for simplified security

How to implement end-to-end encryption for simplified security

Rebecca Yarbrough — October 30th, 2018

Note: The Virgil SDK used in this tutorial has been replaced by the Virgil Security E3Kit SDK. Please follow the Firebase guide here.

User privacy is a hot topic right now, both in the minds of consumers and developers. It’s the subject of discussions on Capitol Hill between lawmakers and tech companies like Google and Apple; regulations like GDPR are directly impacting the way companies do business globally; and apps like Signal and Telegram have built billion dollar apps by capitalizing on user privacy demand.

It’s clear that the issue will come to a head soon, and developers can get ahead of the curve by proactively building security features like end-to-end encryption into their products.

Virgil Security is enabling this next revolution in app security with our open source SDK that developers can use to add end-to-end encryption to their web, mobile and IoT products.

In this post, we’ll cover what end-to-end encryption actually is, why it’s useful for developers, and how to implement it in an app. We’ll use a Firebase chat app as an example, but Virgil Security’s SDK is platform-independent and works across many languages.

What is End-to-End Encryption?

This is what a typical Firebase app looks like today:

Virgil Security Announces End-to-End Encryption for Firebase

Firebase uses Google Cloud’s strong security features, including encryption in transit with HTTPS and encryption at rest. This means that if any unauthorized person were to listen in on the network calls to Cloud Firestore or break into one of Google's data centers and make off with a hard drive, they’d only find useless strings of scrambled letters and numbers.

But when it passes through frontend and backend servers, the data is vulnerable and unencrypted and also available in plaintext to admins and developers in the live database. This means that any internal developers or admins with view access to your Cloud Firestore database can see the user data. And if there's an error in your Firebase Security Rules that allows rogue clients to illegitimately access your stored documents, they’ll be able to see the data contained in those documents.

These vulnerabilities exist on other platforms too. If you’re using a custom implementation or another platform, your risk of data breach might be even higher, since Google has somewhat rigorous security mechanisms.

Why does this matter? Internal bad actors and misconfigured security are two of the most common ways that an app’s data is exposed. In fact, a two year study in the UK found that 88% of data breaches were caused by developer error, not cyberattacks.

Developers need a solution to properly protect user data from accidental or deliberate data breaches. But with the complexity of today’s dev stacks, it’s almost impossible to build a breach-proof product. With end-to-end encryption, you can sleep easy at night knowing that even if someone somewhere makes a mistake, no sensitive data will get out.

Plus, end-to-end encryption makes compliance with regulations like HIPAA and GDPR possible without costing millions of dollars or years of development time.

An End-to-end Encrypted Firebase App

This is what your app will look like after you implement client-side end-to-end encryption:

Firebase now has end-to-end encryption

Using a chat app as an example, the messages will be encrypted on the users’ devices and remain encrypted everywhere in between. In other words, none of the networks, servers and databases (not even you) will see anything but scrambled data passing through.

What can I end-to-end encrypt?

Anything – chat messages, files, photos, sensory data on IoT devices, permanent or temporary data. You decide what data you want to end-to-end encrypt. For example, you can encrypt some fields in a Cloud Firestore document, but not others. For example, you might want to keep benign information related to a chat app (like timestamps) in plaintext but end-to-end encrypt the message content.

How do I implement it?

  1. Every user has a private & public key which the SDK will generate on your users’ device at signup or next time they log in.
  2. The user’s public key is published to Virgil’s REST-based key management service for users to find each other’s public keys and be able to encrypt data to each other.
  3. The user’s private key remain on the user’s device, protected by the operating system’s native key store:
import { EThree } from '@virgilsecurity/e3kit';

// Fetch Virgil JWT token from Firebase function
const fetchToken = async () => {...}

// Log in Firebase user on client device
firebase.signInWithEmailAndPassword(email, pwd)

// Once Firebase user authenticated, bootstrap e3kit to load user's private key
firebase.auth().onAuthStateChanged(function(user{
  if (user) {

    // Initialize e3kit
    const eThree = await EThree.init(fetchToken);

    // Bootstrap user (i.e. load user's private key)
    eThree.bootstrap(pwd);

    // User private key loaded, ready to end-to-end encrypt!

  } else {
    // No user signed in.
  }
});
  1. Before sending a chat message or sharing a document, the app encrypts the contents using the recipient’s public key (client side).
const usersToEncryptTo = ["[email protected]""[email protected]"'[email protected]'];

// Lookup destination user public keys
const chatRoomParticipants = await eThree.lookupKeys(usersToEncryptTo);

// Encrypt message using target user public keys
const encryptedMessage = eThree.encrypt('Hello there!', chatRoomParticipants);

  1. After receiving a message, the app decrypts it using the recipient user’s private key.
// Decrypt message from chat room

const decryptedMessage = eThree.decrypt(encryptedMessage, chatRoomParticipants);

This technique ensures that only end-users can see messages. The plaintext data won’t be visible to Firebase, to developers at your company, or to clients that the message wasn't intended for. If you’re building a chat feature or app, you’ll be able to build professional-quality end-to-end encrypted chat. You can also build an end-to-end encrypted IoT product or team collaboration suite, or use end-to-end encryption for any use case to protect your users’ data.

Any Drawbacks?

While there are a number of good reasons to implement end-to-end security in Firebase, it's not without its drawbacks. Specifically...

  1. You won't be able to view the customer data that you’ve end-to-end encrypted. Obviously, this is by design, but it can make things more difficult if you're looking to troubleshoot a specific customer issue.
  2. Similarly, Cloud Functions (or another third party) won't be able to run analytics or other functions on the data that you've encrypted. If there's data that you need to give Cloud Functions access to, consider leaving that data unencrypted.
  3. There's a minor performance hit involved when encrypting and decrypting data. Something along the lines of 1-2 ms per message on the client device. Plus, your clients will need network access whenever they want to encrypt that message (user key lookup is an online operation, which you can cache after it’s done).

Start implementing it today with our SDK at https://developer.virgilsecurity.com/docs/e3kit/.

Want end-to-end encryption in your product, but need a developer to do it? Use a Virgil Security Development Partner. Contact us for details.

If you have any other questions about security, that's our favorite topic! Find us on Slack or on Twitter at @virgilsecurity.

Virgil Security, Inc. allows developers to protect passwords & encrypt everything, in hours, without having to become security experts. Learn more at VirgilSecurity.com.