AWS Encryption SDK

This is part 03 of Data Encryption on the AWS series. You may find the related video for this blog post here.

In the previous blog post, we discussed how to use OpenSSL with AWS KMS in order to encrypt/decrypt sensitive data. You can find the previous blog post here. Today let us focus on AWS Encryption SDK with an example.

What is AWS Encryption SDK?

The AWS Encryption SDK is a client-side encryption library designed to make it easy for everyone to encrypt and decrypt data using industry standards and best practices. It enables you to focus on the core functionality of your application, rather than on how to best encrypt and decrypt your data.

Source — AWS Documentation

AWS Encryption SDK only requires us to provide it a master key(s) and then we can use straightforward methods to encrypt or decrypt our data at the client-side.

You don’t have to worry about which encryption algorithm to use, how to maintain data-keys for the given master keys and how to ensure the data has not tampered between the time it is written and when it is read. AWS Encryption SDK handles everything for you. That makes our lives very easy!

At this point in time, AWS Encryption SDK supports JavaScript, C, Java and Python languages. We use JavaScript SDK for the example below.

When to use AWS Encryption SDK?

You can use Encryption SDK for Client-side encryption in browsers and other clients (e.g. EC2 instance that process data before storing in S3/Database). It is quite useful to encrypt data in distributed systems that communicate with different microservices and third party services.

However, AWS offers two other encryption clients for client-side encryption of data.

  1. DynamoDB Encryption Client
  2. S3 Encryption Client

AWS Encryption SDK and above encryption clients are not compatible. You cannot decrypt data that is encrypted by DynamoDB Encryption Client using AWS Encryption SDK. AWS recommends using above encryption clients if you are specifically working with DynamoDB or S3 as they provide additional functionalities suitable for DynamoDB or S3. For example, DynamoDB Encryption Client preserves partition/sort keys and encrypt only other data attributes.

AWS Encryption SDK can be used for general encryption workloads.

How to use AWS Encryption SDK?

AWS Encryption SDK provides SDKs for various programming languages. If you JavaScript SDK to encrypt data in the browser, you can use any other SDKs (e.g. Java, NodeJS) to decrypt at the server-side.

Following is an example of how you can use the Encryption SDK in NodeJS.

Step 01 — Setting up Encryption SDK for NodeJS

First of all, you need to install the AWS Encryption SDK for NodeJS.

npm install @aws-crypto/client-node

Then require KmsKeyring, encrypt and decrypt methods from the SDK

const { KmsKeyringNode, encrypt, decrypt } = require("@aws-crypto/client-node");

This example uses KMS as the Key management infrastructure. So we have to use KMS Keyring. As the names suggest, encrypt and decrypt methods are used to encrypt and decrypt data with datakeys generated by the keyring.

Note

AWS Encryption SDK for JavaScript uses Keyring to perform Envelope Encryption that is encrypting data keys with the master keys in KMS. You need to provide a reference to the Master Key and then the Keyring will create and manage datakeys to encrypt and decrypt data.

Step 02 — Configuring KMSKeyring with a CMK

Now that we have required the KMSKeyring, let’s configure it using a CMK (Customer Master Key) created in AWS KMS. You can provide the Arn of the CMK to configure with the keyring.

const masterKeyId = "arn:aws:kms:us-east-1:123456:key/beee-abce-..";
const keyring = new KmsKeyringNode({ masterKeyId });

(You can also provide multiple master keys in order to encrypt a datakey multiple times for better security as well)

Step 03 — Creating an Encryption Context

You can optionally create an encryption context for your plain text sensitive data in order to verify if the data has been tampered by anybody at decryption. (It is recommended to create an encryption context).

First, create a context with any useful metadata. Then pass the context to the encrypt method together with the plaintext sensitive data.

let plainText = "My passwords for senstive data";

const context = {
accountId: "100",
purpose: "youtube demo",
country: "Sri Lanka"
};

Step 04 — Encryption & Decryption

Now that we have the encryption context, we can start encrypting the data with Encryption SDK.

let plainText = "My passwords for senstive data";

const { result } = await encrypt(keyring, plainText, { encryptionContext: context });

We use the encrypt method from the SDK and pass the keyring, plaintext and the encryption context as the parameters. As a result, we get the encryption version of the plaintext sensitive data.

We can decrypt this encrypted data in a different microservice in the distributed system by using the decrypt function of the SDK. The decrypt function expects the encrypted data and the keyring as the parameters.

const { plaintext, messageHeader } = await decrypt(keyring, encryptedData);

