Envelope encryption is a way to encrypt data in a secure, yet performant.
Before diving into the details, I'm going to use a use case that will help us understand why this method of envelope encryption exists, how its better than other methods etc.
You're working on a secure journalling app. One of the requirements is that all the data is encrypted at rest. Users would like to see all their previous journal entries on a single page. Remember, these entries need to be encrypted when they're stored in our persistence layer.
Symmetric encryption uses the same key to encrypt and decrypt data
Asymmetric encryption uses a keypair - a public key and a private key. The public key encrypts, and the private key decrypts. Slower than symmetric encryption. See this resource that explains asymmetric encryption in HTTPS.
The elements involved in envelope encryption are:
We first generate a random key (in code) that we will use to encrypt our data. This key will be used as a symmetric key to encrypt single journal entries.
What we have now is our encrypted data, and the symmetric key (our DEK) used to encrypt this data. Anyone with access to this DEK will be able to decrypt this data.
Next, we encrypt our data encryption key with yet another key. This new key is our key encryption key (KEK). Usually, a more secure (slower) algotithm is used to encrypt this our DEK.
The encrypted journal entry, and the encrypted data encryption key (DEK) can now be stored together in our store / database / persistent layer.
When this journal entry needs to be displayed, we can fetch our encrypted data, our encrypted data encryption key (DEK). Then, we decrypt the DEK, and use the decrypted DEK to decrypt the journal entry before sending it to the client to read.
Usually, you'd use a cloud service provider's managed key service (eg: Cloud key management (google) or AWS key management service) to encrypt some data.
A KMS will usually have a limit on the size of data it can encrypt (usually around 4Kb). They're not designed to encrypt bulk data like a journal entry.
Also, if we did use a KMS to encrypt an entire journal entry, we'd need to send the entire journal entry over the network any time we wanted to encrypt or decrypt this data, which would have an adverse effect on latency of your system. You'd also be rate-limited quickly. Imagine a scenario where our system has 100 cuncurrent users who each have 50 journal entries. We'd be hitting that rate-limit fairly quick, which will then result in our user's not being able to load their journal entries. There are also cost implications of the amount of data being encrypted by our KMS.
It doesn't matter how secure your app is if your users can't use it.
By only sending our data encryption key (DEK) over the network, we're minimising the data our KMS system needs to process, keeping latency per entry low.
Once we've made the faster call to decrypt our encrypted DEK, its a fairly quick local operation (i.e. does not require a network) to decrypt our journal entry data.
We could further make it more efficient by creating a DEK per user, so we'd only need to make 1 network call to KMS, making the entire operation more efficient. Yes, it comes with some compromises that you'd need to weigh it against.
Some other advantages of using envelope encryption in this context:
The source code for this website can be found here under an MIT license