SM系列算法
SM 系列算法
SM2
SM2 是椭圆曲线公钥密码算法,是基于 ECC 的非对称加密,又称作 SM2-ECDSA,主要应用于数字签名。
国密算法标准中推荐使用的默认值为
1 | p = 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF |
其中 \(p\) 为有限域规模,\((a,b)\) 为椭圆曲线参数,\(n\) 为这个椭圆曲线的阶数,\(G(G_x,G_y)\) 为基点。
国密标准规范来源:https://www.sca.gov.cn/sca/xxgk/2010-12/17/content_1002386.shtml
SM2公钥加密算法
符号
\(klen\) 指代消息长度,\(M\) 指代消息,标准推荐 \(\mathrm{KDF}\) 使用 SM3 算法,标准推荐 \(\mathrm{Hash}\) 使用 SM3 算法(输出必须为 32 字节),\(||\) 表示比特串拼接。
公钥与密钥
- 私钥 \(d\) 是 32 byte(256 bit)的随机数
- 公钥 \(P=d\cdot G\)
加密
- 产生随机数 \(k\in[1,n-1]\)
- 计算椭圆曲线点 \(C_1(x_1,y_1)=k\cdot G\)
- 计算椭圆曲线点 \(k\cdot P=(x_2,y_2)\)
- 计算 \(t=\mathrm{KDF}(x_2||y_2,klen)\),如果 \(t\) 全为 0 比特串,则回到步骤一重新选取 \(k\)
- 计算椭圆曲线点 \(C_2=M\oplus t\)
- 计算椭圆曲线点 \(C_3=\mathrm{Hash}(x_2||M||y_2)\)
- 输出密文 \(C=C_1||C_2||C_3\)
解密
- 从密文中获取 \(C_1\),验证 \(C_1\) 是否满足曲线方程,不满足则报错推出
- 计算椭圆曲线点 \(dC_1=(x_2,y_2)\)
- 计算 \(t=\mathrm{KDF}(x_2||y_2,klen)\),如果 \(t\) 全为 0 比特串,则报错退出
- 计算 \(M'=C_2\oplus t\)
- 计算 \(u=\mathrm{Hash}(x_2||M'||y_2)\),验证 \(u=C_3\),不正确则报错退出
- 输出明文 \(M'\)
代码
基于 Sagemath 的椭圆曲线的运算代码如下
1 | from . import sm3 |
SM2数字签名算法
符号
\(M\) 指代消息,标准推荐 \(\mathrm{KDF}\) 使用 SM3 算法,标准推荐 \(\mathrm{Hash}\) 使用 SM3 算法(输出必须为 32 字节)。
公钥与密钥
- 私钥 \(d\)
- 公钥 \(P=d\cdot G\)
用户信息
签名者具有可辨别标识 \(ID\),记 \(ENTL\) 是可辩别表示的比特大小(占两字节),使用杂凑算法生成 32 字节的杂凑值 \(Z\)。标准推荐使用 SM3 算法作为杂凑算法。 \[ Z=\mathrm{Hash}(ENTL||ID||a||b||G_x||G_y||P_{x}||P_{y}) \]
签名
- 计算 \(e=\mathrm{Hash}(Z||M)\)
- 产生随机数 \(k\in[1,n-1]\)
- 计算椭圆曲线点 \((x_1,y_1)=k\cdot G\)
- 计算 \(r=e+x_1\pmod{n}\),若 \(r=0\) 或 \(r+k=n\) 则重新选取随机数
- 计算 \(s=(1+d)^{-1}\cdot(k-r\cdot d)\pmod{n}\),若 \(s=0\) 则重新选取随机数
- 输出消息 \(M\) 的签名 \((r,s)\)
验证
接收到消息 \(M'\) 和数字签名 \((r',s')\)。
- 检验 \(r',s'\in[1,n-1]\),如果错误则验证失败
- 计算 \(e'=\mathrm{Hash}(Z||M')\)
- 计算 \(t=r'+s'\pmod{n}\),如果 \(t=0\) 则验证失败
- 计算椭圆曲线点 \((x_1',y_1')=s'G+tP\)
- 计算 \(R=e'+x_1'\pmod{n}\),如果 \(R=r'\) 则验证通过;否则验证失败。
代码
1 | def sign(self, e: bytes, k0: int = None): |
SM3
SM3 密码杂凑算法,即哈希算法。
SM3 适用于商用密码应用中的数字签名和验证,是在 SHA-256 基础上改进实现的一种算法,其安全性和 SHA-256 相当。SM3 和 MD5 的迭代过程类似,也采用 Merkle-Damgard 结构。消息分组长度为 512 位,摘要值长度为 256 位。
整个算法的执行过程可以概括成四个步骤:消息填充、消息扩展、迭代压缩、输出结果。
国密标准规范来源:https://www.sca.gov.cn/sca/xxgk/2010-12/17/content_1002389.shtml
常数与函数
初始值
1 | IV = [0x7380166f, 0x4914b2b9, 0x172442d7, 0xda8a0600, 0xa96f30bc, 0x163138aa, 0xe38dee4d, 0xb0fb0e4e] |
常量
1 | T = [0x79cc4519] * 16 + [0x7a879d8a] * 48 |
布尔函数
1 | def FF(X: int, Y: int, Z: int): |
置换函数
1 | ROTL = lambda X, P: ((X << P) | (X >> (32 - P))) & 0xFFFFFFFF |
算法描述
消息填充
假设消息 \(m\) 的长度为 \(l\) 比特,将比特 1 添加到消息末尾,后填充比特 0 直到消息长度为 \(l' =448\pmod{512}\),最后填充比特长度 \(l\) 的 64 位比特串到末尾。
1 | def padding(msg: bytes): |
消息扩展
将 512 位的消息分组扩展为 132 字节的 \(W_0,W_1,\cdots,W_{67},W_0',\cdots,W_{63}'\),用于压缩函数 \(CF\)。
1 | def expand(Bi: bytes): |
消息压缩
将消息分组 \(B_i\) 扩展后压缩为 16 字节的杂凑值
1 | def CF(Vi: bytes, Bi: bytes): |
杂凑迭代
对填充过的消息分块后迭代压缩,最终杂凑值为 \(V_{i+1}\)。
1 | def hash(msg: bytes): |
基于 SM3 的 KDF
输入基密钥字节串 \(Z\) 和派生密钥字节长度 \(klen\),输出派生密钥。
- 初始化 4 字节 32 比特计数器
ct=0x00000001
- 从
1
到klen
,计算 \(Ha=Ha||\mathrm{Hash}(Z||ct)\)
1 | def KDF(Z: bytes, klen: int): |
SM4
SM4 分组密码算法,也是无线局域网标准的分组数据算法,是一种对称加密流密码,密钥长度和分组长度均为 128 比特 16 字节。
加密算法与密钥扩展算法都采用 32 轮非线性迭代结构,是典型的 Feistel 密码结构。
密钥及密钥参量
加密密钥长度 128 比特 16 字节,每组 32 比特 4
字节(标准 int32
),共 4 组,表示为 \(MK=(MK_0,MK_1,MK_2,MK_3)\)。
轮密钥每组 32 比特 4 字节,共 32 组,表示为 \(rk=(rk_0,rk_1,\cdots,rk_{31})\),轮密钥用于加密密钥生成。
\(FK=(FK_0,FK_1,FK_2,FK_3)\),每组 32 比特 4 字节,共 4 组,为系统参数;
\(CK=(CK_0,CK_1,\cdots,CK_{31})\),每组 32 比特 4 字节,共 32 组,为固定参数,二者都用于密钥扩展算法。
轮函数
轮函数结构
设输入为 128 比特 16 字节,每组 32 比特 4 字节,即 \((X_0,X_1,X_2,X_3)\),轮密钥为 \(rk\)(32 组轮密钥中的一个),那么轮函数运算为 \[ F(X_0,X_1,X_2,X_3,rk)=X_0\oplus T(X_1\oplus X_2\oplus X_3\oplus rk) \]
合成置换
\(T\) 变换为可逆变换,由非线性变换 \(\tau\) 和线性变换 \(L\) 复合而成,即 \(T(X)=L(\tau(X))\)。
非线性变换 \(\tau\)
\(\tau\) 由四个并行的 S 盒构成。 \[ \tau(a_0,a_1,a_2,a_3)=(\mathrm{Sbox}(a_0),\mathrm{Sbox}(a_1),\mathrm{Sbox}(a_2),\mathrm{Sbox}(a_3)) \] 其中 \((a_0,a_1,a_2,a_3)\) 是每组 8 比特 1 字节的输入,且 \(\mathrm{Sbox}\) 的数据如下
1 | Sbox = [ |
线性变换 \(L\)
非线性变换 \(\tau\) 的输出是线性变换 \(L\) 的输入。 \[ L(X)=X\oplus (X<<<2)\oplus(X<<<10)\oplus (X<<<18)\oplus(X<<<24) \] 其中 \(X\) 是 32 比特 4 字节的输入,\(<<<\) 代表循环左移。
加密
设明文输入为 \((X_0,X_1,X_2,X_3)\),每组 32 比特 4 字节;
密文输出为 \((Y_0,Y_1,Y_2,Y_3)\),每组 32 比特 4 字节;
轮密钥为 \(rk_i,i=0,1,\cdots,31\)。
运算过程如下:
- 32 次迭代运算:\(X_{i+4}=F(X_i,X_{i+1},X_{i+2},X_{i+3},rk_i),i=0,1,\cdots,31\)
- 反序变换:\((Y_0,Y_1,Y_2,Y_3)=(X_{35},X_{34},X_{33},X_{32})\)
解密
将轮密钥反序即可,即 \(rk'=(rk_{31},rk_{30},\cdots,rk_0)\)。
密钥扩展
轮密钥生成过程为
- 计算 \((K_0,K_1,K_2,K_3)=(MK_0\oplus FK_0,MK_1\oplus FK_1,MK_2\oplus FK_2,MK_3\oplus FK_3)\)
- 轮密钥 \(rk_i=K_{i+4}=K_i\oplus T'(K_{i+1}\oplus K_{i+2}\oplus K_{i+3}\oplus CK_i),i=0,1,\cdots,31\)
其中,\(T'\) 是将线性变换 \(L\) 变为 \(L'\): \[ L'(X)=X\oplus (X<<<13)\oplus (X<<<23) \] 系统参数 \(FK\) 为
1 | FK = [0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc] |
固定参数 \(CK_i\) 为
1 | CK = [ |
SM9
SM9 是标识密码算法(Identity-base cryptogrphy),又称作身份基密码.
标准规范来源:http://www.gmbz.org.cn/main/bzlb.html
数字签名算法
标准推荐参数
使用 256 位的 BN 曲线,椭圆曲线方程为 \[ y^2=x^3+b \] 曲线参数为:
参数 \(t\):0x600000000058F98A
迹 \(tr(t)=6t^2+1\):0xD8000000019062ED0000B98B0CB27659
基域特征 \(q(t)=36t^4+36t^3+24t^3+6t+1\):0xB640000002A3A6F1D603AB4FF58EC74521F2934B1A7AEEDBE56F9B27E351457D
方程参数 \(b\):0x05
群的阶 \(N(t)=36t^4+36t^3+18t^2+6t+1\):0xB640000002A3A6F1D603AB4FF58EC74449F2934B18EA8BEEE56EE19CD69ECF25
余因子 \(cf=1\)
嵌入次数 \(k=12\)
扭曲线的参数 \(\beta=\sqrt{-2}\)
\(k\) 的因子 \(d_1=1,d_2=2\)
曲线识别符 \(cid\):0x12
群 \(G_1\) 的生成元 \(P_1\):P1=(0x93DE051D62BF718FF5ED0704487D01D6E1E4086909DC3280E8C4E4817C66DDDD, 0x21FE8DDA4F21E607631065125C395BBC1C1C00CBFA6024350C464CD70A3EA616)
群 \(G_2\) 的生成元 \(P_2\):
P2x=(0x85AEF3D078640C98597B6027B441A01FF1DD2C190F5E93C454806C11D8806141, 0x3722755292130B08D2AAB97FD34EC120EE265948D19C17ABF9B7213BAF82D65B)
P2y=(0x17509B092E845C1266BA0D262CBEE6ED0736A96FA347C8BD856DC76B84EBEB96, 0xA7CF28D519BE3DA65F3170153D278FF247EFBA98A71A08116215BBA5C999A7C7)
双线性对的识别符 \(eid\):0x04
扩域相关:
二次扩张的约化多项式为 \(x^2+2\)
四次扩张的约化多项式为 \(x^2-\sqrt{-2}\)
十二次扩张的约化多项式为 \(x^3-(-2)^{1/6}\)
基于 Sagemath 的参数如下
1 | t = 0x600000000058F98A |
符号
加密主密钥
加密主密钥(encryption master key)处于标识密码密钥分层结构最顶层的密钥,内容为加密主私钥和加密主公钥,其中加密主公钥是公开的,而加密主私钥由密码生成中心(KGC)秘密保存。KGC 使用加密主私钥和用户的标识(ID)生成用户的加密私钥。
标识
标识(ID)由实体无法否认的信息组成,如电子邮箱、身份证号、电话号码等。
曲线识别符 cid
用于区分不同椭圆曲线的标识。
0x10
表示 \(F_p\) 上的常曲线,\(p\) 是素数,\(p>2^{191}\)0x11
表示 \(F_p\) 上的超奇异曲线0x12
表示 \(F_p\) 上的常曲线及其扭曲线
标准使用的是 BN 曲线(\(a=0,b=5\)),cid=0x12
。
双线性对识别符 eid
0x01
表示 Tate 对0x02
表示 Weil 对0x03
表示 Ate 对0x04
表示 R-ate 对
系统签名主密钥和用户签名密钥的产生
KGC 产生随机数 \(ks\in[1,N-1]\) 作为签名主私钥,计算群 \(G_2\) 中的元素 \(P_{pub-s}=ks\cdot P_2\) 作为签名主公钥,则签名主密钥对为 \((ks,P_{pub-s})\)。
KGC 秘密保存 \(ks\),公开 \(P_{pub-s}\)。
KGC 选择并公开用一个字节表示签名私钥生成函数识别符 \(hid\)。
用户 A 的标识为 \(ID\),KGC 在有限域 \(F_N\) 上计算 \(t_1=H_1(ID||hid,N)+ks\),若 \(t_1=0\) 则重新计算签名主私钥、更新签名主密钥对;
随后计算 \(t_2=ks\cdot t^{-1}\pmod{N}\);
最后计算签名私钥 \(ds=t_2\cdot P_1\)。
辅助函数
密码杂凑函数
标准推荐使用 SM3 密码杂凑算法,输出 256 比特 32 字节。