4. 数据加密密钥(DEK)与密钥加密密钥(KEK)归纳总结

到现在为止,我们已经聊了信封加密的核心流程。说实话,很多刚接触云上加密的同学,最容易绕晕的地方就是那两个缩写——DEK 和 KEK。我自己刚开始也搞混过,到底哪个是用来加密数据的,哪个是用来保护密钥本身的?

今天这一章,我们就彻底把这两个角色掰扯清楚。我习惯用一句话来区分它们:DEK 是干活的那个,KEK 是管人的那个。你想想看,DEK 直接面对你的业务数据,而 KEK 只负责保护 DEK,不碰数据本身。

4.1 DEK:数据加密密钥

DEK,全称 Data Encryption Key。它就是那个真正用来加密和解密你业务数据的密钥。不管你用 AES-256 还是 SM4,最终计算的时候都得拿 DEK 上。

小提示: 我个人习惯用 KMS 直接生成 DEK,而不是自己手动拍脑袋写一个。KMS 生成的随机数质量,比你在 Java 里 new SecureRandom() 靠谱得多。

DEK 有几个关键特性:

  • 生命周期短:通常一次一换,或者几天一换。我见过一些项目把 DEK 用半年不换,差点出大事。
  • 对称密钥:加密和解密用同一把密钥。算法常见的是 AES-256、SM4。
  • 永远不能明文落盘:这是底线。DEK 只在内存里使用,用完就销毁。

4.2 KEK:密钥加密密钥

KEK,全称 Key Encryption Key。它的职责很单一——保护 DEK。说白了,KEK 就是用来给 DEK 裹一层保护壳的钥匙。

我举个例子。你在数据库里存了 100 个文件的 DEK,每个都是明文?那如果数据库被拖库,你所有的加密数据相当于白加密。但如果每个 DEK 都用 KEK 加密后再存储,黑客拿到数据库也只是一堆密文,他解不开。

核心区别一句话:

DEK 加密你的数据,KEK 加密你的 DEK。

KEK 的特点包括:

  • 生命周期长:可以几个月甚至几年保持不变。但要配合轮换策略。
  • 存储在 KMS 或 HSM 内部:永远不暴露到业务服务器上。调用 KMS 的 API 时,传进去的是密文 DEK,KMS 用 KEK 解密后返回。
  • 主密钥角色:在信封加密里,KEK 就是那层信封的封口。

4.3 两者关系对比

我用一张表格帮你理清它们的差异。这个表格我自己做项目时经常拿出来给团队讲,清晰得很。

对比维度 DEK(数据加密密钥) KEK(密钥加密密钥)
加密对象 业务数据(文件、数据库记录等) DEK 本身
存储位置 加密后存储在数据库或本地磁盘 KMS / HSM 内部,不可导出明文
生命周期 短(一次一换或按天轮换) 长(按季度或按年轮换)
访问频率 高(每次读写数据都要用) 低(只在信封打开/关闭时用)
密钥生成
可由客户端或 KMS 生成 必须在 KMS 或 HSM 内生成
泄露后果 对应数据全被解密 所有用该 KEK 保护的 DEK 都危险

4.4 流程中的具体分工

现在我们把它们放到实际的加解密流程里看看。我挑一个典型场景:上传文件到云存储。

加密流程:

  1. 从 KMS 请求生成一个 DEK(明文)。KMS 内部会生成随机 AES-256 密钥。
  2. 用这个明文 DEK 加密文件内容。得到密文文件。
  3. 再次调用 KMS,用 KEK 加密 DEK。得到加密后的 DEK(也叫 wrapped DEK)。
  4. 把密文文件和 wrapped DEK 一起上传到云存储。
  5. 立即从内存中清除明文 DEK。
我曾经踩过的坑: 有一次在第三步直接把明文 DEK 和密文 DEK 一起存了。过了两天才发现,等于白加密。因为黑客拿到明文 DEK 就能直接解密。一定要确保明文 DEK 只活在内存里。

解密流程:

  1. 从云存储拉取密文文件和 wrapped DEK。
  2. 将 wrapped DEK 发送给 KMS,请求用 KEK 解密。
  3. KMS 验证权限后,返回明文 DEK(只在网络连接中加密传输)。
  4. 用明文 DEK 解密文件内容。
  5. 解密完成后,立即清空明文 DEK。

4.5 密钥轮换策略

轮换是个大话题。我这里只针对 DEK 和 KEK 的不同轮换逻辑给点建议。

DEK 轮换:

  • 每次加密新数据时,都生成新的 DEK。这是最安全的方式。
  • 对于已存数据,可以按时间(比如 7 天)重新加密。
  • 我的做法:在文件元数据里加一个 "keyVersion" 字段,方便追踪。

KEK 轮换:

  • KEK 轮换成本高,因为所有 DEK 都需要重新加密保护。
  • 建议在以下情况触发轮换:怀疑密钥泄露、合规审计到期、人员离职。
  • 我用过的一个方案:创建新版本的 KEK,然后逐步把旧 DEK 切换到新 KEK 下。

4.6 核心知识体系

为了帮你一次性记住这张关系网,我画了一张 SVG 图。你看完就明白了。

DEK 与 KEK 核心知识体系 信封加密中 DEK 与 KEK 的分工与关系 DEK(数据加密密钥) KEK(密钥加密密钥) 加密保护 DEK 特性 • 加密对象:业务数据 • 生命周期:短(一次一换) • 存储方式:加密后存于应用侧 • 访问频率:高(每次读写用) KEK 特性 • 加密对象:DEK • 生命周期:长(按季度/年) • 存储方式:KMS/HSM 内部 • 访问频率:低(仅信封操作) 应用层(DEK 所在) 安全层(KEK 所在) 核心原则:DEK 负责加密数据,KEK 负责加密 DEK,两者永不混用 DEK 由 KEK 保护后落盘,明文 DEK 仅存于内存中

从这张图里你能看到,DEK 和 KEK 分属不同的安全层级。DEK 在应用层直接干活,但它的安全由 KEK 在底层兜底。这个分层设计,说白了就是把核心秘密藏起来,让暴露在外面的密钥即使被偷,也只是一堆无用乱码。

4.7 避坑指南

最后我列几个常见的坑,都是我或者团队里的人亲身经历过:

我建议的存放方式: 在数据库里存 wrapped DEK 的时候,顺便存一个 KEK 版本号。这样以后轮换 KEK,你能知道哪些 DEK 是用旧 KEK 保护的,好做批量重加密。

  • 别把明文 DEK 写日志:我曾经在 debug 阶段把 DEK 打印到日志里,上线前忘了删。好在只是测试环境。但养成习惯很重要。
  • DEK 和 KEK 不能共用同一把:如果 DEK 和 KEK 是一样的,那信封加密就失去意义了。相当于你把家里钥匙放在门口的脚垫下面。
  • KEK 的权限要最小化:不是谁都能调 KMS 的 Decrypt 接口。我在一个项目里看到运维同学给所有应用配了同一个 KEK 的完全访问权限…后来改成了按应用隔离。
  • 定期检测密钥是否过期:很多云 KMS 支持密钥过期时间。我习惯在 KEK 过期前 30 天开始轮换,留足缓冲。