开源之夏04:密钥管理与密码学安全设计
在密码设备开发中,密钥管理是绝对的核心。这周通过 SDF 接口的深入学习和代码实现,理清了困扰已久的几个基础问题。
密码学四要素与工具选择
密码学第一课说:这门课程主要阐述如何利用密码技术实现信息的机密性、完整性、可鉴别性和抗抵赖性。但为什么有了数字签名还要消息鉴别?为什么还要身份鉴别?这些技术背后的联系是什么?
核心推理链是这样的:
- 数学上证明:只要密钥不泄露,加密的内容就是安全的。
- 因此推论:假设密钥完成分发,不考虑重放,使用密钥加密保护信息传递,保证密钥安全,各种业务场景就都是安全的。
- 于是:需要保护密钥,让它在每次用完后都能被妥善保管,不丢失泄露。
不同密码工具解决不同层面的问题:
| 工具 | 完整性 | 身份鉴别 | 不可否认性 | 说明 |
|---|---|---|---|---|
| MAC/HMAC | ✔ | ✘ | ✘ | 只能证明”有人拥有同一对称密钥” |
| 数字签名 | ✔ | ✔ | ✔ | 签名用私钥,验签用公钥/证书 |
| 挑战-响应协议 | 间接 | ✔ | 间接 | 解决”此刻对端是不是声称的实体” |
完整的信任链
- 密钥本身:只是一串随机比特,本身没有任何”意义”。
- 谁有权用它(最小授权/访问控制):通过 PIN、口令、HSM 角色把”实体→密钥使用权”绑定,但不透露密钥。
- 消息鉴别(MAC/HMAC):解决”消息在传输途中是否被篡改”。对称密钥本身不表明”谁”产生的——拿到密钥就能伪造 MAC。
- 数字签名(SM2/RSA):私钥永远留在设备内,公钥可以公开。验证链条的最后一环:私钥只负责”计算签名”,身份由”公钥证书”绑定,”谁有权用私钥”由 HSM 的访问控制决定。形成”实体 / 密钥使用权 / 签名结果”三层分离。
- 身份鉴别(挑战-响应、TLS 握手):组合使用 MAC 或数字签名,现场证明”此刻使用这把私钥的人就是那个被认证的实体”。
统一的指导思想:最小权限原则(Principle of Least Privilege)+ 分层信任模型(Layered Trust)——把敏感资产(密钥、消息、身份)从逻辑与物理上逐层最小化暴露,任何一层泄露都不足以破坏整体信任。
SDF 密钥管理三维度
SDF 规范用不同的接口组合覆盖密钥管理的全部交叉点。任何一把密钥都可以被描述为:
(持久/会话/临时)×(内部/外部)×(签名/加密/对称)
维度一:生命周期
把密钥按时间维度切成三档,对应密码设备在安全、性能、合规三个维度上无法同时满足的”不可能三角”:
| 类型 | 存储 | 安全 | 性能 | 典型场景 |
|---|---|---|---|---|
| 持久密钥 | NVRAM,掉电不丢 | 最高(私钥永不出芯片) | 访问慢 | 根密钥、CA 私钥 |
| 会话密钥 | 易失 RAM,关闭即销毁 | 中等(泄露只影响一次会话) | 平衡 | 单次通信加密 |
| 临时密钥 | 瞬时生成、用完即毁 | 可接受的一次性风险 | 极限 | 海量并发、零持久化 |
会话密钥负责”会话内不泄密”,持久密钥负责”跨会话还能认人”。两者缺一不可。
维度二:使用权限
- 内部密钥:私钥永不出设备,只能做内部运算(签名、解密)
- 外部密钥:私钥(或会话密钥明文)可以导出到主机内存
维度三:功能用途
- 签名密钥对:ExportSignPublicKey / GenerateSignKeyPair
- 加密密钥对:ExportEncPublicKey / GenerateEncKeyPair
- 对称会话密钥:GenerateKey、ImportKeyWithKEK 等
密钥封装与 KEK 体系
SDF 标准的推荐业务流程是”会话密钥+密钥封装”:
数据不直接用非对称私钥解密,而是用对称会话密钥加密/解密,非对称密钥只用于加密/解密会话密钥。
典型流程:
- 发送方生成随机对称会话密钥(如 SM4),用接收方公钥加密该会话密钥得到”密钥密文”
- 用会话密钥加密数据得到”数据密文”
- 发送”密钥密文+数据密文”
- 接收方用自己的私钥解封会话密钥,再用会话密钥解密数据
KEK vs IPK/EPK/ISK
这几个概念容易混淆,本质上是不同场景的密钥封装方案:
| 机制 | 类型 | 适用场景 | 性能 |
|---|---|---|---|
| EPK/ISK | 非对称(公钥加密) | 跨系统/跨设备安全传递 | 慢,安全高 |
| IPK | 非对称 | 同设备内不同进程/模块间隔离 | 慢,安全高 |
| KEK | 对称 | 设备内部或同域密钥封装、备份、迁移 | 快 |
KEK(密钥加密密钥)是设备内部生成并长期安全存储的对称密钥,专门用于加密/解密会话密钥。它的生命周期长,只有设备内部能直接使用,外部应用只能通过索引引用。KEK 不是替代 IPK/EPK,而是为设备内部高效安全的密钥管理提供补充——快的那条路。
KEK 走对称加密路线,速度快适合高频操作;IPK/EPK 走非对称路线,安全性高但速度慢适合跨域场景。两者互补构成完整的密钥管理体系。
设备→会话→密钥 三级句柄架构
这是密码硬件领域经过二十多年迭代后最通用的架构:
1 | |
每一层解决不同的矛盾:
| 层级 | 解决什么 | 生命周期 |
|---|---|---|
| 设备 | 全局配额、权限隔离 | 进程级 |
| 会话 | 并发隔离、认证状态、对象列表 | 登录态 |
| 密钥 | 受保护的密钥对象,仅暴露整数句柄 | 会话或持久 |
为什么要这样设计?因为在单块芯片上需要同时满足:多用户并发、密钥最小暴露、资源可计量、运维可管理——单靠任何一层都做不到。
会话句柄退出或关闭即可零成本”擦除”临时密钥,减少应用层忘记清内存的安全风险。密钥句柄只暴露 32/64 位整数而非密钥明文,即使句柄泄露也无法直接获取密钥材料。
SM2 签名与密钥协商
Z 值的计算与作用
SM2 签名算法中的 Z 值是一个”用户身份绑定杂凑值”:
1 | |
作用:防止公钥替换攻击。攻击者如果替换公钥并伪造签名,由于 Z 值绑定了用户身份和公钥,验签时计算出不同的 Z 值会导致验证失败。
SDF 标准规定:调用 SDF_HashInit 时传入 ECC 公钥和用户 ID,设备自动完成 Z 值计算。随后 SDF_HashUpdate 拼接 Z||M(原始消息),SDF_HashFinal 输出 “SM2 预处理+SM3”后的摘要。
密钥协商中的双重密钥
SM2 密钥协商同时使用主公钥(长期密钥) 和临时公钥,二者缺一不可:
- 主公钥:经 CA 认证、长期绑定用户身份,防止中间人伪造身份。
- 临时公钥:每次会话动态生成,提供前向安全性(Forward Secrecy)——即使长期密钥泄露,历史会话密钥也不会被恢复。
只用主密钥:有身份认证但无前向安全。只用临时密钥:有前向安全但无法认证身份。两者结合才是现代密钥协商的标准做法。
柔性数组
SDF 标准的 ECCCipher 结构中密文字段 C[] 使用了柔性数组(Flexible Array Member):
1 | |
C99 正式引入 C[](未指定长度的数组),C89/C90 时代常用 C[1] 占位。原理:结构体大小只包含 C[1] 的 1 字节,但可以通过 malloc 分配更大空间,把多余部分当作变长数组使用。广泛用于协议、密码学等需要变长数据的场景。
硬件攻击面:芯片安全 ≠ 系统安全
SDF 的”芯片”很安全,但芯片到 CPU 这条 PCIe 总线以及宿主机系统仍是可攻击面。”没人会攻击密码卡”是一个危险的错觉:
| 攻击者 | 典型目标 | 动机 |
|---|---|---|
| 国家级 APT | 政府/军工/金融根证书 | 长期潜伏、情报窃取 |
| 犯罪集团 | POS 机、加密 U-Key | 直接套现、银行卡复制 |
| 云厂商内部人 | 大客户加密卡 | 横向提权、盗窃 API 密钥 |
| 学术/白帽 | 发表论文、CVE | 经费、声誉 |
攻击门槛并不高:PCIe 协议分析仪只需 $3000,开源工具链(ChipWhisperer、Glasgow)让本科生 1-2 周即可复现功耗攻击。机密计算正是为了解决这个问题——用 CPU 自身 TEE(Trusted Execution Environment)消除芯片到 CPU 总线的可攻击面。