Encrypting large volumes of data directly through KMS is impractical — KMS is designed for key operations, not bulk data transfer. The solution is envelope encryption: KMS generates a data key and protects it with your customer master key (CMK), while your application uses that data key locally to encrypt or decrypt files. This keeps your raw data off the network and ensures the data key itself is never stored in plaintext.
How KMS and your application divide the work:
KMS: generates the data key, encrypts it with your CMK, and decrypts it on demand.
Your application: uses the plaintext data key locally to encrypt or decrypt files, then immediately discards it from memory.
Your raw data never leaves your environment. The data key is never stored in plaintext.
Delete the plaintext data key from memory as soon as you finish encrypting or decrypting. Keeping it in memory longer than necessary increases exposure risk.
Use cases
Envelope encryption is suitable for encrypting large amounts of data, including the following scenarios:
Encrypting business data files.
Encrypting all data stored on local disks.
How it works
Encryption flow

Create a CMK in the KMS console or by calling
CreateKey.Call
GenerateDataKey. KMS returns both the plaintext and the ciphertext of a new data key.Use the plaintext data key to encrypt your local files, then delete it from memory immediately.
Store the ciphertext data key alongside the encrypted files. Keep them together — you need the ciphertext key to decrypt the files later.
Decryption flow

Retrieve the ciphertext data key stored with your encrypted files.
Call
Decrypt. KMS decrypts the ciphertext data key and returns the plaintext. No CMK ID is required — KMS infers it from the ciphertext.Use the plaintext data key to decrypt the files, then delete it from memory immediately.
API operations
The following KMS API operations support envelope encryption. The actual file encryption and decryption happen locally in your application using standard cryptographic libraries — KMS handles only key operations.
| API operation | Description |
|---|---|
| CreateKey | Creates a CMK. |
| CreateAlias | Creates an alias for a CMK. |
| GenerateDataKey | Generates a data key and encrypts it with the specified CMK. Returns both the plaintext and ciphertext of the data key. |
| Decrypt | Decrypts data that is encrypted in KMS, including the ciphertext data key generated by calling the GenerateDataKey operation. No CMK needs to be specified — KMS infers it from the ciphertext. |
Encrypt and decrypt local files
The following example encrypts and decrypts a local CSV file using Alibaba Cloud CLI and Python.
The AccessKey pair of an Alibaba Cloud account has permissions on all API operations, which makes it a high-risk credential. Use a RAM user to call API operations for routine tasks. Store credentials in environment variables rather than in your project code — hardcoded credentials risk exposing all resources under the account. For setup details, see Instantiate a client and configure a credential.
Prerequisites
Before you begin, ensure that you have:
An Alibaba Cloud account with KMS access
A RAM user with permissions to call
CreateKey,GenerateDataKey, andDecryptAlibaba Cloud CLI installed and configured
Python installed with
pycryptodomeandaliyunsdkcore/aliyunsdkkmspackages
Step 1: Create a CMK
aliyun kms CreateKeyExpected output:
{
"KeyMetadata": {
"CreationDate": "2019-04-08T07:45:54Z",
"Description": "",
"KeyId": "1234abcd-12ab-34cd-56ef-12345678****",
"KeyState": "Enabled",
"KeyUsage": "ENCRYPT/DECRYPT",
"DeleteDate": "",
"Creator": "151266687691****",
"Arn": "acs:kms:cn-hangzhou:151266687691****:key/1234abcd-12ab-34cd-56ef-12345678****",
"Origin": "Aliyun_KMS",
"MaterialExpireTime": ""
},
"RequestId": "2a37b168-9fa0-4d71-aba4-2077dd9e80df"
}Step 2: Create an alias (optional)
An alias lets you reference a CMK by name instead of ID. If you skip this step, use the KeyId from Step 1 in subsequent commands.
aliyun kms CreateAlias --AliasName alias/Apollo/WorkKey --KeyId 1234abcd-12ab-34cd-56ef-12345678****In this example,alias/Apollo/WorkKeyidentifies the CMK for theApolloproject. The subsequent code samples use this alias.
Step 3: Encrypt a local file
The script below generates a data key via KMS, uses it to encrypt ./data/sales.csv with AES-EAX, and writes the result to ./data/sales.csv.cipher.
The ciphertext file stores four base64-encoded values on separate lines:
Line 1: ciphertext data key
Line 2: IV (nonce)
Line 3: encrypted file content
Line 4: authentication tag
#!/usr/bin/env python
# coding=utf-8
import os
import json
import base64
from Crypto.Cipher import AES
from aliyunsdkcore import client
from aliyunsdkkms.request.v20160120 import GenerateDataKeyRequest
def kms_generate_data_key(kms_client, key_alias):
request = GenerateDataKeyRequest.GenerateDataKeyRequest()
request.set_accept_format('JSON')
request.set_KeyId(key_alias)
request.set_NumberOfBytes(32) # 256-bit AES key
response = json.loads(kms_client.do_action(request))
datakey_encrypted = response['CiphertextBlob']
datakey_plaintext = response['Plaintext']
return datakey_plaintext, datakey_encrypted
def read_text_file(in_file):
with open(in_file, 'r') as f:
return f.read()
def write_text_file(out_file, lines):
with open(out_file, 'w') as f:
for ln in lines:
f.write(ln)
f.write('\n')
def local_encrypt(datakey_plaintext, datakey_encrypted, in_file, out_file):
# Decode the base64-encoded plaintext key returned by KMS
data_key_binary = base64.b64decode(datakey_plaintext)
cipher = AES.new(data_key_binary, AES.MODE_EAX)
in_content = read_text_file(in_file)
ciphertext, tag = cipher.encrypt_and_digest(in_content.encode('utf-8'))
# Store ciphertext key, IV, encrypted content, and authentication tag
lines = [
datakey_encrypted,
base64.b64encode(cipher.nonce).decode('utf-8'),
base64.b64encode(ciphertext).decode('utf-8'),
base64.b64encode(tag).decode('utf-8'),
]
write_text_file(out_file, lines)
# Load credentials from environment variables
kms_client = client.AcsClient(
os.environ.get('ALIBABA_CLOUD_ACCESS_KEY_ID'),
os.environ.get('ALIBABA_CLOUD_ACCESS_KEY_SECRET'),
'<region-id>', # Replace with your region ID, for example, cn-hangzhou
)
key_alias = 'alias/Apollo/WorkKey'
in_file = './data/sales.csv'
out_file = './data/sales.csv.cipher'
# Generate a data key and encrypt the file locally
datakey = kms_generate_data_key(kms_client, key_alias)
local_encrypt(datakey[0], datakey[1], in_file, out_file)Replace the following placeholder:
| Placeholder | Description | Example |
|---|---|---|
<region-id> | The region where your CMK is located | cn-hangzhou |
Step 4: Decrypt a local file
The script below reads ./data/sales.csv.cipher, calls KMS to decrypt the ciphertext data key, and uses the plaintext key to restore the original file to ./data/decrypted_sales.csv.
#!/usr/bin/env python
# coding=utf-8
import os
import json
import base64
from Crypto.Cipher import AES
from aliyunsdkcore import client
from aliyunsdkkms.request.v20160120 import DecryptRequest
def kms_decrypt(kms_client, ciphertext):
request = DecryptRequest.DecryptRequest()
request.set_accept_format('JSON')
request.set_CiphertextBlob(ciphertext)
response = json.loads(kms_client.do_action(request))
return response.get('Plaintext')
def read_cipher_file(in_file):
with open(in_file, 'r') as f:
return [line.rstrip('\n') for line in f]
def write_text_file(out_file, content):
with open(out_file, 'w') as f:
f.write(content)
def local_decrypt(datakey_ciphertext, iv_b64, ciphertext_b64, tag_b64, out_file):
# Decrypt the data key via KMS
datakey_plaintext = kms_decrypt(kms_client, datakey_ciphertext)
datakey_binary = base64.b64decode(datakey_plaintext)
cipher = AES.new(datakey_binary, AES.MODE_EAX, base64.b64decode(iv_b64))
plaintext = cipher.decrypt_and_verify(
base64.b64decode(ciphertext_b64),
base64.b64decode(tag_b64),
).decode('utf-8')
write_text_file(out_file, plaintext)
# Load credentials from environment variables
kms_client = client.AcsClient(
os.environ.get('ALIBABA_CLOUD_ACCESS_KEY_ID'),
os.environ.get('ALIBABA_CLOUD_ACCESS_KEY_SECRET'),
'<region-id>', # Replace with your region ID, for example, cn-hangzhou
)
in_file = './data/sales.csv.cipher'
out_file = './data/decrypted_sales.csv'
# Read the cipher file (line 0: ciphertext key, 1: IV, 2: ciphertext, 3: tag)
in_lines = read_cipher_file(in_file)
local_decrypt(in_lines[0], in_lines[1], in_lines[2], in_lines[3], out_file)Replace the following placeholder:
| Placeholder | Description | Example |
|---|---|---|
<region-id> | The region where your CMK is located | cn-hangzhou |