国密标准中的密钥边界约束

做国密算法这么多年,我遇到过很多因为密钥边界踩坑的案例。说白了,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%的兼容性坑。

  1. 长度边界: SM2私钥必须256位,SM4密钥必须128位。不能多不能少。我记得有次看到有人用Java的BigInteger截取,私钥高位补零导致多出1个字节,HSM直接拒绝加载。
  2. 数值范围边界: SM2私钥必须在[1, n-1]内(n为基点阶)。我曾经在代码里直接用随机数发生器生成32字节,然后mod n,结果没有检查是否为0或1——这种私钥极弱,标准明确禁止。
  3. 格式封装边界: SM2公钥必须包含04前缀(未压缩)或02/03前缀(压缩);私钥使用PKCS#8 DER编码时必须带国密OID(1.2.156.10197.1.301)。很多老旧系统缺少这个OID的注册,导致跨平台解析失败。
  4. 存储与导出边界: 签名密钥对中的私钥原则上不应离开硬件令牌;密钥交换时的临时密钥必须按协议销毁。我曾见过一个项目把临时会话密钥存到数据库做“历史查询”,结果完全违反了密钥生命周期边界。

避坑指南: 我在帮一家芯片厂商做国密驱动时,他们的SM4密钥生成器直接调用RAND_bytes,生成了128位随机后当作密钥用。看起来很合理对吧?但标准要求SM4密钥必须使用密码学安全的随机数发生器,并且要对生成的密钥进行奇偶校验(某些实现有弱密钥检测)。虽然GM/T 0004没写弱密钥列表,但参考ANSI X9.9,全0、全1、0xE0E0...这类密钥应禁止。后来我把这些边界检查加进去了,fips测试才通过。

关键标准间的边界关联

为什么说国密密钥边界是“网状约束”?因为单个标准只规定自身,但系统里密钥会在不同标准中流动。我画了张图,把这些关联串一下:

国密密钥边界约束体系 国密密钥边界约束体系 GM/T 0001 (SM2) 密钥256位 · 私钥范围 GM/T 0004 (SM4) 密钥128位 · 无弱密钥 GM/T 0002 (SM3) 哈希256位 (密钥派生基) GM/T 0009-0012 公钥格式 · 算法标识 OID · 编码规范 GM/T 0016 / 0018 签名私钥不可导出 临时密钥生命周期 GM/T 0010 密文C1C2C3边界 公钥嵌入前导 密钥边界约束输出 ① 长度合规(256/128)② 数值范围严格 ③ 格式封装统一(前缀/OID/DER)④ 生命周期受控 ⑤ 跨标准引用一致性(签名用SM3、加密用SM4派生)

密钥边界校验实战清单

讲完了标准,来点干货。这是我自己整理的一个密钥边界校验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里的关系链,实际落地方案时很有用。