---
title: "Wrap data keys with a key-encryption key · Agent Wranglers"
url: https://agentwranglers.se/playbook/application-security/cryptography-and-keys/envelope-encryption
id: APS-103
level: Recommended
updated: 2026-10-27
build: a2a6bdfed830
tokens: 1263
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Wrap data keys with a key-encryption key

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Cryptography and keys](https://agentwranglers.se/playbook/application-security/cryptography-and-keys.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers.md). Updated 2026-10-27.

- ID: APS-103
- Level: Recommended
- Chapter: [Cryptography and keys](https://agentwranglers.se/playbook/application-security/cryptography-and-keys.md)
- Rule: Encrypt data with data keys, and store each data key only in wrapped form. A key-encryption key that never leaves the key service or HSM wraps it. Rotate the key-encryption key without decrypting the data.
- Check: A search of the database and storage finds no unwrapped data key. A test encrypts a record, rotates the key-encryption key in a sandbox and rewraps the data keys. The record still decrypts, its ciphertext bytes are unchanged, and every wrapped key names the new version.
- How: This is envelope encryption, and it gives you a key hierarchy. A root key sits in a hardware security module (HSM) or a cloud key service. It wraps key-encryption keys, one per purpose or tenant, and these wrap the data keys. Ask the key service for a new data key, encrypt locally with it, then keep only the wrapped copy next to the ciphertext. Rotating a key-encryption key means unwrapping and rewrapping the small data keys, never re-encrypting the data. Give each data key one purpose, such as one table or one file, so a leak stays small. Record the key version with every wrapped key. Key storage and rotation periods are in [Keep encryption keys in a key service](https://agentwranglers.se/playbook/application-security/cryptography-and-keys/key-management.md). Keys per tenant are in [Give each tenant its own encryption key](https://agentwranglers.se/playbook/data/multi-tenancy/tenant-encryption-keys.md).

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### Python example

```python
import boto3, os
from cryptography.hazmat.primitives.ciphers.aead import AESGCM

kms = boto3.client("kms")

def seal(plaintext: bytes, kek_id: str) -> dict:
    key = kms.generate_data_key(KeyId=kek_id, KeySpec="AES_256")
    nonce = os.urandom(12)
    return {"wrapped_key": key["CiphertextBlob"], "nonce": nonce,
            "data": AESGCM(key["Plaintext"]).encrypt(nonce, plaintext, None)}

def rewrap(sealed: dict, new_kek_id: str) -> dict:
    out = kms.re_encrypt(CiphertextBlob=sealed["wrapped_key"], DestinationKeyId=new_kek_id)
    return {**sealed, "wrapped_key": out["CiphertextBlob"]}
```

### JavaScript example

```js
import { KMSClient, GenerateDataKeyCommand, ReEncryptCommand } from '@aws-sdk/client-kms';
import { createCipheriv, randomBytes } from 'node:crypto';

const kms = new KMSClient({});

export async function seal(plaintext, kekId) {
  const key = await kms.send(new GenerateDataKeyCommand({ KeyId: kekId, KeySpec: 'AES_256' }));
  const nonce = randomBytes(12);
  const cipher = createCipheriv('aes-256-gcm', key.Plaintext, nonce);
  const data = Buffer.concat([cipher.update(plaintext), cipher.final(), cipher.getAuthTag()]);
  return { wrappedKey: key.CiphertextBlob, nonce, data };
}

export async function rewrap(sealed, newKekId) {
  const out = await kms.send(new ReEncryptCommand({ CiphertextBlob: sealed.wrappedKey, DestinationKeyId: newKekId }));
  return { ...sealed, wrappedKey: out.CiphertextBlob };
}
```

## Sources

- [NIST SP 800-57 Part 1 Rev. 5 Recommendation for Key Management](https://csrc.nist.gov/pubs/sp/800/57/pt1/r5/final)
- [AWS KMS concepts, envelope encryption](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html)

## Related rules

- APS-57 [Keep encryption keys in a key service](https://agentwranglers.se/playbook/application-security/cryptography-and-keys/key-management.md) in Application security
- DAT-74 [Give each tenant its own encryption key when customers ask to hold it](https://agentwranglers.se/playbook/data/multi-tenancy/tenant-encryption-keys.md) in Data and databases

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/application-security/cryptography-and-keys/envelope-encryption">Agent Wranglers application security playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Keep encryption keys in a key service](https://agentwranglers.se/playbook/application-security/cryptography-and-keys/key-management.md)
- Next: [Encrypt the most sensitive fields](https://agentwranglers.se/playbook/application-security/cryptography-and-keys/field-encryption.md)
- [Cryptography and keys](https://agentwranglers.se/playbook/application-security/cryptography-and-keys.md)
