← All use cases
Key Management·20 min

Envelope encryption: how a KMS actually protects your data

Every cloud KMS — AWS KMS, GCP Cloud KMS, Azure Key Vault, HashiCorp Vault — uses the same pattern to encrypt data without ever moving your master key. Here's why, and how it actually works.

Developer / EngineerSecurity ArchitectIT Ops / DevOps

The problem envelope encryption solves

The obvious way to use a KMS is to send it your data and ask it to encrypt that data directly with your master key. Almost no production system actually does this, for a simple reason: a KMS's whole security model depends on the master key never leaving a tightly controlled, audited boundary (an HSM or an equivalent hardware root of trust) — but encrypting gigabytes of data one API call at a time, inside that boundary, is both slow and a poor match for what an HSM is built to do well.

Envelope encryption solves this by splitting the job in two: a fast, local, symmetric key does the actual bulk encryption (using AES-GCM, covered in the AES module), and the KMS's master key is used only to encrypt that one small key — never the data itself. The master key's job shrinks to something an HSM handles extremely well: wrapping and unwrapping keys, which are always small, fixed-size, and few in number compared to the data they protect.

The pattern: a Data Key wrapped by a Key-Encryption Key

The key that actually touches your data is called a Data Encryption Key (DEK) — generated fresh, used locally, and never stored anywhere in plaintext. The key that protects the DEK is the Key-Encryption Key (KEK) — the KMS's master key, which never leaves the KMS boundary in plaintext, ever. "Wrapping" is just encrypting the DEK with the KEK; "unwrapping" is decrypting it back.

What gets stored alongside your ciphertext isn't the DEK itself — it's the wrapped (encrypted) DEK. That's the entire trick: the only thing that can turn a wrapped DEK back into a usable key is the KMS holding the matching KEK, so an attacker who steals your encrypted data and its wrapped DEK together still has nothing without access to the KMS itself.

Envelope encryption, end to end

  1. 1

    Request a data key

    The application asks the KMS to generate a new DEK for this object.

  2. 2

    KMS returns two things

    A plaintext DEK (used immediately, then discarded from memory) and that same DEK encrypted under the KEK — the "wrapped" DEK.

  3. 3

    Encrypt locally

    The application uses the plaintext DEK to AES-GCM-encrypt the actual data, entirely outside the KMS.

  4. 4

    Store both pieces together

    The ciphertext and the wrapped DEK are stored side by side — the wrapped DEK is safe to store in the clear, since only the KMS can unwrap it.

Decryption: nothing readable exists until the last step

Reading the data back reverses the exact same path: the application sends the stored wrapped DEK to the KMS, which unwraps it using the KEK and returns the plaintext DEK — the KMS never sees the actual encrypted data, only the small wrapped key. The application then uses that plaintext DEK locally to AES-GCM-decrypt the object.

Notice what this means for a stolen backup or a leaked storage bucket: an attacker with the ciphertext and the wrapped DEK has exactly nothing readable, because turning that wrapped DEK back into something useful requires a live call to a KMS that enforces its own access policy, logging, and (usually) a hardware boundary around the KEK itself.

What it costs: a wrapped key's size, and a KMS call's latency

Wrapping via RSA-OAEP (the padding module covers exactly why raw RSA can't do this safely) produces a ciphertext exactly the size of the KMS's RSA modulus — nothing more, nothing less, regardless of how large the original DEK was. A 4096-bit RSA KEK wrapping a 256-bit AES DEK still produces a 512-byte wrapped output, because RSA ciphertext size depends only on the modulus.

The other real cost is latency: every GenerateDataKey or Decrypt call is a network round trip to the KMS, and at scale that adds up in ways worth actually computing, not just hand-waving about.

wrapped DEK size (bytes)=RSA modulus size in bits8\text{wrapped DEK size (bytes)} = \frac{\text{RSA modulus size in bits}}{8}

Practice

A KMS wraps every DEK using RSA-OAEP with a 4096-bit RSA KEK. How many bytes is the resulting wrapped DEK, regardless of the DEK's own size?

Practice #2

A service generates a fresh DEK via a network KMS call for each of 100,000 small objects it encrypts, with each call taking 20 milliseconds and running serially (one after another). How many total seconds does that add?

Rotating the KEK without touching a single byte of stored data

This is the payoff for the whole design: rotating the master key normally means re-encrypting everything that key ever touched — a massive, risky, often infeasible operation at scale. Envelope encryption sidesteps it entirely. Rotating the KEK just means the KMS starts wrapping new DEKs with a new key version; every already-wrapped DEK still unwraps correctly, because the KMS keeps old key versions available for exactly this purpose. Nothing stored — not the ciphertext, not the wrapped DEK — needs to change at all.

This single property is why envelope encryption, not direct master-key encryption, is the default pattern in every major cloud KMS and in tools like HashiCorp Vault's transit engine — key rotation becomes a KMS-side configuration change instead of a data migration project.

Knowledge check

Test what you just learned →

10 quick questions, with an explanation for every answer.

Up next

Key wrapping and key exchange: moving keys without ever exposing them →

Envelope encryption covers wrapping a key with your own KMS. This is about the broader problem: getting a key from one system, person, or organization to another — without it ever existing in the clear outside a trust boundary.