End to end encryption on Cloud Platforms

Jay Pavagadhi
4 min readSep 14, 2019

--

In the world where data breaches and concerns over personal data privacy are increasing, it’s worth rethinking about who should really have access to user’s data. With dominance of cloud services, in most cases, cloud providers have direct access to client’s data. Not that they have any incentives to access or monitor it or they would ever attempt it, theoretically it’s very well possible. Also, cloud providers are subject to complex local government laws and policies and so does your users’ data. All in all, it’s always a good idea to restrict data access to minimal number of persons and entities. Ideal scenario would be just the owner of the data should have access to it and no one else.

Question is, how can we achieve this while still using cloud platform and preferably with minimal work?

Let us take an example of simple app which stores user’s notes. For that, we would need a good authentication mechanism and a database service. Instead of reinventing the wheel, as we discussed, we would use existing cloud services. Let us use Amazon Cognito and DynamoDB for this.

A typical app architecture would look like this –

A user authenticates with her credentials against Cognito and gets necessary tokens to further access restricted database service.

Encryption

What we need to make sure is, data is encrypted on client device before it gets on wire. And here’s how we can do that –

import * as forge from 'node-forge';const note = 'This is a secure note. Only I can read it, no one else!’const encryptionAlgorithm: forge.cipher.Algorithm = 'AES-CBC';const cipher = forge.cipher.createCipher(encryptionAlgorithm, encryptionKey);
cipher.start({iv: iv});
// Uint8Array to binary encoded string to forge ByteBuffer
cipher.update(forge.util.createBuffer(forge.util.binary.raw.encode(data)));
cipher.finish();
const encryptedNote = cipher.output.getBytes()

We are using industry standard 256-bit AES encryption. We would use forge – a JavaScript crypto library to encrypt user notes.

Encryption Key

If we look at the code, it’s apparent that we need an encryption key. It’s hard to memorize 256-bit long key, so it’s good idea to derive it from password. We can use a good hash function to generate one. Also, in order to avoid dictionary attacks, it’s a good idea to use salt. And for that, we can use another piece of user credential – the username.

const encryptionKeySize = 32;  // 32 bytes (256 bit)const pbkdf2RoundsForEncryptionKey = 101010;const md = forge.md.sha256.create();

const encryptionKey = forge.pkcs5.pbkdf2(password, username, pbkdf2RoundsForEncryptionKey, encryptionKeySize, md);

We are using PBKDF2 – a password hashing algorithm. We can easily plug in other algorithms like bcrypt or scrypt if we are not targeting wide range of platforms. Password hashing functions are inherently slow to counter brute force attacks and to make it even slower we will use large number of iterations.

Password Hash

Cognito doesn’t store passwords in plain text, instead it uses SRP protocol for authentication and stores verifiers instead. We can always add extra protection on top of that by using password hash as Cognito password.

We don’t want encryption key as password hash, so we can probably derive different password hash with additional rounds of hashing on top of encryption key. But that has different set of problems. Since you can easily get long lived access tokens to keep user signed in, you would need to preserve encryption key in memory/disk in order to decrypt retrieved data. So, if someone gets hold of your encryption key, they can easily generate password hash as well.

A smart workaround that I figured is to use a different salt – reverse of username. That would give us a completely different password hash that we are looking for. And that’s what we would use as Cognito password at the time of sign up and for subsequent sign ins.

That is all what we need to restrict everyone but the user to have access to her data. But this also means, if user forgets her username or password, she may lose all the data. In order to support password recovery or if we require to access users’ data, we can store encryption keys to different cloud provider, preferably in different jurisdiction.

--

--