Temporary Encryption

This feature is available for Swift, Kotlin and Java. It's not yet available for JavaScript.

In this guide, you'll learn how to create and use temporary channels in order to send encrypted data to users not yet registered on the Virgil Cloud.

Before proceeding with this implementation, make sure you've considered other options such as not allowing communication with unregistered users. We lay out some ideas in this article.

About temporary channels

For communication between a registered and unregistered users, true end-to-end encryption is not possible since it requires all the involved parties to have established asymmetric key pairs.

To help with the case where communication between a sender and an unregistered recipient is absolutely required, E3Kit provides an alternative that is less secure than end-to-end encryption, but still far more secure than plaintext communication.

When a user wants to send encrypted data to a recipient that isn't yet registered, the recommended solution is to create an temporary channel with the unregistered recipient's future identity. This identity is the one that will be used in the JWT generation for that user to authenticate with at Virgil Cloud.

The temporary channel consists of a temporary key that is safely stored in Virgil's Keyknox service. After the creation of the temporary channel, it's possible to encrypt data that can be decrypted by the recipient as soon as they register.

Note that, while this approach is secure and is built into E3Kit, it is not part of the true end-to-end encryption flow E3Kit offers for registered user communication. It should be used sparingly and with caution. After the recipient registers and decrypts the messages from the temporary channel, it's recommended to delete the temporary channel establish the usual end-to-end encrypted flow.

Before you begin

Be sure to implement the following:

Create the temporary channel for an unregistered user

In order to encrypt a message to an unregistered user, the sender must first create an temporary channel with the recipient's future identity.

ethree.createTemporaryChannel("Bob")
      .addCallback(new OnResultListener<TemporaryChannel>() {
          @Override public void onSuccess(TemporaryChannel temporaryChannel) {
              // Channel created and saved locally!
          }

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

Encrypt data with the temporary channel

After the temporary channel is created, data can be encrypted and sent:

String encryptedText = channel.encrypt("Hello, Bob!");
// send encryptedText

Data encryptedData = channel.encrypt(new Data("Hello, Bob!".getBytes()));
// send encryptedData

Load temporary channel

Once the recipient is registered, they are able to join the temporary channel:

ethree.loadTemporaryChannel(false, "Bob")
      .addCallback(new OnResultListener<TemporaryChannel>() {
          @Override public void onSuccess(TemporaryChannel temporaryChannel) {
              // Channel loaded and saved locally!
          }

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

If the channel creator changed devices or cleaned up the current one, they can load temporary channel in a similar way:

ethree.loadTemporaryChannel(true, "Bob")
      .addCallback(new OnResultListener<TemporaryChannel>() {
          @Override public void onSuccess(TemporaryChannel temporaryChannel) {
              // Channel loaded and saved locally!
          }

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

After loading or creating the channel, you can use the getTemporaryChannel method to retrieve it from local storage:

TemporaryChannel channel = ethree.getTemporaryChannel("Alice");

Decrypt data with the temporary channel

After the channel is joined, and the encrypted data fetched, it can be used for decryption:

// fetch encryptedText
String decryptedText = channel.decrypt(encryptedText);

// fetch encryptedData
Data decryptedData = channel.decrypt(encryptedData);

Delete the temporary channel

After the messages from the temporary channel are decrypted by the recipient, it's highly recommended to delete the temporary channel, and establish regular end-to-end encryption from then on.

ethree.deleteTemporaryChannel("Bob")
      .addCallback(new OnCompleteListener() {
          @Override public void onSuccess() {
              // Channel was deleted!
          }

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

Limitations

Not true end-to-end encryption

As laid out in the introduction of this guide, this method does not support true end-to-end encryption. Unless communication with unregistered users is a requirement, consider using the other encryption methods available.