SM3算法分析(国密学习 2/5)
注:本blog参考《SM3密码杂凑算法》(GB/T 32905-2016)与python开源库gmssl中的sm3算法实现
国家标准全文公开系统:https://openstd.samr.gov.cn
算法基本信息
SM3是一种杂凑算法(就是一种哈希算法,类似SHA-256、MD5等等)
输入长度:小于$2^{64}$(理论)
输出长度:256bit
sm3对明文的填充是比较有特点的
填充
长度l的明文m,填充如下:
1.先加一比特1
2.在1后加k个0,使明文长度为$(l + 1 + k) = 448 \mod 512$
3.再加上一个64位比特串,这个比特串就是长度l的二进制表示(这里就能看出为什么sm3的理论输入长度要小于$2^{64}$)
填充后的明文长度是512的倍数,后经迭代压缩,输出256bit的杂凑值
下面是gmssl库中的实现,注意一下,py中没办法一比特一比特填充,只能填充字节($1byte = 8bit$),所以实现起来会麻烦一点
1 | |
定义函数
指的是在下面的迭代压缩中会出现的函数(在GB/T标准中定义好的)
有俩个布尔函数和俩个置换函数
$\land$ : 32bit与运算
$\lor$:32bit或运算
$\oplus$:32bit异或运算
$\lnot$:32bit非运算
布尔函数
(1)
$0 \leqslant j \leqslant 15$时:$FF_j(X,Y,Z) = X \oplus Y \oplus Z$
$16 \leqslant j \leqslant 63$时:$FF_j(X,Y,Z) = (X \land Y) \lor (X \land Z) \lor (Y \land Z)$
(2)
$0 \leqslant j \leqslant 15$时:$GG_j(X,Y,Z) = X \oplus Y \oplus Z$
$16 \leqslant j \leqslant 63$时:$GG_j(X,Y,Z) = (X \land Y) \lor (\lnot X \land Z)$
其中 $X$,$Y$,$Z$ 为字
置换函数
(1)$$P_0(X) = X \oplus (X <<<9) \oplus (X<<<17)
$$
(2)$$P_1(X) = X \oplus (X<<<15) \oplus(X<<<23)
$$
其中X为字
代码实现:
没什么特别的地方
1 | |
压缩函数
注:在sm3中,要进行压缩函数的运算前是要先对消息进行扩展的,这里先说压缩函数,消息扩展在后面。
定义:<-是左向赋值W为字(32比特串)A、B、C、D、E、F、G、H为字寄存器SS1、SS2、TT1、TT2为中间变量
$V^0$ 为256bit初始值IV,$V^n$为迭代压缩结果,$B^i$为明文分组
$T_i$ 是算法定义好的值(随i值的变化而变化)
压缩函数:$V^{i+1}=CF(V^i,B^i)$
过程:
将$V^i$存入ABCDEFGH后进入循环
可能看着有点乱,可以看代码实现来辅助理解
1 | |
迭代压缩
第一步:消息填充
对消息填充后按512比特分组:$m’=B^0B^1…B^{n-1}$,其中$n = (l+k+65)/512$
1 | |
第二步:消息扩展
将 $B^i$ 扩展成132个消息字 $W_0,W_1,…,W_{67}$,$W’_0, W’1,…, W’{63}$ ,后会用在压缩函数里。
先将消息分组 $B^i$ 划分成16个字$W_0,W_1,…,W_{15}$,后经过下面俩个循环扩展。
FOR j = 16 TO 67
$W_i$ <- $P_1(W_{i-16}\oplus W_{i-9} \oplus (W_{i-3} <<< 15))\oplus (W_{i-13}<<< 7)\oplus W_{i-6}$
ENDFOR
FOR j = 0 TO 63
$W’i$ = $W_i\oplus W{i+4}$
ENDFOR
成功将消息扩展成132个消息字
1 | |
第三步:迭代
对$m’$进行迭代:
FOR i = 0 TO n-1
$V^{i+1} = CF(V^i,B^i)$
ENDFOR
$V^0$ 为256bit初始值IV,$V^n$为迭代压缩结果
迭代完成输出256比特杂凑值:$y = ABCDEFGH$ <- $V^n$
1 | |
注:本文的gmssl代码演示,因展示顺序可能导致有函数被拆成几部分,详细请看gmssl库源码
密钥派生函数
gmssl中还实现用sm3来实现的密钥派生函数
1 | |
总源码
1 | |