It will return the plaintext data and the “messageHeader” as a result of decrypt call. The messageHeader contains the encryption context we added at the point of encryption. So now we can verify that in order to make sure the data has not been tempered.

Step 05 — Verifying Encryption Context

Let’s compare the original encryption context and the context returned by the decrypt call.

let originalContext = {
accountId: "100",
purpose: "youtube demo",
country: "Sri Lanka"
};

Object.entries(originalContext).forEach(([key, value]) => {
if (messageHeader.encryptionContext[key] === value) {
console.log("Awesome. It is matching!");
} if (messageHeader.encryptionContext[key] !== value) {
throw new Error("Someone has changed the data");
}
});

If all the original context attributes are matching, we can conclude that the encrypted data is intact.

References

https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/introduction

Please follow and like us:

Data Encryption on AWS — Part 02

In part 01, we discussed the main concepts around AWS KMS.

OpenSSL and AWS Encryption SDK are used for Client-Side Encryption outside AWS. This blog post is focused on how to interact with KMS using AWS CLI and OpenSSL for data encryption and decryption. In the next part, we will also discuss the AWS Encryption SDK with examples.

Encrypt/Decrypt using OpenSSL

OpenSSL is a full-featured cryptographic library that we can use to communicate with AWS KMS over the command-line interface. (You can install the OpenSSL toolkit for your operating system)

Step 01 — Creating a CMK

Let’s start by creating a CMK in our AWS account. This can be done using the AWS Console, AWS SDKs or AWS CLI. I use the AWS Console.

Login to your AWS account and go to AWS KMS.

Select the region N.Virginia (us-east-1) from the top right side of the console and click “Create Key”

Select Symmetric encryption type and click “Next”. In Symmetric Encryption, the same key is used for both encryption and decryption. AWS recommends using Symmetric CMK for most cases.

“Use a symmetric CMK for most use cases that require encrypting and decrypting data. The symmetric encryption algorithm that AWS KMS uses is fast, efficient, and assures the confidentiality and authenticity of data.” — AWS Documentation

Provide an alias to the key in the next step. Alias is useful to reference the CMK easily.

Tell KMS about the key administrators. By default, the root user has all the permissions. You can select IAM users who can administrate the key and use the key. Click next.

Now select the IAM users who need key usage permissions.

Finally, review the permissions and click finish to create the CMK.

Step 02 — Generating Data-Keys for the CMK

A CMK only allows encrypting data that is less than 4KBs. If we have a large payload to encrypt, then we need Data Keys generated from that CMK. (See the video for more details).

Let’s use AWS CLI to call KMS service and generate data keys for the CMK we just created.

Note: Follow the instruction to install AWS CLI and configure in your operating system.

We refer to the CMK by the alias (e.g. youtube) we have provided during the creation process at step 01.

aws kms generate-data-key --key-id alias/youtube --key-spec AES_256 --region us-east-1

Response (This is mock data)

{
"KeyId": "arn:aws:kms:us-east-1:123456789:key/bbee76a1-bd25-4d57-81d8-38ff2b26468a",
"Plaintext":"7DmPVPgzJ8exc9+AekcEmVL7jdv0RWMxPgA4JlrpE4k=",
"CiphertextBlob":
"ADIDAHiiF6PCTM1Hou+61r+M/pyUfwSizO02mH9+pIa0gaFRWwFF+FoN25Pm+tdPZiB0paGRAAAAfjB8BgkqhkiG9w0BBwabbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMIB9YpWJsDdZjP4BVAgEQgDvigjj2IaJoDmXJPS2AWG6OHqMwI8H5ybsS6l0Rt26fVUskQTxxWvCzkLSqssqi3bDnEysfaxN/ryXO7w=="
}

It returns both the Plaintext version of the data key and the Encrypted or Ciphertext version of the same data key. Both these keys are base64 encoded. So let’s decode and save them into datakey and encrypted-datakey files

echo "7DmPVPgzJ8exc9+AekcEmVL7jdv0RWMxPgA4JlrpE4k=" | base64 
--decode > datakey

echo "ADIDAHiiF6PCTM1Hou+61r+M/pyUfwSizO02mH9+pIa0gaFRWwFF+FoN25Pm+tdPZiB0paGRAAAAfjB8BgkqhkiG9w0BBwabbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMIB9YpWJsDdZjP4BVAgEQgDvigjj2IaJoDmXJPS2AWG6OHqMwI8H5ybsS6l0Rt26fVUskQTxxWvCzkLSqssqi3bDnEysfaxN/ryXO7w=="
| base64 --decode > encrypted-datakey

