Back4App developers looking for extra security in their apps can use Virgil Security's E3Kit SDK to end-to-end encrypt any data in their product, limiting liability and simplifying compliance with regulations like HIPAA and GDPR.
In this guide, we’ll walk you through how E3Kit layers over Back4App and how you can start building end-to-end encryption into your app today. This guide explains the concepts using a chat app example, but 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.
HIPAA and end-to-end encryption
Healthcare industry experts see end-to-end encryption as the de facto standard for protecting healthcare data, 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: Any healthcare data sent through Back4App needs to be end-to-end encrypted and redacted so that that service is not considered your Business Associate and remains categorized as a "conduit" under HIPAA.
How does it work in my app?
E3Kit works as a layer over your app's existing communication system so that message data is encrypted on the device or in the browser before it is sent to Back4App, and then only decrypted on the recipient's device or browser session.
Encrypted group chat and multi-device access for users is supported out of the box with E3Kit, and there are SDKs for iOS, Android and JavaScript.
How do I implement it?
You'll need to configure your Back4App project and install E3Kit in your application project. To help, 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 their corresponding 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.
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
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
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.
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 E3Kit tutorial for adding end-to-end encryption to your app.
Questions? Feel free to ask the Virgil Security team on our Slack community.