Per-User Encryption in Elixir III

Sharing user-encrypted data using public-private key pairs

Badu
5 min readJun 13, 2020

This is the follow up to a series of posts on securing sensitive user data using encryption. The first two posts explored how to encrypt user data using symmetric encryption by using user tokens such as a password or a PIN.

In this post, we will explore
1) Securing user data using public-private keys (asymmetric encryption)
2) Allow users to securely share encrypted data with other users
3) Allowing multiple users to securely modify a shared encrypted data

Using symmetric encryption work for simple scenarios where data sharing is not required. However, it becomes a challenge when a user wants to share encrypted data with other users. Better still, allowing multiple users to edit the same encrypted document. The challenge is that by using symmetric encryption, data is encrypted with a single key and can only be decrypted with the same key. Since our per-user encryption implementation is using a password-derived key to encrypt a user’s data, we can’t use symmetric encryption as we will have to know the user’s password or PIN for other users to access or make changes to data encrypted by that user. This defeats the whole point of security. This is where asymmetric encryption becomes useful.

What is asymmetric encryption

Asymmetrical encryption (also known as public-key cryptography) uses public and private keys to encrypt and decrypt data. The private key must be secured but the public key can be made public. A user can encrypt a message using the receiver’s public key, but that encrypted message can only be decrypted with the receiver’s private key. This means we can share encrypted data between users just by using their public keys.

General Idea

First, in addition to a password derived key, each user will be assigned a public-private key pair. The private key will be encrypted with the user’s password derived key in order to ensure only that user has access to the private key. Then each document to be encrypted will have a separate unique key for encryption. Each user who has access to the document will have a copy of the document key encrypted with the user’s public key — meaning will require the user’s private key to decrypt the encrypted document key. Since the private key can only be decrypted by using the password-derived key, only the user can decrypt the encrypted document key.

Entities

User — a user has an identifier such as an email and token such as a password (or a PIN). A user also has a public-private key pair and a password-derived key.

Document — data that must be secured. To keep it simple, our document model has two fields; one for id and another for the encrypted data.

User Document — associate a user with a document. A user document has (optional) id, a user id, document id, and the encrypted document key for that user.

UML

The previous post explains how password derived keys work so we will focus on how the asymmetric encryption works in this post.

Registering a New User
During user registration, we’ll generate a public-private key pair for the user. Using the user’s password-derived key to encrypt the private key (ensuring that only that user can decrypt the private key).

Creating Encrypted Documents with Document Keys
In order to ensure a document can be shared and edited by multiple users, each document will be assigned a unique key that will be used to encrypt the data. The document key will NOT be stored with the document. Rather, each user that has access to the document will keep an encrypted copy of the document key. For each user that we want to give access to, we will encrypt the document key using the user’s public key. This means only that user can decrypt it with their public and private keys. And since the user’s private key is encrypted with a password-derived key, only the user (i.e those who know the password) can decrypt the private key and hence decrypt the encrypted document key to get the actual document key to decrypt the document content.

Also, this ensures that users who have access to the document can share it with other users simply by first decrypting their encrypted document key and encrypting the document key with the public key of the user they want to share the document with.

Updating the Encrypted Document
When updating the document, first, we retrieve the encrypted document key for the user that wants to update the document. Decrypt it with the user’s private-public key pair. Once we have the decrypted document key we can encrypt the new content with that key and save the document. Since we used the same key to encrypt the new content, other users who already have access to the document will still be able to have access to the updated document.

Considerations
It’s assumed that the document key remains unchanged from the time it was created. If you want to change the document key you should update the key for all users that have access to the document. The operation should be run in a transaction to ensure atomicity.

If a user loses access to the document, another user can grant access to the document again for that user. Simply by removing the user’s access and following the steps to share the document with that user.

You can have access control level whereby only certain users (e.g the creator) can share the document with other users. In this case, the application must check ownership of the document before allowing the user to share

Check out the next post in which we implement this in an Elixir project.

Happy coding!

--

--