Encrypted Chat
Ahoy Back4app community!
This is a guest tutorial from the team at Virgil Security, Inc.: we’re the crypto tech behind Twilio’s End-to-End Encrypted Messaging. Our friends @ Back4app asked us to show you how to build an End-to-End Encrypted chat app on top of Back4app.
In this post, we’ll walk you through the steps to make a simple Back4App Android Messenger app End-to-End Encrypted! Are you ready? PS: If you don’t care about the details, simply skip to the end of the post and download the final product.
First, let’s start with a quick refresher of what E2EE (End-to-End Encryption) is and how it works. E2EE is simple: when you type in a chat message, it gets encrypted on your mobile device (or in your browser) and gets decrypted only when your chat partner receives it and wants to display it in chat window.
The message remains encrypted while it travels over Wi-Fi and the Internet, through the cloud / web server, into a database, and on the way back to your chat partner. In other words, none of the networks or servers have a clue of what the two of you are chatting about.
What’s difficult in End-to-End Encryption is the task of managing the encryption keys in a way that only the users involved in the chat can access them and nobody else. And when I write “nobody else”, I really mean it: even insiders of your cloud provider or even you, the developer, are out; no accidental mistakes or legally enforced peeking are possible. Writing crypto, especially for multiple platforms is hard: generating true random numbers, picking the right algorithms, and choosing the right encryption modes are just a few examples that make most developers wave their hands in the air and end up just NOT doing it.
This blog post will show you how to ignore all these annoying details and quickly and simply End-to-End Encrypt using Virgil’s SDK.
For an intro, this is how we’ll upgrade Back4app’s messenger app to be End-to-End Encrypted:
- During sign-up: we’ll generate the individual private & public keys for new users (remember: the recipient’s public key encrypts messages and the matching recipient’s private key decrypts them).
- Before sending messages, you’ll encrypt chat messages with the recipient’s public key.
- After receiving messages, you’ll decrypt chat messages with the recipient’s private key.
We’ll publish the users’ public keys to Virgil’s Cards Service so that chat users are able to look up each other and able to encrypt messages for each other. The private keys will stay on the user devices.
Keep it simple
This is the simplest possible implementation of E2EE chat and it works perfectly for simple chat apps between 2 users where conversations are short-lived and it’s okay to lose the message history if a device is lost with the private key on it.
OK, enough talking! Let’s get down to coding.
- We’ll start by guiding you through the Android app’s setup,
- Then, we’ll add some code to make the app end-to-end encrypted.
To complete this tutorial, you need:
- Android Studio.
- An app created at Back4App.
Let’s start with deploying the cloud function. For this, you will need to:
- Find main.js and package.json in scripts directory;
- Open main.js with your favorite editor.
1.1) Get Back4App credentials
- Open Dashboard of your app > App Settings > Security & Keys:
- In main.js, replace PARSE_APP_ID with your Application ID and PARSE_REST_API_KEY with your REST API key:
1.2) Get Virgil credentials
- Open your new Virgil application, navigate to E3Kit section and and generate a .env file under the E3Kit section in the left side bar
- Copy the values of APP_ID, APP_KEY, and APP_KEY_ID from the .env file
- Replace the copied values in your main.js file in the corresponding fields (main.js of scripts directory):
1.3) Deploy cloud code function
- Open Back4App “Dashboard” of your app -> “Core” -> Cloud code functions;
- Click +ADD and select your main.js and package.json (from scripts directory), after that move both of them to the cloud folder;
- Click DEPLOY.
Don’t forget to set up Back4App cloud code function first. It is a mandatory part of this demo. After this, go through the following steps:
2.1) Import Project in Android Studio
- Open Android Studio -> File > New > Project from Version Control > Git
- Git Repository URL: https://github.com/VirgilSecurity/chat-back4app-android
- Check out the clean-chat-kt branch
Important!
Select “Project” type of file tree. It will be used all-through the tutorial:
2.2) Setup Back4App credentials in project
- Open Back4App “Dashboard” of your app -> “App Settings” -> “Security & Keys”;
Go to /app/src/main/res/values/strings.xml file in your android project and replace your_back4app_app_id with your Application ID and your_back4app_client_key with your Client Key:
2.3) Setup DB
- Open Back4App “Dashboard” -> “Core” -> “Database Browser” -> “Create a class” and create classes of Custom type named Message and ChatThread;
2.4) Setup live query
- Press the Server Settings button on your Application
- Find the “Web Hosting and Live Query” block
- Open the Live Query Settings and check the Activate Hosting option.
- Choose a name for your subdomain to activate Live Query for the 2 classes you created: Message and ChatThread.
- Copy your new subdomain name and click the SAVE button:
Return to /app/src/main/res/values/strings.xml and paste “Subdomain name” you have entered above into the back4app_live_query_url instead of “yourSubdomainName”:
After these steps you will be able to hit the Run button in Android Studio and get the sample to work. Use emulator or real device to test it out.
To see the result of running the clean version of the demo, you’ll need to:
- Sign up 2 users;
- Start a conversation between them and send a couple of messages;
3. Open Back4App “Dashboard” -> “Core” -> “Database Browser” -> “Message”.
If it all worked out, you should see the chat messenger app popping up. Register two users and send a few messages to each other: you should see new data showing up in the Message class.
Note that you can see on the server what your users are chatting about:
Next: Close your chat interface and move on to the next step – adding E2EE encryption.
By the end of this part, this is how your chat messages will look like on the server: can you spot the difference?
How do we get there? Obviously, we need to implement end-to-end encryption, which means that our app needs to:
- Generate the private & public key pair as part of signup
- Store the private key in the key storage on user’s device
- Publish the public key in Virgil’s Card Service as a “Virgil Card” for other users to download & encrypt messages with it
- Encrypt messages with public key and sign with private key; decrypt messages with private key and verify with public key
For this, we will need to add E3Kit to our clean demo application and some more code to implement all that was described above.
But before we begin, let’s clear two important terms for you: what’s a Virgil Card and a private key?
- Virgil Card - Virgil Сards carry the users’ private keys. Virgil Cards are published to Virgil’s Cards Service (imagine this service is like a telephone book) for other users to retrieve them: Alice needs to retrieve Bob’s public key in order to encrypt a message for Bob using that key.
- Private key - a private part of the encryption key. Remember, private keys can decrypt data that was encrypted using the matching public key.
- In the app-level (Module: app) gradle at /app/build.gradle add (but don’t sync gradle scripts just yet):
- Add the following to the end of your project-level /build.gradle (Project: chat-back4app-android):
- Now you can synchronize gradle scripts;
- Update your AppVirgil class by adding new fields:
- Press Alt+ Enter to import the necessary libraries into the class.
- In ../virgilsecurity/virgilback4app/model/ directory, create data classes AuthenticateResponse and VirgilJwtResponse that represent responses from Cloud Code functions:
- In ../virgilsecurity/virgilback4app/util/ create AuthRx object that implements calls to Cloud Code functions (don’t forget to import all the necessary libraries afterwards):
Virgil token received from Cloud Code functions needs to be stored locally. Let’s update Preferences class in ../virgilsecurity/virgilback4app/util/:
- Define constant:
- Add functions setVirgilToken, virgilToken and clearVirgilToken:
~~~kotlin
fun setVirgilToken(virgilToken: String) { with(sharedPreferences.edit()) { putString(KEY_VIRGIL_TOKEN, virgilToken) apply() } }
fun virgilToken(): String? { with(sharedPreferences) { return getString(KEY_VIRGIL_TOKEN, null) } }
fun clearVirgilToken() { with(sharedPreferences.edit()) { remove(KEY_VIRGIL_TOKEN) apply() } }
E3Kit takes care about your private and public keys. To generate them during the registering process, we’ll need to do the following:
- In ../virgilsecurity/virgilback4app/util/create RxEthree class:
- Now, add initEthree function that initializes E3Kit instance in RxEthree class:
- Add registerEthree function that registers a new user to RxEthree class. E3Kit generates a key pair during a sign up. The generated private key then is stored in local storage, and public key is published to Virgil Services as a Virgil Card.
- Let’s make some updates to LogInPresenter class (in ../virgilsecurity/virgilback4app/auth/).
- Add rxEthree field:
Update the requestSignUp function to run registration with E3Kit
Now, let’s make changes to requestSignIn method of LogInPresenter class (in ../virgilsecurity/virgilback4app/auth/):
Next, add functions that handle E3Kit initialization into ThreadsListFragment class (in ../virgilsecurity/virgilback4app/chat/contactsList/):
Update postCreateInit function to initialize E3Kit:
And add the following code into ThreadsListFragmentPresenter class in virgilsecurity.virgilback4app.chat.contactsList/:
- Add field:
- and function
At this point we are able to Sign up/Sign in a user and create a new chat with other user.
Now let’s add encryption for our messages.
Let’s add findCard function to RxEthree class (in ../virgilsecurity/virgilback4app/util/) that will help us to get the latest Virgil Card by user name:
When a chat is opened, we should obtain Virgil Card of the recipient. Edit postCreateInit of ChatThreadFragment class (in ../virgilsecurity/virgilback4app/chat/thread/) by replacing
code with a new one
And add two functions:
Now let’s change ChatThreadPresenter:
- Add fields:
- Add a function that obtains a Virgil Card of the recipient:
- Add encryption of outcoming messages in requestSendMessage function:
Add decryption of all the incoming messages into ChatThreadRVAdapter class (in ../virgilsecurity/virgilback4app/chat/thread/):
- Add fields:
- Implement message decryption in onBindViewHolder function
Now to see the result of our fully end-to-end encrypted demo, go through these steps again:
- Log out the previous user
- Sign up 2 new users;
- Start a conversation between them and send a couple of messages;
- Open Back4App “Dashboard” -> “Core” -> “Database Browser” -> “Message”.
Important! You have to Log Out the current user and register two new users, after that you can start E2EE chat with those two new users. The reason is that your first two users have no Virgil Card’s, so you can not use encrypt\decrypt for them.{: .blockquote-tip}
Done! Now you can see that users’ messages are encrypted and can only be accessed in app by users themselves.
End-to-End Encryption is a way to meet the technical requirements for HIPAA (the United States’ Health Insurance Portability and Accountability Act of 1996) & GDPR (the European Union’s General Data Protection Regulation). If you need more details, sign up for a free Virgil account, join our Slack community and ping us there: we’re happy to discuss your own privacy circumstances and help you understand what’s required to meet the technical HIPAA & GDPR requirements.
Final project. If you missed pieces from the puzzle, open the E2EE project branch. You can insert your application credentials in this code (as you did during the article) and build the project.
You can find more information about what you can build with Virgil Security here.