Build

Build an End-to-End Encrypted Chat with Seald and PubNub

6 min read Darryn Campbell on Mar 19, 2024

This article has been contributed by a third party, seald, and presents an alternative to PubNub's built-in message-level encryption. It was originally published on Hackernoon.


Today, let's discover how to build an end-to-end encrypted chat with Pubnub and the seald SDK.

👉 A fully working example of how to use PubNub and Seald can be found here: https://github.com/seald/pubnub-example-project

What's Pubnub?

PubNub is a real-time communication service that can be integrated into most applications. Reliable and scalable, it can easily be integrated with the most common frameworks.

What's Seald?

Seald.io offers an SDK that allows you to carry out end-to-end encryption, with advanced management features, without any prior cryptographic knowledge. This SDK can be integrated into web, backend, mobile, or desktop applications.

Content Overview

  • Why use end-to-end encryption?

  • Why use Seald.io instead of PubNub encryption hook ?👀

  • Goals 🏆

  • Implementation 🧠

  • Adding end-to-end encryption with Seald 🔒💬

  • Conclusion ✅

Why use end-to-end encryption? 🔒

End-to-end encryption offers the highest level of privacy and security. It allows encrypting sensitive data as soon as they are collected. An early encryption will reduce the attack surface of your app. Another advantage is that you can precisely manage who can access the data. This will also protect when it is not in your scope, like third-party services.

End-to-end encryption allows you to keep control at all times, when your data is in transit, when it is at rest, and even when it is not in your hand. Thus, it offers far wider protection than other encryption technologies (TLS, full-disk encryption, ...).

Whenever you face a case where compliance is important (GDPR, HIPAA, SOC-2,...) or where you have sensitive data (medical, defense,...), end-to-end encryption is a must-have. But even for more commonplace data, it's good practice to have. A data breach is a devastating event that is becoming more and more frequent.

Why use Seald.io instead of PubNub encryption hook? 👀

PubNub SDK offers a simple encryption hook, using the cipherKey argument when instantiating its SDK. Doing so will ensure that all uploaded messages are encrypted before being sent. However, you have to do the key management yourself.

Vulnerabilities rarely come from the encryption itself, but most often from keys being leaked through flaws in the security model.

Using a third-party service for your security allows you to not have a single point of failure. Seald.io proposes a robust security model, certified by the ANSSI, with real-time access-management control, user revocation and recovery, 2FA, and more.

Goals 🏆

This article explains how to integrate Seald with PubNub step-by-step, in order to secure your chat with end-to-end encryption. We will build an example messaging app, with the following features:

  • One-to-one and group chat rooms.

  • Each member has a dedicated chat room with every other user.

  • Anyone can create a group chat room with multiple other users.

  • Use end-to-end encryption for every message and file sent.

  • Allow real-time access management to chats.

Implementation 🧠

Set up a PubNub account 👤

To get started, you will need a PubNub account. You can sign up here. Once logged in on your dashboard, you should see that a demo app with a demo keyset has been created:

Select the demo keyset, and scroll to the configuration tab. For our demo, we need to activate Files and Objects permissions. For the Object permission, we will use the following events: User Metadata EventsChannel Metadata Events andMembership Events.

Once the keyset is created and configured, we need to copy it to our frontend.

Let's create a JSON file on the src/ folder, called settings.json. We will use this file for all the API keys we will need. Starting with the PubNub keyset:

Building a basic chat using PubNub 💬

We will use PubNub for almost every backend task. Our backend will only handle user sign-up/sign-in, and use a minimalist user model with only an ID, a name, and an email.

On the front side, we need a small authentication interface:

Once the user has an account, the first thing they need is an instance of the PubNub SDK.

To identify the user on Pubnub, we need to provide a UUID.

To keep things simple, we will use the same ID as on our backend:

To keep our backend as simple as possible, we will use PubNub's user metadata to exchange users' info.

Just after the SDK instantiation, we simply call PubNub setUUIDMetadata function:

Getting initial app state 🌱

The first thing to do with PubNub is to retrieve all existing members and store them in our local data store:

Each chat room will correspond to a PubNub channel. We will also add some metadata to each channel:

  • ownerId: The ID of the user who created the room.

  • one2one: A boolean to differentiate direct messaging rooms and group rooms.

  • archived: A boolean, to hide a deleted group room.

