SM3 密码杂凑算法
SHA-256 是常用的哈希算法,输入长度小于 2^64 bit
的消息,输出为 256 bit
的杂凑值,分组大小为 512 bit
,字长定义为 32 bit
;
SM3 算法在 SHA-256 的基础上进行改良,输入长度小于 2^64 bit
的消息,输出为 256 bit
的杂凑值。分组大小为 512 bit
,字长定义为 32bit
;
SM3 和 SHA-256 对比:
SM3 算法步骤
SM3 算法主要分为以下几个部分:
- 消息填充
- 消息扩展
- 迭代压缩
- 生成杂凑值
输出为 256 bit 杂凑值,即 32 byte
设消息 m 的长度为 l
,索引从 0 开始编号
常量与函数
符号约定
ABCDEFGH:8 个字寄存器(串联)
B(i):第 i 个消息分组
CF:压缩函数
FFj:布尔函数,随 j 的变化取不同的表达式
GGj:布尔函数,随 j 的变化取不同的表达式
IV:初始值,用于确定压缩函数寄存器的初态
P0:压缩函数中的置换函数
P1:消息扩展中的置换函数
Tj:常量,随 j 的变化取不同的值
m:消息
m′:填充后的消息
∧:32 比特与运算
∨:32 比特或运算
⊕:32 比特异或运算
¬:32 比特非运算
+:mod232 算数加运算
⋘k:循环左移 k 比特运算
←:左向赋值运算符
初始值 IV
IV=7380166f4914b2b9172442d7da8a0600a96f30bc163138aae38dee4db0fb0e4e
常量
Tj={79cc45197a879d8a0≤j≤1516≤j≤63
布尔函数
FFj(X,Y,Z)={X⊕Y⊕Z(X∧Y)∨(X∧Z)∨(Y∧Z)0≤j≤1516≤j≤63
GGj(X,Y,Z)={X⊕Y⊕Z(X∧Y)∨(¬X∧Z)0≤j≤1516≤j≤63
X,Y,Z 为字。
置换函数
P0(X)=X⊕(X⋘9)⊕(X⋘17)P1(X)=X⊕(X⋘15)⊕(X⋘23)
X 为字。
消息填充
首先在消息 m 的末尾添加一个比特 1
;
然后再添加 k 个比特 0
;
k 满足 l + 1 + k ≡ 448(mod 512)
,字节表示为 (448(mod 512))/8 = 56(mod 64)
最后添加长度 l
的二进制比特表示,以大端序存放;
数据的高位字节存储在地址的低端
填充后的消息 m’ 的长度为 512 bit 的倍数。
消息扩展
将填充后的消息 m’ 按照 512 bit 分组
m′=B(0)B(1)...B(n−1)
对消息分组 B(i) 进行扩展,生成 132 个字:
W0,W1,...,W67,W0′,W1′,...,W63′
具体过程如下:
-
首先将消息分组 B(i) 划分为 16 个字 W0,W1,...,W15 ,记为 Wj
-
递推生成剩余的 Wj ,共计 68 个字
FORj=16TO67Wj←P1(Wj−16⊕Wj−9⊕(Wj−3⋘15))⊕(Wj−13⋘7)⊕Wj−6ENDFOR
- 递推生成 Wj′ ,共计 64 个字
FORj=0TO63Wj′=Wj⊕Wj+4ENDFOR
迭代压缩
迭代过程
FORi=0TOn−1V(i+1)=CF(V(i),B(i))ENDFOR
- CF 是压缩函数
- V(0) 为 256 比特初始值 IV
- B(i) 为填充后的消息分组
- 迭代压缩的结果为 V(n) ,即最终的杂凑值
压缩函数
- A, B, C, D, E, F, G, H 为字寄存器
- SS1, SS2, TT1, TT2 为中间变量
- Vi+1=CF(V(i),B(i)),0≤i≤n−1
压缩函数过程如下:
ABCDEFGH←V(i)FORj=0TO63SS1←((A⋘12)+E+(Tj⋘j))⋘7SS2←SS1⊕((A⋘12)TT1←FFj(A,B,C)+D+SS2+Wj′TT2←GGj(E,F,G)+H+SS1+WjD←CC←B⋘9B←AA←TT1H←GG←F⋘19F←EE←P0(TT2)ENDFORV(i+1)←ABCDEFGH⊕V(i)
生成杂凑值
ABCDEFGH←V(n)
输出 256 bit 杂凑值 y = ABCDEFGH
总结
SM3 算法流程简洁明了,可以直接按步骤实现。已有支持国密SM2/SM3/SM4/SM9/ZUC/SSL的密码工具箱 The GmSSL Project ,提供不同语言的 API 接口;学习 Golang 的过程中找到开源实现 基于Go语言的国密SM2/SM3/SM4加密算法库 ,研读了一段时间,现在才回头梳理总结(老懒熊了xd