1. 国密算法概述:SM2/SM3/SM4/SM9 算法家族介绍

各位同学,咱们今天先聊聊国密算法的整体面貌。说实话,我刚入行那会儿,国密还是个「小众」领域,项目里能用 OpenSSL 搞定的事,没人愿意碰国密。但这些年不一样了——金融、政务、电力,甚至你手机里的身份证电子证照,底层跑的都是国密算法。

国密算法不是某一个算法,而是一整套密码体系。它覆盖了公钥加密、数字签名、哈希计算、对称加密、标识密码等核心场景。我习惯把这套体系叫做「中国密码工具箱」——你想想看,一个工具箱里得有扳手、螺丝刀、锤子,缺了哪个都不顺手。

核心要点:国密算法家族目前包含 SM2、SM3、SM4、SM9 四个主力算法,分别对标国际上的 RSA/ECDSA、SHA-256、AES、IBE。它们不是简单复制,而是在安全参数、曲线选择、实现效率上做了针对性优化。

1.1 SM2:椭圆曲线公钥密码算法

SM2 是国密体系里的「门面担当」。它基于椭圆曲线密码学(ECC),支持密钥交换、数字签名、数据加密三大功能。我个人觉得,SM2 最聪明的地方在于选择了 256 位的素域曲线——这个参数既保证了 128 位的安全强度,又让计算效率比 384 位曲线快不少。

我在项目中遇到过一件事:某次做金融系统的国密改造,客户坚持要用 SM2 替换 RSA-2048。结果一测性能,SM2 签名快了 3 倍,但验签慢了 20%。后来发现是没做预计算优化。嗯,这里要注意——SM2 的验签涉及两次点乘,如果不缓存公钥的预计算表,性能确实会打折扣。

算法 密钥长度 安全强度 主要用途
SM2 256 位 128 位 签名、加密、密钥交换
RSA-2048 2048 位 112 位 签名、加密
ECDSA (P-256) 256 位 128 位 签名

避坑指南:SM2 的密钥对生成必须使用合格的随机数发生器。我曾经见过某厂商直接用 rand() 生成 SM2 私钥,结果两个设备生出了相同的密钥对——这比没有加密还可怕。

1.2 SM3:密码杂凑算法

SM3 是国密体系的「指纹机」。它输出 256 位的哈希值,设计上借鉴了 SHA-256 的 Merkle-Damgård 结构,但在消息扩展和压缩函数上做了改动。说白了,SM3 的安全冗余比 SHA-256 更高——它的压缩函数有 64 轮迭代,而 SHA-256 是 64 轮但每轮操作更简单。

我记得有一次做等保测评,对方问:「SM3 和 SHA-256 到底谁更安全?」我的回答是:从密码分析角度看,两者目前都没有实际攻击;但从设计哲学看,SM3 的雪崩效应更均匀,差分攻击的难度更大。当然,这不是说 SHA-256 不安全,而是国标在设计时吸收了国际算法二十年的攻击经验。

重要提醒:SM3 的初始化向量(IV)是固定的 8 个 32 位字,任何实现都必须使用 GB/T 32905-2016 规定的 IV 值。我见过有人把 SM3 的 IV 改成全零,结果算出来的哈希值完全不可用——这不是 SM3,这是自创算法。

1.3 SM4:分组密码算法

SM4 是国密体系里的「加密快手」。它是对称分组密码,分组长度 128 位,密钥长度也是 128 位,采用 32 轮非线性迭代结构。你可能会问:为什么不用 AES?其实 SM4 的设计目标很明确——在资源受限的嵌入式设备上跑得快,同时抗住差分分析和线性分析。

我在做物联网安全方案时,对比过 SM4 和 AES-128 在 Cortex-M4 上的性能。结果很有意思:SM4 的查表实现比 AES 快约 15%,但抗侧信道攻击的能力需要额外加掩码。嗯,这里要记住——SM4 的 S 盒是固定的 8×8 置换,和 AES 的 S 盒完全不同,不能混用。

// SM4 密钥扩展示例(简化版)
void sm4_key_expand(const uint8_t key[16], uint32_t rk[32]) {
    uint32_t K[4];
    // 将密钥拆分为 4 个 32 位字
    for (int i = 0; i < 4; i++) {
        K[i] = (key[4*i] << 24) | (key[4*i+1] << 16) |
               (key[4*i+2] << 8)  | key[4*i+3];
        K[i] ^= FK[i];  // 系统参数 FK
    }
    // 32 轮迭代生成轮密钥
    for (int i = 0; i < 32; i++) {
        uint32_t tmp = K[1] ^ K[2] ^ K[3] ^ CK[i];
        rk[i] = K[0] ^ sm4_tau(tmp);
        K[0] = K[1]; K[1] = K[2]; K[2] = K[3]; K[3] = rk[i];
    }
}

