Problem
Sending all data to a KMS for encryption is slow and hits size and rate limits, while embedding a single key in the app exposes everything if it leaks. Rotating a key that directly encrypted terabytes means re-encrypting all of it.
Also known as: data-key-wrapping, kms-data-keys
Encrypt large data with local data keys and protect those keys with a master key held in a KMS or HSM.
Sending all data to a KMS for encryption is slow and hits size and rate limits, while embedding a single key in the app exposes everything if it leaks. Rotating a key that directly encrypted terabytes means re-encrypting all of it.
Envelope encryption uses two layers of keys. A fast symmetric DEK encrypts data; a KEK that never leaves the KMS encrypts the DEK. Cloud storage services, databases and backup tools all use this under the hood.
Cloud providers already implement this for object and disk encryption, but application-level envelope encryption adds tenant-specific control. Use well-reviewed libraries such as the AWS Encryption SDK or Tink instead of composing primitives yourself, and test the full restore path including KEK access.
encrypt(plaintext):
dek = kms.GenerateDataKey(kekId) # returns plaintext + wrapped copy
nonce = random(12B)
ct = AES-GCM(dek.plain, nonce, plaintext, aad=tenantId)
wipe(dek.plain)
store { ct, nonce, dek.wrapped, kekId }
decrypt(record):
dek = kms.Decrypt(record.dek.wrapped)
return AES-GCM-open(dek, record.nonce, record.ct, aad)
Binding additional authenticated data such as tenant id prevents moving ciphertext between tenants.
Medium — KMS or HSM
Medium — key policies and rotation
Medium
KMS outage or throttling blocks decryption
Deleted KEK makes all wrapped data permanently unrecoverable
Nonce reuse with AES-GCM breaks confidentiality