End to End Authenticated Encryption with Associated Data (AEAD)

Qingping Meng
The Startup
Published in
4 min readJun 30, 2020

Recently my work requires me to implement the encryption of the credentials entered by the customer from the browser and the decryption at server side, in a secure and compliance manner.

The first thought came to my mind was the RSA public key/private key encryption algorism, which is straightforward.

Code is also straightforward:

https://gist.github.com/QingpingMeng/f51902e2629fc061c6b9fc9bb0f3f57b

This worked fine until I learned asymmetric encryption can only encrypt small amount of data which is up to the length of key size modulus minus a small number depending on padding mode.

After some research, it’s usually recommended to use symmetric encryption like AES to encrypt the data where the limit of data size is infinite, then use RSA public key to encrypt the AES symmetric key and finally send the encrypted key and encrypted data to the server.

The difference here is to generate an AES key with a random iv (initiate vector) from the browser. The plain text is encrypted using the generated AES key. Since this is a symmetric encryption, plain text can be any size. Next, we use the RSA public key to encrypt the AES key. The final cipher text will be the concatenation of encrypted key, iv and encrypted data. Note iv is required for the server side to restore AES decryption.

Sample code: https://gist.github.com/QingpingMeng/f3d83886f66efa75df577b6ed811c5ba

Now this seems good enough, isn’t it? Actually, not really. This is still not perfect because the server cannot validate the received encrypted data was tempered or not. In other words, the server cannot validate the authenticity of the encrypted data.

There need to be some sort of signature of the encrypted data as part of the final payload so whoever receives the data is confident about its authenticity. So, let’s do solve it now.

Now a new key HMAC key is generated on the browser side, which is a 32-byte random data. This HMAC key is used to sign the encrypted data and iv using SHA512 hash function, the result is appended to the final cipher text. At the same time, this HMAC key along with AES key is encrypted using RSA public key so encrypted key now includes two keys.

How adding an HMAC key can prevent the encrypted data from being tampered?

When server side received the cipher text, it can get the HMAC key and AES key buy decrypting the corresponding part. Next, server can use AES to get encrypted data and use HMAC key to re-calculate the authentication tag to make sure the result matched the authentication tag part of cipher text.

Image the message was intercepted, since the attacker didn’t have the private key, it cannot know the HMAC key (HMAC is generated for each encryption and only browser know it). If attacker attempt to temper the data, the authentication tag will not match, and server can just throw this tampered message away.

In this way, a secure E2E encryption is established.

Well till now, this is already very secure solution, but a little bit from perfection. Image the browser side need to send some insensitive payload to the server like the algorithms for encryption and signing and server can get this payload without decrypting the cipher text.

So, we can add an extra header payload to the final cipher text. This payload is not participating the encryption but need to be protected from being tampered like the payload part of JWT.

Note a new input headers is introduced in this iteration. headers is base64Url encoded into a (short for associated data) and the length of headers is base64Url encoded into a_length .

The length of the associated data input a is included in the HMAC input to ensure that the encryptor and the decrypter have the same understanding of that length. Because of this, an attacker cannot trick the receiver into interpreting the initial bytes of cipher text as the final bytes of a.

a and a_length are sent for calculating the authentication tag and a is appended to the first part of the final cipher text.

Now when server receives the final cipher text, it can extract the first part and decoded to get some unencrypted data.

To make the server’s life easier without struggling to split the cipher text into various parts by byte size, we can leverage JWE (Json Web Encryption) to build the cipher text in this format.

This is exactly what is described below:

[AEAD-CBC-SHA] https://tools.ietf.org/html/draft-mcgrew-aead-aes-cbc-hmac-sha2-05

[RFC7516] https://tools.ietf.org/html/rfc7516

Final code sample for encryption at browser and decryption at server side:

https://gist.github.com/QingpingMeng/2313a08f6d86a4c1ac7eae7e52b2e54b

--

--