1.4 SM9:标识密码算法

SM9 是国密体系里的「黑科技」。它基于双线性对(Pairing),允许直接用用户的标识(比如邮箱、手机号、身份证号)作为公钥。这意味着什么?你不需要再维护证书吊销列表(CRL),不需要在线查询证书状态——公钥本身就是标识,天然解决了公钥分发问题。

说实话,SM9 的实现难度比 SM2 高一个量级。双线性对的计算涉及扩域上的 Miller 算法和最终幂运算,稍不注意就会踩坑。我曾在 SM9 的密钥封装(KEM)实现中踩过一个雷:双线性对的群元素序列化格式,国标规定用压缩表示,但很多开源库默认用非压缩格式——对接时数据直接解析失败。

特性 SM2 SM9
公钥来源 随机生成 用户标识
证书需求 需要 CA 签发 不需要证书
计算开销 较低 较高(双线性对)
适用场景 通用密码服务 IoT、邮件加密、无证书环境

1.5 国密与国际算法对比

很多同学会问:国密算法和国际算法到底差在哪?我个人的理解是:国密算法在设计上更「保守」,安全冗余给得更足。比如 SM3 的压缩函数轮数比 SHA-256 多,SM4 的密钥扩展算法比 AES 复杂——这些设计选择牺牲了一点性能,但换来了更高的安全容错空间。

但这不是说国密就比国际算法「好」。AES 有硬件加速指令(AES-NI),SM4 目前还没有广泛支持的硬件指令,纯软件实现时性能差距明显。你想想看,在支持 AES-NI 的 CPU 上,AES-128 加密 1GB 数据只需要 0.5 秒,SM4 纯软件可能要 2 秒——这个差距在高速网络场景下是不能忽视的。

对比总结:国密算法在安全强度上与国际主流算法持平或略高,但在生态成熟度、硬件支持、国际互认方面仍有差距。选型时不要「为了国密而国密」,要根据实际场景做权衡。

1.6 国密标准体系

国密标准不是孤立的几个算法文档,而是一整套从算法、协议、接口到应用的标准体系。我习惯把它分为三层:

  • 算法层:GB/T 32918(SM2)、GB/T 32905(SM3)、GB/T 32907(SM4)、GB/T 38644(SM9)——定义算法的数学原理和基本运算。
  • 协议层:GB/T 35276(SM2 数字签名协议)、GB/T 38647(SM9 密钥交换协议)——定义如何使用算法完成具体密码协议。
  • 应用层:GM/T 0009(SM2 密码机接口)、GM/T 0018(智能密码钥匙接口)——定义密码模块的 API 和数据格式。

我记得刚开始做国密项目时,最头疼的就是标准文档的版本管理。同一个算法,国标(GB/T)和行标(GM/T)的细节可能不一样——比如 SM2 的椭圆曲线参数,国标和行标在基点坐标的表示上有细微差异。嗯,这里要提醒大家:做产品时一定要确认你引用的标准版本,最好在文档里写明「依据 GB/T 32918.1-2016」。

国密算法家族结构图 国密算法家族结构图 国密算法家族 SM2 公钥密码 SM3 密码杂凑 SM4 分组密码 SM9 标识密码 数字签名 密钥交换 数据加密 消息摘要 / 完整性校验 ECB/CBC CTR/GCM 密钥封装 数字签名 密钥协商 说明: SM2/SM3/SM4 构成国密基础算法层,SM9 基于双线性对实现标识密码,属于进阶算法。

1.7 本章小结

国密算法家族不是凭空造出来的,它是在国际密码学基础上,结合中国实际需求和安全标准演化而来的。SM2 对标 ECDSA/RSA,SM3 对标 SHA-256,SM4 对标 AES,SM9 对标 IBE——每一款算法都有明确的定位和适用场景。

我个人建议,刚开始接触国密的同学,先吃透 SM2 和 SM4,这两个是项目里用得最多的。SM3 相对简单,但要注意它的 IV 和填充规则。SM9 可以放一放,等把双线性对的基础打牢了再深入。

学习建议:下载 GB/T 32918、GB/T 32905、GB/T 32907 的官方 PDF,对照着看。标准文档虽然枯燥,但所有实现的「坑」都在里面写着——比任何博客都靠谱。