3、SM2密钥体系:密钥对生成原理、密钥格式与生命周期管理
密钥体系是整个SM2安全存储的基石。说白了,你后面所有的加密、签名、认证,都建立在密钥对正确生成、安全存储和规范管理之上。这一块如果出了纰漏,整个系统就等于没穿裤子上街——我见过不少项目,算法选得挺先进,结果密钥管理一塌糊涂,最后还是被攻破。
好,我们直接进入正题。
3.1 密钥对生成原理
SM2是基于椭圆曲线密码学的。它的密钥对生成,本质上就是在椭圆曲线上找一个点,然后基于这个点做标量乘法。
具体来说,SM2使用一条特定的256位椭圆曲线,参数由国家密码管理局定义。生成密钥对的步骤其实不复杂:
- 选取私钥:在[1, n-2]范围内随机生成一个大整数d,n是曲线的阶。这个d就是私钥,必须绝对保密。
- 计算公钥:公钥P = d * G,G是椭圆曲线的基点。这是一个标量乘法,结果是一个椭圆曲线上的点。
- 输出密钥对:私钥d(整数),公钥P(点坐标(x, y))。
核心要点:从私钥推导公钥是计算上可行的(标量乘法),但从公钥反推私钥是计算上不可行的(椭圆曲线离散对数问题)。这就是SM2安全性的数学基础。
我在项目中遇到过一个问题:随机数生成器不够随机。有一次测试环境用的伪随机数生成器种子固定,结果每次重启服务生成的密钥对都一样。嗯,这要是上了生产,后果不堪设想。所以,一定要用硬件随机数发生器或经过认证的密码学安全伪随机数生成器(CSPRNG)。
3.2 密钥格式:PEM、DER与SM2标准格式
密钥生成了,总得存起来吧?存成什么格式?这就涉及到密钥的编码和序列化问题。
你想想看,一个SM2私钥就是一个256位的大整数,公钥是两个256位的坐标。直接存二进制?可以,但不方便交换和阅读。所以业界定义了几种标准格式。
3.2.1 DER格式
DER是ASN.1编码的一种二进制形式。SM2的密钥对在DER中通常使用特定的OID(对象标识符)来标识算法。
SM2公钥的DER编码结构大致如下:
SEQUENCE {
SEQUENCE {
OID 1.2.156.10197.1.301 -- sm2p256v1曲线OID
}
BIT STRING (未压缩公钥点数据)
}
私钥的DER编码则更复杂一些,通常包含版本号、私钥数据、曲线参数和公钥信息。
我的习惯:在底层存储或硬件安全模块(HSM)中,我倾向于使用DER格式。因为它是二进制、紧凑、解析效率高。但在文件交换和配置文件中,DER的可读性太差了。
3.2.2 PEM格式
PEM其实就是对DER进行Base64编码,再加上头尾标记行。说白了,就是把二进制变成文本,方便复制粘贴和传输。
一个SM2私钥的PEM文件长这样:
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgR8JfI5LqF7R3Yp5Q
...
-----END PRIVATE KEY-----
公钥的PEM:
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE0JgF5R6V7zY8X9X8zY8X9X8zY8X9
...
-----END PUBLIC KEY-----
注意:PEM只是DER的文本封装,它本身不提供任何加密保护。私钥的PEM文件如果泄露,就等于私钥泄露。所以,永远不要将私钥的PEM文件以明文形式存储在磁盘上。我建议至少使用密码加密的PKCS#8格式。
3.2.3 SM2标准格式
国密标准对SM2密钥的格式有更具体的规定。主要体现在:
- 曲线参数:必须使用标准指定的曲线(sm2p256v1),OID为1.2.156.10197.1.301。
- 公钥格式:通常使用未压缩格式(04 || x || y),共65字节。
- 私钥格式:32字节的大整数,大端序。
- 标识:在证书和密钥文件中,必须明确标识为SM2算法。
我把三种格式的对比整理了一下:
| 特性 | DER | PEM | SM2标准格式 |
|---|---|---|---|
| 编码方式 | 二进制ASN.1 | Base64 + 头尾标记 | 二进制/文本均可 |
| 可读性 | 差 | 中 | 中 |
| 解析效率 | 高 | 中(需Base64解码) | 高 |
| 算法标识 | OID | OID | OID + 国密标识 |
| 典型用途 | HSM、底层存储 | 文件交换、配置文件 | 国密合规场景 |
3.3 密钥生命周期管理
密钥不是生成出来就完事了。它有一个完整的生命周期,从出生到死亡,每个阶段都需要严格管理。
我画了一张图,把密钥的整个生命周期串起来:
每个阶段都有需要注意的地方:
3.3.1 密钥生成
- 必须使用合格的随机数源
- 生成后立即验证密钥对的有效性(检查公钥是否在曲线上)
- 记录生成日志,但绝不能记录私钥本身
3.3.2 安全存储
- 私钥必须加密存储,推荐使用HSM或安全密码箱
- 访问控制:只有授权进程和用户才能读取私钥
- 备份要加密,且与主密钥分开存放
我曾经踩过的坑:有一次,开发人员为了方便调试,把私钥以明文形式写在了配置文件中,还提交到了Git仓库。虽然很快删除了,但Git历史里永远留下了那个私钥。所以,一定要在.gitignore中排除密钥文件,并使用git filter-branch清理历史。
3.3.3 密钥分发
- 公钥可以通过非安全通道分发,但必须保证完整性(使用数字证书或指纹验证)
- 私钥分发必须使用安全通道(如TLS、物理传递)
- 分发后接收方要验证密钥的完整性
3.3.4 密钥使用
- 遵循最小权限原则:每个密钥只用于特定目的(签名密钥不用于加密)
- 设置使用次数或有效期限制
- 记录使用日志,便于审计
3.3.5 密钥更新与撤销
- 定期更新密钥(我建议SM2密钥最长使用不超过2年)
- 密钥泄露或人员离职时立即撤销
- 撤销的密钥要加入证书撤销列表(CRL)
3.3.6 密钥销毁
- 销毁必须彻底:覆盖存储介质、销毁HSM中的密钥槽
- 销毁后要验证无法恢复
- 保留销毁记录,但删除所有密钥副本
我的建议:建立一个密钥生命周期管理台账,记录每个密钥的生成时间、用途、有效期、最后使用时间、销毁时间。这样审计的时候一目了然,出了问题也能快速定位。
好了,SM2密钥体系的核心内容就是这些。密钥对生成原理是数学基础,密钥格式是工程实践,生命周期管理是运维保障。三者缺一不可。你想想看,如果密钥格式不规范,不同系统之间无法互操作;如果生命周期管理不到位,密钥泄露了都不知道。所以,这三块都要扎扎实实地做好。