We will use them in the next step.

Step 03 — Encrypting data with Plaintext Data-Key

Now we use the Plaintext data key to encrypt our data.

First of all, we need data to encrypt. Let’s create password.txt file with some data. In general, this will be the sensitive data that we need to protect.

echo "My database password" > password.txt

Now, let’s use the datakey to encrypt our sensitive data. We will output the encoded data into a file called secret.txt.

openssl enc -in ./passwords.txt -out ./passwords-encrypted.txt -e -aes256 -k fileb://./datakey

After encrypting the data, we must NOT forget to delete the plaintext-datakey. Otherwise, anyone can use that key to decrypt our secret data.

rm datakey

Step 04 — Decrypting data with Encrypted Data Key

Now that we have removed the key that was used to encrypt the data, how do we decrypt it at a later point in time?

For that, we use encrypted-data-key that was stored with the encrypted data. We already discussed KMS concepts in-depth in the previous blog post as well as in the Data Encryption on AWS video.

We need to pass the encrypted-data key to KMS and request for the plaintext-data key. It will return the same plain text data key that we used to encrypt the sensitive data.

aws kms decrypt --ciphertext-blob fileb://./encrypted-datakey  --region us-east-1

[Output - Mock data]
{
"Plaintext": "xyQtd+/oB0ob1Gr9dmkQ4JBSR1+jQRZrK1sLAVdJIHg=",
"KeyId": "arn:aws:kms:us-east-1:123456789:key/beae46a1-bd25-4d37-81d8-38ff1b26469a"
}

Great! Now we can use this Plaintext data key to decrypt our data. But first, let’s do base64 decode and save it as datakey again.

echo "xyQtd+/oB0ob1Gr9dmkQ4JBSR1+jQRZrK1sLAVdJIHg=" | base64 
--decode > datakey

Now finally we can decrypt our encrypted data with the datakey that we received. The decrypted sensitive data is output to a file called passwords-decrypted.txt.

openssl enc -in ./passwords-encrypted.txt -out ./passwords-decrypted.txt -d -aes256 -k fileb://./datakey

Now if you open the passwords-decrypted.txt you should find the original plaintext data.

Congratulations! We have successfully completed the encryption and decryption of our sensitive data.

Please follow and like us:

Data Encryption on AWS

This blog post is related to Data Encryption on AWS youtube video.

Imagine that your server got hacked. Now, the hacker has full access to the sensitive data stored on the disk. You are in big trouble since you haven’t encrypted that data and the hacker can do whatever he wants with your plain text data.

Encryption is vital if you deal with sensitive data that must not be accessed by unauthorized users. Regulations like GDPR (General Data Protection Regulation) instruct companies to encrypt both data at transit and data at rest. This article is about how to encrypt your data on AWS.

Encryption at Rest vs in Transit

When you deliver your website over HTTPS by associating an SSL certification with your domain, the browser makes sure to encrypt the data in transit. The communication between the browser and the server is encrypted. However, as soon as the data (e.g. username and password) gets to the point where the SSL termination happens (At the server itself, Load Balancer, CloudFront, etc…) the encrypted data is decrypted. After that, the server is storing the plain text (e.g. username and password) in the server storage or in databases. If you want to avoid saving plain text, you have to enable encryption at rest.

Encryption at Rest

This is about encrypting the data that you store in the backend servers and databases. There are two main methods to encrypt data at rest.

  1. Client-Side Encryption
  2. Server-Side Encryption

Client-Side Encryption

As the name implies this method encrypts your data at the client-side before it reaches backend servers or services. You have to supply encryption keys 🔑 to encrypt the data from the client-side. You can either manage these encryption keys by yourself or use AWS KMS(Key Management Service) to manage the encryption keys under your control.

AWS provides multiple client-side SDKs to make this process easy for you. E.g. AWS Encryption SDK, S3 Encryption Client, DynamoDB Encryption Client etc…

Server-Side Encryption

In Server-Side encryption, AWS encrypts the data on your behalf as soon as it is received by an AWS Service. Most of the AWS services support server-side encryption. E.g. S3, EBS, RDS, DynamoDB, Kinesis, etc…

All these services are integrated with AWS KMS in order to encrypt the data.

AWS KMS

