End-to-End Encryption for Firebase

In this tutorial, we will help you add end-to-end encryption to your product on Firebase platform to secure your messages and user data.

Benefits of E3Kit for Firebase

  • Full privacy: Only user can read their own messages; Firebase, Virgil and other third-party services cannot decrypt and access messages and data.
  • Complete end-to-end encryption: User's data is always encrypted and protected - at rest and in transit.
  • Independent data protection: With E3Kit your data protection doesn't rely on any network and service providers, so any attacks on them won't influence the data integrity and confidentiality.
  • Data integrity: The E3Kit signs and verifies data as part of the encrypt and decrypt functions. This confirms that data is actually coming from the user who encrypted it and that it hasn't been tampered with in transit or storage.

How E2EE works with 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.

End-to-end encryption fills the gaps and creates a secure, unbreakable chain between two users using a private and public key for each user:

Encrypted communication

  • The public key is published to Virgil Cards Service, part of the Virgil Cloud PKI. When your users want to send a message, the Virgil E3Kit uses the recipient's public key to encrypt the message data in a way that only the recipient's corresponding private key can decrypt it.
  • The private key is kept on the end-user's device, enabling the user and only the user to decrypt any messages or data that other users sent to them. It's similar to the relationship between a public mailing address and a private mailbox. You look up someone's address to send them a letter, but only they can unlock their mailbox to open and read the letter.

The address book (Virgil's Cards Service), mailing address (public key) and mailbox key (private key) are related to each other, but can't be traced to each other in any way that would compromise the security of the system. End-to-end encryption also locks the letter (message data), and only the recipient has the key to unlock it.

This setup enables users to encrypt a message on their phone or computer, send it over the Internet to a recipient without any chance of another party reading it in transit or on the server, and have it be decrypted only by the recipient on their phone or computer. This all works seamlessly for the end-users and it only takes a few lines of code to implement using E3Kit.

Configure your Firebase project

We assume that you already have a Firebase Project. If you don't, please create one now at your Firebase Console.

Configure user authentication

If you haven't already, set up Sign-in method in your Firebase Project by enabling any of the Sign-in providers. For the purposes of this tutorial it doesn't matter which sign-in provider you choose.

To set up your Sign-in method, go to your Firebase Console and navigate to Authentication, under Develop. Go to the Sign-in method tab and set up your preferred sign-in method(s).

Provide your users access to Virgil Cloud

To make API calls to the Virgil Cloud, you'll need to provide the users of your app with a JWT that contains the user's identity which is a string that uniquely identifies each user in your application. For this tutorial we'll assume that your user records have a unique ID assigned by Firebase, known as uid, and we will use that as their identity.

If you don't want to use the Firebase UID, you can use another field for the user identity as long as it's unique for each user. For security reasons, avoid using fields that contain any personally identifiable information such as name or email address.

For this tutorial we've created a Firebase Function that you can use to generate the JWTs. All you need to do is generate the configuration file with your Virgil Account data for it and deploy it to your Firebase account.

To deploy the Firebase function, head over to our GitHub repo and follow the instructions in README.

When completed, you should have a deployed function in your Firebase project like the one below.

Firebase Functions

Set up your client

On the client side we will use the E3Kit to create and store the user's private key on their device and publish the user's corresponding public key in the Virgil Cloud.

Install E3Kit

Use the package manager to download the E3Kit to your mobile or web project.

// to integrate E3Kit SDK into your Android project using Gradle,
// add jcenter() repository if missing:

repositories {
    jcenter()
}

// set up dependencies in your `build.gradle`:

dependencies {
    // This works for both Java and Kotlin.
    implementation 'com.virgilsecurity:ethree:<latest-version>'

    // If you want to use kotlin coroutines - use insead:
    // implementation 'com.virgilsecurity:ethree-coroutines:<latest-version>'
    // Check out coroutines sample via link: https://github.com/VirgilSecurity/virgil-e3kit-kotlin/tree/master/samples/android-kotlin-coroutines

    // You can find <latest-version> here: https://github.com/VirgilSecurity/virgil-e3kit-kotlin
}

Initialize E3Kit

In order to interact with the Virgil Cloud, the E3kit SDK must be provided with a callback that it will call to fetch the Virgil JWT for the current user from your backend - your Firebase Function in this tutorial.

The next steps must be done after the device is fully authenticated with Firebase. To understand how to authenticate with Firebase, see the Firebase documentation.

// Fetch Virgil JWT token from Firebase function
OnGetTokenCallback tokenCallback = new OnGetTokenCallback() {

    @NotNull @Override public String onGetToken() {
        Map<String, String> data =
                (Map<String, String>) FirebaseFunctions.getInstance()
                                                       .getHttpsCallable("getVirgilJwt")
                                                       .call()
                                                       .getResult()
                                                       .getData();

        return data.get("token");
    }
};

OnResultListener<EThree> initializeListener = new OnResultListener<EThree>() {

    @Override public void onSuccess(EThree result) {
        // Init done!
        // Save the eThree instance
    }

    @Override public void onError(@NotNull Throwable throwable) {
        // Error handling
    }
};

// Initialize EThree SDK with JWT token from Firebase Function
EThree.initialize(context, tokenCallback).addCallback(initializeListener);

The EThree.initialize() function gets the user's JWT and initializes the Virgil E3Kit for further use. The EThree.initialize() function must be used on SignUp and SignIn flows.

Next step

Now that you have your Firebase and E3Kit set up and initialized, you can move on to registering users: