国密标准中的密钥边界约束
做国密算法这么多年,我遇到过很多因为密钥边界踩坑的案例。说白了,GM/T系列标准对密钥的“圈地”非常清楚——多长、什么格式、能不能跨平台、怎么验——都写在标准里了。但大部分人看标准只看算法逻辑,忽略了密钥边界这块硬约束。
这一节我们就专门把GM/T标准里关于密钥边界的零散规定,拎出来归类。你想想看,一个SM2私钥在A系统能用,到B系统就报“无效密钥”,多半是边界条件没对齐。
涉及密钥边界的主要GM/T标准
国密标准分得比较细,每个算法都有自己的规范族。我把跟密钥边界强相关的列出来:
| 标准号 | 规范名称 | 密钥边界核心约束 |
|---|---|---|
| GM/T 0001-2012 | SM2椭圆曲线公钥密码算法 | 密钥长度256位(素数域);私钥为随机整数范围[1, n-1];公钥为非无穷远点,含未压缩前缀04。 |
| GM/T 0004-2012 | SM4分组密码算法 | 密钥长度固定128位;密钥拓展后轮密钥为32个32位字。 |
| GM/T 0002-2012 | SM3密码杂凑算法 | 虽非密钥算法,但密钥派生时需遵守SM3输出长度256位。 |
| GM/T 0009-2012 | SM2密码算法使用规范 | 公钥数据格式含算法标识;私钥存储支持PKCS#8包裹及国密专用OID。 |
| GM/T 0016-2012 | SM2数字签名算法 | 签名密钥对中私钥不得导出,公钥需进行有效性验证(验证点是否在曲线上)。 |
| GM/T 0018-2012 | SM2密钥交换协议 | 交互双方临时密钥有效期限制;会话密钥长度由协商参数决定。 |
| GM/T 0010-2012 | SM2密码算法加密规范 | 密文开头包含公钥哈希及加密算法标识,密钥边界通过C1C2C3格式固话。 |
我的经验: 刚接手一个银行密码服务平台时,发现两边SM2公钥虽然都能解析,但长度不一样——一侧用了完整公钥(65字节),另一侧只存了x坐标(32字节),结果验签一直失败。最后追溯,是标准对公钥存储边界定义不明确导致的。所以实际项目中,公钥必须带前缀04且坐标用完整256位。
密钥边界约束的四大维度
我从项目里总结出来,国密密钥边界约束其实就落在四个地方:长度、数值范围、格式封装、可导出/存储策略。记好这四条,基本能避开90%的兼容性坑。
- 长度边界: SM2私钥必须256位,SM4密钥必须128位。不能多不能少。我记得有次看到有人用Java的BigInteger截取,私钥高位补零导致多出1个字节,HSM直接拒绝加载。
- 数值范围边界: SM2私钥必须在[1, n-1]内(n为基点阶)。我曾经在代码里直接用随机数发生器生成32字节,然后mod n,结果没有检查是否为0或1——这种私钥极弱,标准明确禁止。
- 格式封装边界: SM2公钥必须包含04前缀(未压缩)或02/03前缀(压缩);私钥使用PKCS#8 DER编码时必须带国密OID(1.2.156.10197.1.301)。很多老旧系统缺少这个OID的注册,导致跨平台解析失败。
- 存储与导出边界: 签名密钥对中的私钥原则上不应离开硬件令牌;密钥交换时的临时密钥必须按协议销毁。我曾见过一个项目把临时会话密钥存到数据库做“历史查询”,结果完全违反了密钥生命周期边界。
避坑指南: 我在帮一家芯片厂商做国密驱动时,他们的SM4密钥生成器直接调用RAND_bytes,生成了128位随机后当作密钥用。看起来很合理对吧?但标准要求SM4密钥必须使用密码学安全的随机数发生器,并且要对生成的密钥进行奇偶校验(某些实现有弱密钥检测)。虽然GM/T 0004没写弱密钥列表,但参考ANSI X9.9,全0、全1、0xE0E0...这类密钥应禁止。后来我把这些边界检查加进去了,fips测试才通过。
关键标准间的边界关联
为什么说国密密钥边界是“网状约束”?因为单个标准只规定自身,但系统里密钥会在不同标准中流动。我画了张图,把这些关联串一下:
密钥边界校验实战清单
讲完了标准,来点干货。这是我自己整理的一个密钥边界校验checklist,每次移植国密库时都会过一遍:
- SM2私钥: 长度=32字节,数值在[n, n-1]之外直接拒绝;派生私钥时检查是否与公钥对应(点乘测试)。
- SM2公钥: 确保前缀04或02/03;将坐标代入曲线方程验证;检查是否为无穷远点。
- SM4密钥: 长度=16字节;检测所有字节是否相同(弱密钥);补充建议:避免全0、全1、0x01010101...。
- 密钥交换临时密钥: 生命周期仅限一次会话;在协议结束后立即清除内存。
- OID注册: 证书或密钥存储中必须带有国密OID,且与系统OID表一致。我发现有些系统没注册 SM2 的 OID,结果证书链解析失败。
思考题: 如果两个系统都宣称支持SM2,但一个使用压缩格式公钥(02前缀+ x坐标),另一个使用未压缩格式(04前缀+ x+y坐标),它们能否互认公钥?答案是不能直接。标准虽允许两种格式,但边界不一致时,接收方必须实现两种格式的解析。我建议工程上统一使用未压缩格式,虽然多32字节,但避免了大量边界问题。
小结——密钥边界不是孤岛
GM/T标准对密钥边界的约束,其实是从算法设计、安全要求、跨系统互操作三个角度共同挤压出来的。我经常跟团队说:看标准别只看算法数学,更要看“边界话”——密钥在生成、传递、存储、使用每个环节的形态都有红线。越过一条红线,兼容性就可能爆炸。
嗯,这一节就先讲这些。记住那几个表格和SVG里的关系链,实际落地方案时很有用。