3. 信封加密概念与原理
我刚开始做加解密系统的时候,经常接到一个需求:“帮我把这批数据库字段加密一下”。那时候我就直接把用户密钥拿过来,一条数据一个秘钥对?太多。一个密钥加密全部?风险太大。直到接触了信封加密——嗯,这招儿真管用。
说白了,信封加密就是“用数据加密数据,再用高级密钥去加密那个数据密钥”。它把对称加密的高效和密钥管理的灵活性结合在了一起。你想想看,如果对所有数据都用同一个主密钥加密,一旦泄露,全盘皆输;如果每条数据都独立密钥,存储和分发又成了灾难。
核心概念
信封加密里有两个角色:
- 数据加密密钥(DEK)——真正的“干活”密钥。对称算法(比如 AES-256),大量数据都用它加密,速度快。
- 密钥加密密钥(KEK)——专门用来加密 DEK 的“保护伞”。可以是对称密钥,也可以是非对称密钥(比如 KMS 中的主密钥)。
一个完整的信封加密流程长这样:
- 生成一个随机的 DEK。
- 用 DEK 加密实际数据,得到密文
C1。 - 用 KEK 加密 DEK,得到密文
C2(称为“信封”)。 - 把
C1和C2一起存储 / 传输。 - 解密时:先用 KEK 解密
C2拿到 DEK,再用 DEK 解密C1还原数据。
为什么叫“信封”?想象一下:你把数据装进一个信封里,信封封口用的是 DEK 这把锁;然后你用 KEK 这把更高级的锁再把那个 DEK 锁进一个更小的信封里。两个信封一里一外,外层的钥匙只有你(或 KMS)持有。
典型的密钥层次
KMS 里的主密钥(CMK)就是 KEK 的一种常见形态。我在项目中遇到过这样的层次:
| 层级 | 名称 | 算法 | 保护对象 |
|---|---|---|---|
| L0 | 根密钥(根CA) | 非对称 RSA-4096 | HSM 内部 |
| L1 | 客户主密钥(CMK) | 对称 AES-256 / 非对称 | DEK |
| L2 | 数据加密密钥(DEK) | 对称 AES-256 | 业务数据 |
| L3 | 业务数据 | — | 明文 / 密文 |
越往上,密钥越珍贵、越难泄露。L0 的根密钥甚至可能从不出 HSM 硬件。L2 的 DEK 可以频繁轮转——你甚至每写一条记录就换一个 DEK。
为什么非要用信封加密?
两个字:性能和管理。
- 性能:公钥加密比较慢。如果拿非对称密钥直接加密几十 GB 的数据,服务器得累死。而 DEK 是对称的,速度是公钥的几千倍。你只需要用非对称加密一次 DEK 就行。
- 管理:你可以在 KMS 里只存 KEK(比如每个应用一个主密钥),而 DEK 随密文一起存储,不需要额外保护。甚至可以把 DEK 的密文(信封)直接存在数据库的一个字段里。密钥管理范围从“海量文件”缩小到“少量主密钥”。
完整流程示意图
下面这张图展示了信封加密的整个生命周期。注意节点颜色:蓝色节点是“密钥生成/使用”,绿色节点是“加密操作”,红色节点是“存储结果”。
解封过程 & 避坑
解密是反过来的:读取 C1 和 C2,向 KMS 请求用 KEK 解密 C2 得到 DEK,再用 DEK 解密 C1。这里有个细节我当初踩过坑:
Decrypt API 解密信封,DEK 永不出 KMS — 除非你本地有 HSM 级别的保护。对于吞吐要求高的场景,可以考虑“DEK 缓存带过期时间 + 仅在工作内存中”,但绝不能落盘。
另外,DEK 可以定期轮转。你只需要在加密时选一个新的 DEK,然后重新用 KEK 加密就行——历史数据完全不受影响。这主意在实际生产环境里非常省心。
一个简单代码示例(伪代码)
// 加密
function envelopeEncrypt(kekId, plaintext):
dek = generateRandomKey(32) // AES-256
ciphertext = aes256Encrypt(dek, plaintext)
envelope = kmsEncrypt(kekId, dek) // 使用 KMS 主密钥
return { ciphertext, envelope }
// 解密
function envelopeDecrypt(kekId, ciphertext, envelope):
dek = kmsDecrypt(kekId, envelope)
plaintext = aes256Decrypt(dek, ciphertext)
return plaintext
实际调用 KMS 时,kmsEncrypt 和 kmsDecrypt 通常是远程 RPC。注意加解密操作不要放在客户端自身实现——把信封传给 KMS 让它帮你解,避免密钥在客户端出现。
适用范围总结
| 场景 | 推荐使用信封加密? | 原因 |
|---|---|---|
| 海量静态文件加密 | ✅ 强烈推荐 | DEK 随文件,KEK 集中管理 |
| 数据库字段级加密 | ✅ 推荐 | 每行一个 DEK,轮转容易 |
| 小型应用,数据量少 | ✅ 可用 | 也可直接用主密钥加密 |
| 需要多方协作的场景 | ✅ 非常适合 | 可以每个协作方持有不同的 KEK,但共用同一个 DEK |