一、国密算法体系概览
“国密”(GM,GuoMi)是中国商用密码算法体系的通称。这一体系由国家密码管理局(SCA,State Cryptography Administration)主导设计与发布,旨在为国家关键信息基础设施、政务系统和金融行业提供自主可控的密码学基础。从上世纪九十年代末开始酝酿,到二十一世纪初陆续公开发布,国密算法走过了一段从内部使用到公开标准、再到国际认可的发展历程。
在历史背景方面,中国密码学研究起步并不晚——早在二十世纪六七十年代,为满足国防与外交通信需求,国内已有系统性的密码算法研究。然而,民用密码领域长期依赖国际算法(如 DES、AES、RSA、SHA 系列),核心算法的知识产权和潜在后门风险使得国家在战略层面产生了忧虑。2006 年前后,国家密码管理局先后公开了 SM2、SM3、SM4 等算法的技术规范,标志着中国商用密码进入了”公开透明、接受审查”的新阶段。
国密算法体系的标准化工作主要通过 GM/T 标准(密码行业标准)和 GB/T 标准(国家标准)两个层次进行。GM/T 标准由国家密码管理局发布,侧重于算法规范和接口定义;GB/T 标准则由国家标准化管理委员会发布,具有更广泛的法律效力。例如,SM4 分组密码最初以 GM/T 0002—2012 发布,后升格为 GB/T 32907—2016;SM3 杂凑算法对应 GB/T 32905—2016;SM2 椭圆曲线公钥密码算法对应 GB/T 32918 系列标准;SM9 标识密码对应 GB/T 38635 系列标准。
在国际标准化方面,国密算法近年取得了显著进展。SM2 数字签名算法于 2017 年被纳入 ISO/IEC 14888-3:2018 标准;SM3 杂凑算法被纳入 ISO/IEC 10118-3:2018 标准;SM9 标识密码算法的数字签名部分被纳入 ISO/IEC 14888-3:2018 标准。SM4 分组密码则在 2021 年正式成为 ISO/IEC 18033-3:2010/Amd 1:2021 的一部分。这些国际认可意味着国密算法在设计质量和安全强度上得到了国际密码学界的初步背书。
国密算法体系的整体架构可以概括如下:对称密码层面,SM4 提供 128 比特的分组加密能力,ZUC 提供流密码加密能力;杂凑算法层面,SM3 提供 256 比特的散列输出;公钥密码层面,SM2 基于椭圆曲线提供数字签名、密钥交换和公钥加密功能,SM9 基于双线性对(Bilinear Pairing)提供基于标识的密码功能。这一体系在功能上与国际主流算法体系(AES + SHA-256 + ECDSA/ECDH)形成了一一对应的替代关系。
下表以「族谱」的视角呈现国密标准体系的完整映射——从算法类型、核心功能到国家标准编号和典型应用场景:
| 算法 | 类型 | 核心功能 | 国家标准 | 国际标准 | 典型应用场景 |
|---|---|---|---|---|---|
| SM2 | 公钥密码(椭圆曲线) | 数字签名、密钥交换、公钥加密 | GB/T 32918 系列 | ISO/IEC 14888-3 | PKI 体系、eID 电子身份、SSL/TLS |
| SM3 | 杂凑算法 | 消息摘要、完整性校验 | GB/T 32905—2016 | ISO/IEC 10118-3 | 数据完整性、区块链、数字签名预处理 |
| SM4 | 对称分组密码 | 数据加密(128 比特) | GB/T 32907—2016 | ISO/IEC 18033-3/Amd1 | VPN 加密、存储加密、WAPI 无线安全 |
| SM9 | 标识密码(双线性对) | 基于标识的签名/加密/密钥交换 | GB/T 38635 系列 | ISO/IEC 14888-3 | IoT 设备认证、加密邮件、轻量级 PKI |
| ZUC | 流密码 | 流式数据加密 | GM/T 0001—2012 | 3GPP(EEA3/EIA3) | 4G/5G 移动通信加密与完整性保护 |
个人观察: 围绕国密算法的讨论中,有一种常见的误读——将「密码主权」简单等同于政治行为。这种看法忽略了密码学独立性背后深刻的工程合理性。从纯技术角度看,对单一算法体系的全球依赖本身就是一种系统性风险:如果 AES 或 SHA-2 被发现存在结构性弱点(历史上 DES、MD5、SHA-1 都经历过这一过程),拥有独立且经过充分分析的替代算法意味着你有退路。SM3 和 SM4 的设计质量经受住了十余年的国际密码分析检验,SM2 所用的椭圆曲线参数也通过了标准的安全性审计。更务实地说,密码算法的多样性对整个生态是有益的——正如生物多样性增强了生态系统的鲁棒性,密码算法的多样性降低了「一把钥匙开所有锁」式的系统性灾难风险。当然,透明度是关键前提:SM4 的 S 盒设计准则未完全公开这一点确实是一个遗憾,值得持续推动改进。
二、SM4 分组密码
SM4 是中国第一个公开发布的商用分组密码算法,最初以 SMS4 之名应用于无线局域网安全标准 WAPI(Wireless Authentication and Privacy Infrastructure)。该算法的分组长度为 128 比特,密钥长度同样为 128 比特,共执行 32 轮变换。
SM4 的整体结构采用了非平衡 Feistel(Feistel-like)网络。在每一轮中,算法将 128 比特的状态分为四个 32 比特的字 X₀、X₁、X₂、X₃,轮函数 F 的计算方式为:
X_{i+4} = X_i ⊕ T(X_{i+1} ⊕ X_{i+2} ⊕ X_{i+3} ⊕ rk_i)
其中 rk_i 为第 i 轮的轮密钥,T 是由非线性变换 τ 和线性变换 L 复合而成的可逆变换。非线性变换 τ 由四个并行的 S 盒(S-box)查表操作构成,每个 S 盒是一个 8 比特到 8 比特的置换。线性变换 L 定义为:
L(B) = B ⊕ (B <<< 2) ⊕ (B <<< 10) ⊕ (B <<< 18) ⊕ (B <<< 24)
其中 <<< 表示循环左移操作。
SM4 的 S 盒设计是其安全性的核心要素之一。该 S 盒具有良好的差分均匀度和非线性度:其最大差分概率为 2⁻⁶,非线性度达到 112(理论最大值为 120)。与 AES 的 S 盒相比,SM4 的 S 盒在代数次数上略有不同——AES 的 S 盒基于 GF(2⁸) 上的乘法逆元构造,具有清晰的代数结构;SM4 的 S 盒则通过仿射变换与 GF(2⁸) 上的逆元复合而成,但其具体设计准则未完全公开,这曾引发学术界的一些讨论。
密钥扩展方面,SM4 使用系统参数 FK 和常量密钥 CK 对 128 比特主密钥进行扩展,生成 32 个 32 比特的轮密钥。密钥扩展的结构与加密轮函数类似,但使用了不同的线性变换 L’:
L'(B) = B ⊕ (B <<< 13) ⊕ (B <<< 23)
解密过程与加密过程完全相同,仅需将轮密钥的使用顺序颠倒即可。这种对称性是 Feistel 类结构的固有优势,简化了硬件实现。
与 AES 的比较是一个常见话题。从安全强度来看,SM4 和 AES-128 均提供 128 比特的安全级别,目前均无已知的实际攻击能够突破其完整轮数。AES 使用 10 轮变换(128 比特密钥时),而 SM4 使用 32 轮,轮数更多意味着更大的安全余量,但也带来了更高的计算开销。在软件性能方面,由于 AES 在主流处理器上拥有专用指令集(AES-NI),其吞吐量远超 SM4 的纯软件实现。不过近年来,部分国产处理器(如海光、鲲鹏等)已开始加入 SM4 硬件加速指令,性能差距正在缩小。
SM4 支持多种工作模式,包括 ECB、CBC、CFB、OFB 和 CTR 等标准分组密码工作模式,以及 GCM 等认证加密模式。在实际应用中,GCM 模式因其同时提供机密性和完整性保护而备受青睐。
三、SM3 杂凑算法
SM3 是中国商用密码体系中的杂凑算法(Hash Function),输出长度为 256 比特,适用于数字签名、消息认证码(MAC)和随机数生成等场景。该算法由王小云院士团队设计,于 2010 年正式公开发布。
SM3 采用了经典的 Merkle-Damgård 迭代结构。输入消息首先进行填充——在消息末尾添加比特”1”,然后添加若干比特”0”,最后附加一个 64 比特的消息长度字段,使得填充后的消息长度为 512 比特的整数倍。填充后的消息被分为若干个 512 比特的分组,逐一输入压缩函数进行处理。
SM3 的压缩函数(Compression Function)是算法的核心。它接收一个 256 比特的链接值(Chaining Value)和一个 512 比特的消息分组作为输入,输出一个 256 比特的新链接值。压缩函数内部执行 64 轮迭代,分为两个阶段:前 16 轮使用常量 Tj = 0x79CC4519,后 48 轮使用常量 Tj = 0x7A879D8A。
消息扩展(Message Expansion)是 SM3 的一个重要环节。512 比特的消息分组首先被拆分为 16 个 32 比特的字 W₀ 至 W₁₅,然后通过以下递推公式扩展为 68 个字:
W_j = P₁(W_{j-16} ⊕ W_{j-9} ⊕ (W_{j-3} <<< 15)) ⊕ (W_{j-13} <<< 7) ⊕ W_{j-6}
其中 P₁(X) = X ⊕ (X <<< 15) ⊕ (X <<< 23) 是置换函数。此外,还需计算 W’j = W_j ⊕ W{j+4}(j = 0, 1, …, 63),用于压缩函数的迭代运算。
压缩函数每一轮的运算涉及两个布尔函数 FF 和 GG。在前 16 轮中:
FF_j(X, Y, Z) = X ⊕ Y ⊕ Z
GG_j(X, Y, Z) = X ⊕ Y ⊕ Z
在后 48 轮中:
FF_j(X, Y, Z) = (X ∧ Y) ∨ (X ∧ Z) ∨ (Y ∧ Z)
GG_j(X, Y, Z) = (X ∧ Y) ∨ (¬X ∧ Z)
与 SHA-256 的比较,两者在结构上有诸多相似之处:均采用 Merkle-Damgård 结构,输出长度均为 256 比特,消息分组长度均为 512 比特。但在细节设计上存在差异——SM3 的消息扩展更为复杂,增加了字之间的混淆程度;SM3 使用了两组不同的布尔函数和常量,而 SHA-256 在所有轮中使用相同类型的布尔函数。从安全性分析角度看,SM3 自发布以来经受了广泛的密码分析研究,目前最好的公开攻击结果是对简化到约 32 轮的 SM3 的碰撞攻击,完整 64 轮的 SM3 尚未发现任何实际安全威胁。
以下是使用 Python 计算 SM3 杂凑值的示例代码:
#!/usr/bin/env python3
"""SM3 杂凑算法演示(使用 gmssl 库)"""
# pip install gmssl
from gmssl import sm3, func
def sm3_hash(message: str) -> str:
"""计算字符串的 SM3 杂凑值,返回十六进制摘要。"""
msg_bytes = message.encode("utf-8")
# func.bytes_to_list 将 bytes 转为整数列表
msg_list = func.bytes_to_list(msg_bytes)
digest = sm3.sm3_hash(msg_list)
return digest
def sm3_hash_manual(data: bytes) -> str:
"""
SM3 杂凑算法的简化纯 Python 实现。
仅用于教学演示,生产环境请使用经过审计的密码库。
"""
# ---------- 常量 ----------
IV = [
0x7380166F, 0x4914B2B9, 0x172442D7, 0xDA8A0600,
0xA96F30BC, 0x163138AA, 0xE38DEE4D, 0xB0FB0E4E,
]
T = [0x79CC4519] * 16 + [0x7A879D8A] * 48
def rotl(x, n):
"""32 比特循环左移"""
return ((x << n) | (x >> (32 - n))) & 0xFFFFFFFF
def p0(x):
return x ^ rotl(x, 9) ^ rotl(x, 17)
def p1(x):
return x ^ rotl(x, 15) ^ rotl(x, 23)
def ff(j, x, y, z):
if j < 16:
return x ^ y ^ z
return (x & y) | (x & z) | (y & z)
def gg(j, x, y, z):
if j < 16:
return x ^ y ^ z
return (x & y) | (~x & z & 0xFFFFFFFF)
# ---------- 填充 ----------
msg = bytearray(data)
bit_len = len(msg) * 8
msg.append(0x80)
while (len(msg) * 8) % 512 != 448:
msg.append(0x00)
msg += bit_len.to_bytes(8, "big")
# ---------- 分组迭代 ----------
V = list(IV)
for i in range(0, len(msg), 64):
block = msg[i : i + 64]
W = [int.from_bytes(block[j * 4 : j * 4 + 4], "big") for j in range(16)]
for j in range(16, 68):
tmp = p1(W[j - 16] ^ W[j - 9] ^ rotl(W[j - 3], 15))
W.append((tmp ^ rotl(W[j - 13], 7) ^ W[j - 6]) & 0xFFFFFFFF)
Wp = [(W[j] ^ W[j + 4]) & 0xFFFFFFFF for j in range(64)]
A, B, C, D, E, F, G, H = V
for j in range(64):
SS1 = rotl((rotl(A, 12) + E + rotl(T[j], j % 32)) & 0xFFFFFFFF, 7)
SS2 = SS1 ^ rotl(A, 12)
TT1 = (ff(j, A, B, C) + D + SS2 + Wp[j]) & 0xFFFFFFFF
TT2 = (gg(j, E, F, G) + H + SS1 + W[j]) & 0xFFFFFFFF
D = C
C = rotl(B, 9)
B = A
A = TT1
H = G
G = rotl(F, 19)
F = E
E = p0(TT2)
V = [(v ^ x) & 0xFFFFFFFF for v, x in zip(V, [A, B, C, D, E, F, G, H])]
return "".join(f"{w:08x}" for w in V)
if __name__ == "__main__":
# 标准测试向量:对 "abc" 计算 SM3
test_msg = "abc"
expected = "66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0"
result = sm3_hash_manual(test_msg.encode("utf-8"))
print(f"消息: \"{test_msg}\"")
print(f"SM3: {result}")
print(f"校验: {'通过' if result == expected else '失败'}")
# 使用 gmssl 库验证
try:
lib_result = sm3_hash(test_msg)
print(f"gmssl 库结果: {lib_result}")
except ImportError:
print("(gmssl 库未安装,跳过库验证)")四、SM2 椭圆曲线算法
SM2 是中国商用密码体系中的椭圆曲线公钥密码算法(Elliptic Curve Cryptography,ECC),涵盖数字签名、密钥交换和公钥加密三项核心功能。该算法基于素数域上的椭圆曲线离散对数问题(ECDLP,Elliptic Curve Discrete Logarithm Problem),在 256 比特的密钥长度下提供约 128 比特的安全强度。
SM2 推荐使用的椭圆曲线参数集通常被称为 sm2p256v1,其定义在 256 比特的素数域 GF(p) 上,曲线方程为标准的 Weierstrass 形式:
y² = x³ + ax + b (mod p)
具体参数如下:
- 素数 p = FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFF
- 系数 a = FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFC
- 系数 b = 28E9FA9E 9D9F5E34 4D5A9E4B CF6509A7 F39789F5 15AB8F92 DDBCBD41 4D940E93
- 基点 G 的 x 坐标 Gx = 32C4AE2C 1F198119 5F990446 6A39C994 8FE30BBF F2660BE1 715A4589 334C74C7
- 基点 G 的 y 坐标 Gy = BC3736A2 F4F6779C 59BDCEE3 6B692153 D0A9877C C62A4740 02DF32E5 2139F0A0
- 基点的阶 n = FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF 7203DF6B 21C6052B 53BBF409 39D54123
这条曲线的选取经过了严格的安全性审查。余因子 h = 1,意味着曲线上所有点都属于由基点 G 生成的循环群,避免了小子群攻击的风险。此外,该曲线的判别式不为零,embedding degree 足够大,能够抵抗 MOV 攻击(将 ECDLP 归约到有限域上的离散对数问题)。
密钥生成过程非常直接:随机选取一个整数 d ∈ [1, n-2] 作为私钥,计算 P = d·G 作为公钥。这里的标量乘法 d·G 是将基点 G 与自身相加 d 次的结果,在已知 P 和 G 的情况下求解 d 在计算上是不可行的——这正是椭圆曲线密码学的安全基础。
SM2 公钥加密方案采用了类似于 ECIES(Elliptic Curve Integrated Encryption Scheme)的混合加密模式。加密过程如下:
- 随机选取整数 k ∈ [1, n-1],计算 C₁ = k·G(即临时公钥);
- 计算共享点 S = k·P_B(P_B 为接收方公钥),若 S 为无穷远点则返回错误;
- 利用密钥派生函数 KDF(Key Derivation Function)从共享点的坐标派生对称密钥 t = KDF(x₂ ‖ y₂, klen);
- 计算密文 C₂ = M ⊕ t(M 为明文);
- 计算杂凑值 C₃ = SM3(x₂ ‖ M ‖ y₂),作为完整性校验码;
- 输出密文 C = C₁ ‖ C₃ ‖ C₂(新标准格式)或 C = C₁ ‖ C₂ ‖ C₃(旧标准格式)。
解密过程则为加密的逆操作:接收方使用私钥 d_B 计算共享点 S = d_B·C₁ = d_B·k·G = k·P_B,然后依次恢复密钥、明文并验证杂凑值。
SM2 加密方案中一个值得注意的设计特点是 KDF 的使用方式。与 RSA-OAEP 等方案不同,SM2 的 KDF 直接从椭圆曲线点的坐标推导密钥流,然后与明文进行异或操作。这意味着 SM2 加密在本质上是一种流密码式的加密,密钥流的长度需要与明文长度匹配。这一设计使得 SM2 加密可以处理任意长度的明文,但也意味着对于较长的消息,KDF 需要产生足够长的输出。
SM2 加密方案中引入了 ZA 值的概念,这是 SM2 区别于其他椭圆曲线方案的一个重要特征。ZA 是用户标识信息(包括用户 ID、椭圆曲线参数和用户公钥)经 SM3 杂凑后得到的 256 比特哈希值。在签名和密钥交换协议中,ZA 作为前缀参与运算,有效地将用户身份绑定到密码学操作中,增强了协议的安全性。
以下示例代码展示了 SM2 密钥生成的基本流程:
#!/usr/bin/env python3
"""SM2 密钥生成与签名验签演示"""
import secrets
# SM2 推荐曲线参数
SM2_P = 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF
SM2_A = 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC
SM2_B = 0x28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93
SM2_N = 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123
SM2_GX = 0x32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7
SM2_GY = 0xBC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0
INF = (None, None) # 无穷远点
def mod_inv(a: int, m: int) -> int:
"""模逆元(扩展欧几里得算法)"""
if a < 0:
a = a % m
g, x, _ = _extended_gcd(a, m)
if g != 1:
raise ValueError("模逆元不存在")
return x % m
def _extended_gcd(a, b):
if a == 0:
return b, 0, 1
g, x, y = _extended_gcd(b % a, a)
return g, y - (b // a) * x, x
def point_add(P, Q, p=SM2_P, a=SM2_A):
"""椭圆曲线点加法"""
if P == INF:
return Q
if Q == INF:
return P
x1, y1 = P
x2, y2 = Q
if x1 == x2:
if (y1 + y2) % p == 0:
return INF
# 倍点公式
lam = (3 * x1 * x1 + a) * mod_inv(2 * y1, p) % p
else:
lam = (y2 - y1) * mod_inv(x2 - x1, p) % p
x3 = (lam * lam - x1 - x2) % p
y3 = (lam * (x1 - x3) - y1) % p
return (x3, y3)
def scalar_mult(k: int, P, p=SM2_P, a=SM2_A):
"""标量乘法(双倍加法)"""
result = INF
addend = P
while k > 0:
if k & 1:
result = point_add(result, addend, p, a)
addend = point_add(addend, addend, p, a)
k >>= 1
return result
def sm2_keygen():
"""生成 SM2 密钥对"""
G = (SM2_GX, SM2_GY)
# 私钥: 随机整数 d ∈ [1, n-2]
d = secrets.randbelow(SM2_N - 2) + 1
# 公钥: P = d·G
P = scalar_mult(d, G)
return d, P
def format_hex(value: int, width: int = 64) -> str:
"""将整数格式化为定长十六进制字符串"""
return f"{value:0{width}x}"
if __name__ == "__main__":
print("=== SM2 密钥生成演示 ===\n")
private_key, public_key = sm2_keygen()
print(f"私钥 d = {format_hex(private_key)}")
print(f"公钥 Px = {format_hex(public_key[0])}")
print(f"公钥 Py = {format_hex(public_key[1])}")
# 验证公钥在曲线上
x, y = public_key
lhs = (y * y) % SM2_P
rhs = (x * x * x + SM2_A * x + SM2_B) % SM2_P
assert lhs == rhs, "公钥不在曲线上!"
print("\n公钥验证:点在 SM2 推荐曲线上 通过")
# 验证 n·G = O(无穷远点)
G = (SM2_GX, SM2_GY)
O = scalar_mult(SM2_N, G)
assert O == INF, "n·G 应为无穷远点"
print("阶验证:n·G = O 通过")五、SM2 签名与密钥交换
SM2 数字签名算法是国密体系中使用最广泛的公钥密码功能,其在协议设计上与 ECDSA(Elliptic Curve Digital Signature Algorithm)有相似之处,但在关键步骤上存在显著差异。
SM2 签名算法的核心流程如下。设签名者的私钥为 d_A,公钥为 P_A = d_A·G。对消息 M 签名时:
- 计算 ZA = SM3(ENTLA ‖ IDA ‖ a ‖ b ‖ Gx ‖ Gy ‖ xA ‖ yA),其中 IDA 为用户标识(默认为十六进制字符串 “1234567812345678”),ENTLA 为 IDA 的比特长度;
- 计算消息杂凑 e = SM3(ZA ‖ M),将 e 转换为整数;
- 随机选取 k ∈ [1, n-1],计算椭圆曲线点 (x₁, y₁) = k·G;
- 计算 r = (e + x₁) mod n,若 r = 0 或 r + k = n,则返回步骤 3 重新选取 k;
- 计算 s = ((1 + d_A)⁻¹ · (k - r·d_A)) mod n,若 s = 0,则返回步骤 3;
- 输出签名 (r, s)。
验签过程如下:
- 同样计算 ZA 和 e;
- 计算 t = (r + s) mod n,若 t = 0 则签名无效;
- 计算椭圆曲线点 (x₁’, y₁’) = s·G + t·P_A;
- 验证 (e + x₁’) mod n 是否等于 r。
与 ECDSA 相比,SM2 签名的主要差异体现在以下几点。第一,SM2 在签名过程中引入了用户标识 ZA,将签名者的身份信息嵌入到签名计算中,这增强了抗身份伪造的能力。ECDSA 不包含类似机制,签名仅与消息和密钥相关。第二,SM2 签名中 r 的计算方式为 r = (e + x₁) mod n,而 ECDSA 中 r = x₁ mod n,即 SM2 将消息杂凑值直接参与到 r 的计算中。第三,SM2 中 s 的计算公式涉及 (1 + d_A)⁻¹,而 ECDSA 中为 k⁻¹,这使得两者的代数结构有所不同。
SM2 签名算法对随机数 k 的安全性要求极为严格,与 ECDSA 相同——若两次签名使用了相同的 k 值,攻击者可以通过两个签名方程联立求解出私钥 d_A。因此,在实际实现中通常采用 RFC 6979 类似的确定性随机数生成方案(Deterministic k Generation),或确保使用高质量的密码学安全随机数生成器。
SM2 密钥交换协议(Key Exchange Protocol)允许通信双方在不安全的信道上协商出共享密钥。该协议基于椭圆曲线 Diffie-Hellman(ECDH)的思想,但增加了额外的安全措施。协议流程概述如下:
- 双方各自生成临时密钥对:发起方 A 生成 (r_A, R_A = r_A·G),响应方 B 生成 (r_B, R_B = r_B·G);
- 双方交换临时公钥 R_A 和 R_B;
- 双方各自利用己方的长期私钥、临时私钥以及对方的长期公钥和临时公钥,通过一个特定的计算公式得到共享秘密点;
- 利用 KDF 从共享秘密点派生出对称密钥。
SM2 密钥交换协议的一个重要特点是它提供了密钥确认(Key Confirmation)步骤——双方在密钥协商完成后还可以交换各自计算的杂凑值来验证对方确实持有正确的密钥。这使得协议能够抵抗中间人攻击,前提是双方的长期公钥已经通过可信渠道(如 CA 证书)进行了绑定。
六、SM9 标识密码
SM9 是中国商用密码体系中的标识密码(Identity-Based Cryptography,IBC)算法,由密码学家程朝辉等人设计。标识密码的核心思想是:用户的公钥直接由其标识信息(如电子邮件地址、手机号码或身份证号)派生,无需传统的公钥证书基础设施(PKI)。
SM9 基于双线性对(Bilinear Pairing)构建,使用 BN 曲线(Barreto-Naehrig Curve)作为其底层数学结构。BN 曲线是一类特殊的椭圆曲线,具有高效可计算的双线性对 e: G₁ × G₂ → G_T,其中 G₁ 和 G₂ 是曲线上的两个循环群,G_T 是目标群(通常是有限域上的乘法群)。
SM9 标识加密(IBE,Identity-Based Encryption)的工作流程如下:
- 系统建立(Setup):密钥生成中心(KGC,Key Generation Center)选择主私钥 s ∈ [1, N-1],计算主公钥 P_pub = s·P₂(P₂ 为 G₂ 的生成元),并公布系统参数;
- 密钥提取(Extract):KGC 根据用户标识 ID 计算用户私钥 d_ID = s·H₁(ID)·P₁(其中 H₁ 是将标识映射到曲线点的杂凑函数,P₁ 为 G₁ 的生成元);
- 加密(Encrypt):发送方仅需接收方的标识 ID 和系统公参即可加密——计算 Q_B = H₁(ID_B)·P₂,选取随机数 r,计算密文各分量;
- 解密(Decrypt):接收方使用 KGC 签发的私钥 d_ID 进行解密。
SM9 标识签名(IBS,Identity-Based Signature)的流程类似于 SM2 签名,但底层使用了双线性对运算。签名者使用 KGC 为其签发的标识私钥进行签名,验签者仅需签名者的标识信息和系统公参即可完成验证。
SM9 密钥封装机制(KEM,Key Encapsulation Mechanism)提供了一种高效的密钥分发方式。发送方利用接收方的标识信息封装一个对称密钥,接收方使用其标识私钥解封装得到对称密钥。这一机制特别适合于大规模密钥分发场景。
SM9 的安全性基于若干计算困难假设,包括双线性 Diffie-Hellman 问题(BDH)和判定性双线性 Diffie-Hellman 问题(DBDH)。BN 曲线上的双线性对参数选取需确保足够的安全强度——随着数域筛法(NFS)在有限域离散对数问题上的进展,BN 曲线的安全性评估需要持续关注。目前 SM9 推荐的 256 比特 BN 曲线被认为提供了约 128 比特的安全强度,但学术界对此存在一些讨论。
SM9 最大的优势在于简化了密钥管理。在传统 PKI 体系中,每个用户需要申请并维护数字证书,证书的签发、更新、吊销等环节增加了系统的复杂度。SM9 体系中,用户的”公钥”就是其标识信息,发送方无需查询证书库即可完成加密或验签操作。然而,SM9 也存在固有的局限性——KGC 持有主私钥,理论上可以解密任何用户的消息或伪造任何用户的签名,这一”密钥托管”(Key Escrow)问题是所有标识密码方案的共性挑战。在一些场景下,这反而是一种优势(如企业内部通信的监管需求),但在需要端到端安全性的场景中则是一个显著的限制。
七、ZUC 流密码
ZUC(祖冲之密码)是中国提出并被 3GPP(Third Generation Partnership Project)采纳的流密码算法,用于 4G LTE 网络中的数据加密(128-EEA3)和完整性保护(128-EIA3)。该算法以中国古代数学家祖冲之命名,体现了中国密码学界对自主创新的追求。
ZUC 的内部结构由三个核心部件组成:线性反馈移位寄存器(LFSR,Linear Feedback Shift Register)、比特重组层(BR,Bit Reorganization)和有限状态机(FSM,Finite State Machine)。
LFSR 是 ZUC 的状态存储核心,由 16 个 31 比特的寄存器单元 s₀ 至 s₁₅ 组成。LFSR 工作在素数域 GF(2³¹ - 1) 上——选择梅森素数 2³¹ - 1 作为模数使得取模运算可以高效实现。LFSR 的反馈多项式经过精心设计,确保生成序列的周期达到最大值 (2³¹ - 1)¹⁶ - 1。
比特重组层从 LFSR 的 16 个寄存器单元中选取特定的比特段,组合成四个 32 比特的字 X₀、X₁、X₂、X₃,供有限状态机使用。这一层的设计目标是打破 LFSR 输出的线性关系,增加密钥流的非线性度。
有限状态机由两个 32 比特的状态变量 R₁ 和 R₂ 组成,并包含两个 S 盒(S₀ 和 S₁)。FSM 的每一步接收来自比特重组层的输入,经过非线性变换后输出一个 32 比特的密钥流字。FSM 的非线性变换包括 S 盒查表、模加运算和线性变换,这些操作的组合为密钥流提供了良好的统计特性和抗密码分析能力。
ZUC 的初始化过程接收 128 比特的密钥和 128 比特的初始向量(IV),通过 32 轮初始化迭代建立内部状态。初始化完成后,每次调用密钥流生成函数可输出一个 32 比特的密钥流字。
128-EEA3 是基于 ZUC 的加密算法,工作方式类似于流密码的标准用法——将密钥流与明文逐比特异或得到密文。128-EIA3 是基于 ZUC 的消息认证码算法,利用密钥流和通用杂凑函数构造消息认证码,提供完整性保护。
ZUC 在 3GPP 标准中的地位与 SNOW 3G(128-EEA1/128-EIA1)和 AES(128-EEA2/128-EIA2)并列,是三套可选的安全算法之一。ZUC 的加入使得 4G/5G 网络的安全机制拥有了算法多样性,降低了单一算法被攻破带来的系统性风险。
八、国密合规与部署
随着《中华人民共和国密码法》于 2020 年 1 月 1 日正式实施,国密算法的合规部署从行业倡议上升为法律要求。密码法将密码分为核心密码、普通密码和商用密码三类,其中商用密码用于保护不属于国家秘密的信息,由市场主体依法自主使用。
在金融领域,中国人民银行早在 2013 年就发布了《关于做好商用密码管理工作的通知》,要求金融行业在新建和改造的信息系统中优先采用国密算法。随后,银联、各商业银行和支付机构逐步推进了国密改造。目前,银联卡芯片(IC 卡)、网银系统、手机银行和支付终端等均已广泛部署 SM2/SM3/SM4 算法。CFCA(中国金融认证中心,China Financial Certification Authority)作为金融行业的核心 CA 机构,负责签发基于 SM2 算法的数字证书,支持 SSL/TLS 协议中的国密密码套件。
在政务领域,国家电子政务外网和各级政府信息系统正在推进国密改造。政务云平台、电子公文系统、电子印章等应用场景均要求采用国密算法。特别是在电子政务证书体系中,SM2 证书已逐步取代 RSA 证书成为主流。
在技术实现层面,开源社区为国密算法的推广提供了重要支持。GmSSL 是国内最具影响力的国密算法开源库,提供了 SM2、SM3、SM4、SM9、ZUC 等算法的完整实现,支持 C/C++、Java、Python、Go 等多种语言绑定。Tongsuo(铜锁,原名 BabaSSL)是由蚂蚁集团主导开源的密码学库,基于 OpenSSL 分支开发,提供了对国密算法的原生支持,并已被多个大型互联网企业采用。此外,OpenSSL 自 1.1.1 版本开始也加入了 SM2、SM3、SM4 的支持,进一步降低了国密算法的使用门槛。
在 TLS 协议层面,国密 SSL(GMTLS)协议定义了基于国密算法的传输层安全规范,对应的密码套件包括 ECC_SM4_CBC_SM3、ECC_SM4_GCM_SM3 等。然而,国密 SSL 协议与国际标准 TLS 1.2/1.3 在握手流程和密码套件协商机制上存在差异,这给双模(同时支持国际标准和国密标准)部署带来了一定的技术挑战。目前,Nginx、Apache 和 Caddy 等主流 Web 服务器通过插件或补丁的方式支持国密 SSL。
硬件安全模块(HSM,Hardware Security Module)是国密算法在高安全场景中的重要载体。国内多家厂商生产符合 GM/T 0029—2014 标准的密码机和密码卡,提供 SM1(非公开算法,仅以芯片形式提供)、SM2、SM3、SM4、SM7(非公开算法)和 SM9 的硬件加速能力。这些 HSM 设备通常通过 SDF(密码设备应用接口)或 SKF(智能密码钥匙应用接口)标准接口与应用系统对接。
九、安全性分析与国际化
国密算法自公开以来,经历了国内外密码学界的广泛审查和分析。总体而言,各算法在其完整轮数下均未发现实际可行的攻击,安全性评价良好。
对于 SM4 分组密码,学术界进行了大量的差分分析(Differential Cryptanalysis)、线性分析(Linear Cryptanalysis)和不可能差分分析(Impossible Differential Cryptanalysis)研究。目前公开的最优攻击结果可以达到约 23 至 24 轮的简化版 SM4,而完整的 32 轮 SM4 留有充足的安全余量。在相关密钥攻击(Related-Key Attack)方面,SM4 的密钥扩展算法也展现了良好的抗攻击能力。
对于 SM3 杂凑算法,碰撞攻击(Collision Attack)和原像攻击(Preimage Attack)的研究表明,简化版 SM3(约 32 至 33 轮)的碰撞可以在低于生日攻击复杂度的情况下找到,但完整 64 轮 SM3 的安全性仍然牢固。SM3 的消息扩展函数的复杂设计为其提供了较好的抗攻击特性。
对于 SM2 椭圆曲线算法,其安全性主要取决于椭圆曲线离散对数问题的计算难度。sm2p256v1 曲线的参数选择遵循了国际通行的安全准则,曲线阶为大素数、余因子为 1、embedding degree 足够大。然而,与 NIST P-256 曲线类似,SM2 推荐曲线也面临着”参数来源透明性”的质疑——即曲线参数的选择过程是否充分公开和可验证。尽管如此,目前没有证据表明 SM2 曲线存在任何结构性弱点。
对于 SM9 标识密码,其安全性依赖于 BN 曲线上的双线性对相关假设。2016 年 Kim 和 Barbulescu 的研究表明,对于某些参数选择的 BN 曲线,其实际安全强度可能低于最初的估计。这引发了密码学界对 SM9 所用 BN 曲线安全强度的重新评估,但目前的共识是,SM9 推荐的参数集在实际应用中仍然提供了足够的安全保障,不过长远来看可能需要向更高安全强度的曲线(如 BLS 曲线)迁移。
在国际标准化方面,国密算法的纳入 ISO 标准是一个重要的里程碑,但这并不意味着其在国际市场上获得了广泛采用。实际部署面临以下挑战:
第一,互操作性问题。国际主流的密码库、协议实现和硬件设备对国密算法的支持仍然有限。虽然 OpenSSL 已加入基本支持,但许多商业软件产品和云服务平台尚未原生集成国密算法。这意味着在跨国业务场景中,国密算法的使用可能遇到兼容性障碍。
第二,性能优化生态。AES 在全球范围内拥有成熟的硬件加速生态(如 Intel AES-NI、ARM AES 指令),而 SM4 的硬件加速主要集中在国产处理器上。在国际通用处理器上,SM4 的软件实现性能通常低于 AES,这限制了其在性能敏感场景中的竞争力。不过,随着 ARM v8.4 架构引入了可选的 SM3 和 SM4 指令扩展,国际主流处理器对国密算法的硬件支持正在逐步改善。
第三,信任和透明度。国际密码学社区对国密算法的信任度与对 NIST 标准算法的信任度存在差距,这部分源于国密算法的设计准则和参数选择过程的公开透明程度不如 NIST 标准化流程。提高设计文档的透明度和鼓励更多国际学者参与密码分析,是增强国际信任的关键途径。
展望未来,国密算法体系面临着后量子密码学(Post-Quantum Cryptography)的挑战。当大规模量子计算机成为现实时,基于椭圆曲线离散对数问题的 SM2 和基于双线性对的 SM9 都将面临 Shor 算法的威胁,需要向后量子安全的替代方案迁移。中国密码学界已经在积极研究基于格(Lattice)、编码(Code)和多变量多项式(Multivariate)等后量子密码方案,为未来的算法升级储备技术方案。对称密码 SM4 和杂凑算法 SM3 受量子计算的影响相对较小——Grover 算法仅将安全强度减半,通过增加密钥长度或输出长度即可应对。
国密算法体系的建设是中国在网络安全领域追求自主可控的重要实践。从技术角度看,SM2、SM3、SM4、SM9 和 ZUC 在设计质量上达到了国际同类算法的水准,经受住了广泛的密码分析检验。从应用角度看,金融、政务等关键行业的国密改造正在稳步推进,开源生态和国际标准化工作也在不断完善。在全球密码学格局日益多元化的背景下,国密算法作为中国贡献给世界的密码学成果,正在走向更广阔的舞台。
密码学百科系列 · 第 47 篇