AWS KMS (Key Management Service) is the service that manages encryption keys on AWS. These encryption keys are called “Customer Master Keys” or CMKs for short. KMS uses Hardware Security Modules (Physical devices, commonly known as HSM) to store CMKs. AWS KMS is integrated with many AWS services and it uses AWS CloudTrail to track the usage logs of the keys for audit and compliance needs.

Customer Master Keys(CMKs) VS Data Keys

CMKs are created and managed by AWS KMS. However, CMK is only used to encrypt a small amount of data less than 4KBs. AWS does not encrypt the gigabytes of data using CMK. If you have large data to encrypt, then use Data Keys.

Data Keys are generated from CMKs. There is a direct relationship between Data Key and a CMK. However, AWS does NOT store or manage Data Keys. Instead, you have to manage them.

Look at the following diagram.

Image 1 — Generate Data Keys from a CMK (Ref — AWS Documentation)

You can use one Customer Master Key (CMK) to generate thousands of unique data keys. You can generate data keys from a CMK using two methods.

  1. Generate both Plaintext Data Key and Encrypted Data Key
  2. Generate only the Encrypted Data Key

Image-1 illustrates how to generate both plain-text and encrypted data keys using a CMK.

Encrypt/Decrypt Data

Once you get the Plaintext data key and Encrypted data key from CMK, use the Plaintext data key to encrypt your data. After encryption, never keep the Plaintext data key together with encrypted data(Ciphertext) since anyone can decrypt the Ciphertext using the Plaintext key. So remove the Plaintext data key from the memory as soon as possible. You can keep the Encrypted data key with the Ciphertext. When you want to decrypt it, call the KMS API with the encrypted data key and KMS will send you the Plaintext key if you are authorized to receive it. Afterward, you can decrypt the Ciphertext using the Plaintext key.

Envelope Encryption

The method of encrypting the key using another key is called Envelop Encryption. By encrypting the key, that is used to encrypt data, you will protect both data and the key.

Image 2 — Envelop Encryption (Ref — AWS Documentation)

In AWS you can encrypt the Data key used to encrypt the Data with Customer Master Key(CMK). But, where do you store the CMK? AWS KMS will store it inside Hardware Security Module (HSM) with a greater level of protection. (HSM is compliant with FIPS 140–2 security standard)

Key Policies

One of the powerful features in KMS is the ability to define permission separately for those who use the keys and administrate the keys. This is achieved using Key Policies.

{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::111122223333:root"},
"Action": "kms:*",
"Resource": "*"
}

The above key policy is applied to the root user of the account. It allows full access to the CMK that this policy is attached. When it comes to other users and roles you can manage key usage and key administration as follows.

{
"Sid": "Allow use of the key",
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::111122223333:user/manoj"},
"Action": [
"kms:Decrypt",
"kms:DescribeKey",
"kms:Encrypt",
"kms:GenerateDataKey*",
"kms:ReEncrypt*"
],
"Resource": "*"
}

The above policy is applied to the IAM user ‘manoj’. Now he has permission to use the CMK for encryption and decryption. However, he is not allowed to administrate that CMK.

{
"Sid": "Allow access for Key Administrators",
"Effect": "Allow",
"Principal": {"AWS": [
"arn:aws:iam::111122223333:user/KMSAdminUser"
]},
"Action": [
"kms:Create*",
"kms:Describe*",
"kms:Enable*",
"kms:List*",
"kms:Put*",
"kms:Update*",
"kms:Revoke*",
"kms:Disable*",
"kms:Get*",
"kms:Delete*",
"kms:TagResource",
"kms:UntagResource",
"kms:ScheduleKeyDeletion",
"kms:CancelKeyDeletion"
],
"Resource": "*"
}

Now, the above key policy allows administrators to administrate the CMK that it is applied to. However, the administrator cannot use the key to Encrypt or Decrypt data.

Key Rotation

Cryptographic best practices discourage extensive use of encryption keys. Because of that, AWS allows rotating the Customer Master Key(CMK). You can enable the automatic renewal option for the CMKs that you have created in KMS. The CMKs that you have created in KMS are commonly known as Customer Managed CMKs. Once you enable automatic key renewal, KMS renews the key’s cryptographic material(Backing Key) in every year. However, CMKs managed by AWS are only renewed every three years. You cannot change the renewal frequency for AWS managed CMKs.

Reference – AWS Documentation

It is important to understand that AWS KMS saves references to the older backing keys when renewing. So that KMS is able to decrypt data or data keys that were generated by older versions of backing keys. Otherwise, those data/data keys can never be decrypted.

In the next post, let’s discuss S3 and EBS encryption.

Please follow and like us: