End-to-End Encryption for Back4App Using Virgil Security’s e3kit SDK

Rebecca YarbroughJune 28th, 2019

Apps are becoming increasingly complicated, and more and more hands are touching the data that flows through them. It’s nearly impossible for a developer to completely control the security of the information stored and transmitted within an application these days.

That’s why end-to-end encryption has become more popular as a way to ensure that any data on your network isn’t inadvertently exposed by a third-party or breached in brute-force or ransomware attacks.

But perhaps its most attractive use for developers building with Parse on Back4App is within healthcare apps to comply with HIPAA and limit breach liability. 

Building end-to-end encryption yourself is hard though. It can take years even with a dedicated team and millions in funding. That’s why Virgil Security built the e3kit SDK that allows you to add an end-to-end encryption layer over any communication flow without knowing anything about cryptography.

In this guide, we’ll walk you through how e3kit works with Back4App and how you can start building end-to-end encryption into your app today. To illustrate the concepts, we’ll use the common use case of a chat app. However, you can use e3kit to end-to-end encrypt communication between any two endpoints, including mobile apps, web apps, servers and IoT.

To get started, follow the tutorial below and join the Virgil Slack community if you’d like to ask questions.

What is end-to-end encryption?

End-to-end end encryption encrypts data from device to device, with no breaks in the middle. The developer, Back4App, ISP and cloud backend are all locked out from seeing anything but scrambled jibberish. The client device has a locally generated private key, and that’s the only thing that can decrypt data sent to the corresponding user.

Why end-to-end encryption?

Even with Back4App’s strong security measures, there is still significant discretion for developers when it comes to how “secure” they actually make their app. By default, application data is unencrypted as it passes through frontend and backend servers and is available to admins and developers in the live database. If your security rules are misconfigured by you or any third-party vendor, your data could be spilled out in plaintext.

In fact, “some industry researchers predict that 80 percent of cloud data breaches will be due to customer misconfiguration, mismanaged credentials or insider theft, rather than cloud provider vulnerabilities, by 2020” according to Mark Johnson in an article by Data Breach Today.

Application security decisions are simplified with end-to-end encryption. Because third parties or internal employees are handling scrambled, encrypted data without the technical ability to decrypt it, the potential damage is typically lessened.

HIPAA and end-to-end encryption

Healthcare industry experts see end-to-end encryption as the de facto standard for protecting healthcare data, not just because it’s required by HIPAA, but because it lessens the likelihood of any healthcare data breach.

The reasons why most healthcare applications will not accept anything less than end-to-end encryption include the following:

  • A combination of HTTPS and encryption at-rest in the database is not sufficient, because there are termination points along the way where the data is not encrypted.
  • In the typical at-rest encryption configuration, the decryption key is stored in the same database which makes it too easy for internal team members or external bad actors to have access to this key.
  • You can still be liable for exposing PHI even if there’s no evidence it was even accessed by anyone.
  • You can be liable for breaches by your vendors, even if they claim HIPAA compliance

By end-to-end encrypting PHI within your application, you can satisfy requirements in the Security Rules and Privacy Rule within the Technical Safeguards section of the HIPAA and protect yourself from mistakes made by other vendors.

Note: If you’re sending PHI through any service that’s not HIPAA compliant, the message data needs to be end-to-end encrypted and you’ll also need to redact any message data so that that service is not considered your Business Associate and remains categorized as a “conduit” under HIPAA.

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 might want to keep benign information related to a chat app (like timestamps) in plaintext but end-to-end encrypt the message content. 

How does it work in my app?

e3kit works as a layer over your app’s existing communication system. When one of your users signs up, your app will generate a private and public key on their device. The user’s public key is published to the Virgil Cloud directory for users to find other users’ public keys and encrypt data for them. Each user’s private key remains on their device and is protected by the operating system’s native key store.

An overview of the End-to-End Encryption structure on Back4app’s messenger app

 

How do I implement it?

The process is quite simple. It involves configuring your Back4App project and installing e3kit in your application project.

If you want to get a head start on this tutorial, we’ve built a demo app for Android, which you can find on GitHub here.

Step 1: Configure your Back4App project

To start, your Back4App project must have a special Cloud Function to authenticate your users with Virgil Security. The steps for setting up the Cloud Function are in our demo’s GitHub README

Step 2: Set up your client