The ownerId metadata will be used later when adding the Seald SDK. PubNub doesn't have an ownership concept, but Seald does. It will define who can add or remove users from a channel. It basically defines a group administrator.

We will start by retrieving existing chat rooms. We will also need the room metadata, so we need to include custom fields. Then, we need to filter out archived rooms and send everything to our data store.

Finally, we subscribe to the PubNub channel associated with the room, so we will receive new messages:

Now we have fetched all the rooms we are in. We need one last thing to finish app initialization: ensuring we have a one2one room with every other member, including newly registered ones.

For every newly found user, we will create a new room and send a hello message.

Then, we will set the room's metadata, and subscribe to it:

Once all that is done, our initial app state is fully defined. However, we need to keep it up to date.

It can be done simply by adding an event listener for membership events:

We can now have a look at a one2one chat room itself. Then we will handle group rooms.

Receiving and sending messages in a chat room 📩

In a chat.js file, we will have all the logic to display the messages of a chat room.

To initialize this room, the only thing we need to do is to fetch all pre-existing messages.

It can be done simply by knowing the room ID:

We can subscribe to the channel to get new messages, and add a listener to display them in real-time:

To send a message, we simply need to publish it on the channel:

To send a file, we will first upload it to PubNub. Then we will get the uploaded file URI, and publish it as a message in the chat room:

Managing group chat 👨‍👩‍👦‍👦

To create and manage groups, we will need an interface for selecting users:

Once the group members have been selected, we can create a PubNub channel for our room, and then set metadata and membership for the channel. The code is very similar to what is done for one2one rooms, so we will not repeat it here.

We now have a full chat app. Let's add end-to-end encryption for every message!

Adding end-to-end encryption with Seald 🔒💬

Set up a Seald account 👤

To start with Seald, create a free trial account here

When landing on the Seald dashboard, a few URLs and API tokens are displayed.

Get the following elements:

  • appId

  • apiURL

  • keyStorageURL

We will add these keys to our settings.json:

To be able to use the Seald SDK, every user needs a licence JWT when signing-up.

These JWT needs to be generated on the backend using a secret and a secret ID.

From the dashboard landing page, copy the JWT secret and its associated ID in backend/settings.json:

During the signup API call, we will generate a Seald licence JWT, and return it back:

For more information about this, see our documentation article about JWT.

Then, we need to install the Seald SDK.

We also need to install a plugin to identify users on the Seald server. To do so, we will use the sdk-plugin-ssks-password package.

This plugin allows for simple password authentication of our users:

Instantiating the Seald SDK 💡

Then, we will create a seald.js file. In this file, we will start by creating a function to instantiate the Seald SDK:

Creating and retrieving Seald identities 🔑

In seald.js, we will also add two function: one to create an identity and one to retrieve one. To create an identity, we also need the licence JWT returned at account creation:

During our signup and sign-in flows, we just need to call these functions after the user has logged in.

At this point, every time our user is connected, he has a working Seald SDK, ready to encrypt and decrypt!

Warning: For proper security, the password should be pre-hashed before being sent to the authentication server. For more details on this, please see the paragraph about password authentication in our documentation.

Start encrypting and decrypting messages 🔒🔓

Each chat room will be associated with an encryptionSession on the Seald SDK.

Every time we create a chat room, we simply have to add one line to create the encryption session, then use it:

Note that our user is included by default as a recipient of the encryptionSession.

When accessing a room, we need to get the corresponding encryptionSession. It can be retrieved from any encrypted messages or file. Once we have it, we'll keep it in component reference.

Then we can simply use session.encryptMessage ,session.encryptFilesession.decryptMessage and session.decryptFile functions.

Let's start with the messages. To send a message:

And when we receive a message:

Also, we use this decryptMessage function to decrypt all messages already in the session when opening a room:

And now for files. To upload a file:

And to decrypt a file:

Managing group members 👨‍👩‍👦

Group chats will also have their encryptionSession. Every time a group is created, we need to create one:

Then, every time we modify group members, we will need to add or remove them from it:

Conclusion ✅

Once that's done, we're finished!

We managed to integrate Seald into PubNub with only a few lines of code.

Now that the chat is end-to-end encrypted, you can assure your users that their data will remain confidential, even in case of data breaches.

As always, don’t hesitate to contact Seald or contact PubNub  if you need any additional guidance.

Can’t wait to see what you've built 🥳.

0