On the client side, we will use the Virgil e3kit SDK to create and store the user’s private key on their device and to publish the appropriate public key in the Virgil Cloud.

You’ll need to install and initialize e3kit in this step.

A) Use the package manager to download the e3kit SDK 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 {
    // Replace <latest-version> with the latest version number (eg. 0.5.0). You can find it at:     
    // https://github.com/VirgilSecurity/virgil-e3kit-kotlin/releases

    implementation "com.virgilsecurity:ethree-kotlin:<latest-version>”
}
// This works for both Java or Kotlin.

B) Initialize e3kit:

In order to have an eThree instance and interact with the Virgil Cloud, e3kit must be provided with a callback that it will use to fetch the Virgil JWT from your backend for the current user.

// Fetch Virgil JWT token from Back4App function
val tokenCallback = 
    object : OnGetTokenCallback {
        override fun onGetToken(): String {
             val data = Back4AppFunctions.getInstance()
                   .getHttpsCallable("getVirgilJwt")
                   .call()
                   .result
                   ?.data as Map<String, String>
 
            return data["token"]
        }
    }

val initializeListener = 
    object : OnResultListener<EThree> {
        override fun onSuccess(result: EThree) {
            // Init done!
        }

        override fun onError(throwable: Throwable) {
            // Error handling
        }
    }

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

Step 3: Register users with Virgil Security

The `register()` method checks whether a user already has a private key saved in local storage and a published public key on Virgil Cloud, and, if the user doesn’t have them, the function generates a new keypair for the user, saves the private key locally and publishes the public key on Virgil Cloud (for other users to reference).

To register users on Virgil Cloud you have to use `register()` method during the Sign Up flow in your application:

val registerListener =
    object : OnCompleteListener {
        override fun onSuccess() {
            // User private key loaded, ready for end-to-end encrypt!
        }

        override fun onError(throwable: Throwable) {
            // Error handling
        }
    }


eThree.register().addCallback(registerListener)

Step 4: Encrypt Message Data 

`encrypt(data, publicKeys)` signs the data with the sender’s private key and encrypts the message for recipients’ public keys.

The publicKeys parameter is an array of the recipients’ public keys. In order to retrieve the public keys of users using their identities and generate this array, you’ll need to use the `lookupPublicKeys(identities)` method.

// Listener for keys lookup
val lookupKeysListener =
    object : OnResultListener<LookupResult> {
        override fun onSuccess(result: LookupResult) {
            val text = "I was a text, but become a byte array"
            val data = text.toByteArray()

            // Encrypt data using user public keys
            val encryptedData = eThree.encrypt(data, result)

            // Encrypt message using user public keys
            val encryptedText = eThree.encrypt(text, result)
        }

        override fun onError(throwable: Throwable) {
            // Error handling
        }
    }

// Lookup destination user public keys
eThree.lookupPublicKeys(listOf("userUID1", "userUID2", "userUID3")).addCallback(lookupKeysListener)

Step 5: Decrypt Message and Verify Sender

After receiving a message, we’ll decrypt it using the recipient’s private key and verify that it came from the right sender by confirming that the message signature contains the sender’s public key.

// Listener for keys lookup
val lookupKeysListener =
    object : OnResultListener<LookupResult> {
        override fun onSuccess(result: LookupResult) {
            // Decrypt data and verify if it was really written by Bob
            val decryptedData = eThree.decrypt(encryptedData, result["bobUID"])

            // Decrypt text and verify if it was really written by Bob
            val decryptedData = eThree.decrypt(encryptedText, result["bobUID"])
        }

        override fun onError(throwable: Throwable) {
            // Error handling
        }
    }

// Lookup chat room member key
eThree.lookupPublicKeys("bobUID").addCallback(lookupKeysListener)

Voila! You’ve end-to-end encrypted messaging in a Back4App app.

Group chat and multi-device access for users is supported out of the box with e3kit, which can also help with HIPAA’s requirements around audit logs

You can find instructions for additional features like password changes and device cleanup in the integrated tutorials within the Virgil Security dashboard.

To get started with e3kit, sign up for a free Virgil Security developer account at dashboard.virgilsecurity.com, create your first application and follow the quickstart guide for adding end-to-end encryption to your app. The e3kit documentation can be found here. 

Questions? Feel free to ask the Virgil Security team on our Slack community.

Previous
On the loop: The best WWDC in years
Matheus CardosoJune 28th, 2019