SM4介绍
SM4采用分组加密的方式,明文与密文长度均为128bit(16字节),秘钥也为128bit(16字节),采用32轮迭代,每一轮都需要用到新的轮密钥,即加密算法是对明文的32次加密和对轮密钥的生成。
加密算法介绍
轮函数加密
SM4的分组长度为4字,因此,每一段长度都为4字节,我们用X0,X1,X2,X3表示,经过加密后,得到的输出是4字的密文,我们用Y0,Y1,Y2,Y3表示,这个加密过程分为两步,由32次轮迭代和1次反序变换组成。如图所示是加密流程图:

我们先对加密过程进行系统化介绍:
- 将输入的128bit拆分成4个4字节的变量X0,X1,X2,X3
- 进行32次循环,i从0增加到31
- 将Xi单独取出用于最后一步,Xi+1 Xi+2 Xi+3 与传入的第一轮轮密钥rki进行异或操作作为s盒输入,即sbox-input= x i + 1 ⊕ x i + 2 ⊕ x i + 3 ⊕ r k i (32bit/4字节)
- 将sbox-input进行拆分,分为4个单字节(8bit)的变量与s盒进行置换,置换后再合并成32bit数据
- 我们将输出出来的数据分别进行左移位数为(2、10、0、18、24)
- 我们将左移后的数据分别进行标注为y2,y10,y0,y18,y24,此时我们将左移的5个数据与Xi异或得到Xi+4
- 这里提到的循环左移是指这个公式,并非补0操作ROL(x, n) = ((x << n) | (x >> (32 - n))) & 0xffffffff
- L(B)=B⊕(B<<2)⊕(B<<10)⊕(B<<18)⊕(B<<24)(官方公式)
- xi+4=y0⊕y2⊕y10⊕y18⊕y24⊕xi
- 循环一共执行32次,最终将x35,x34,x33,x32 合并成一个 128bit 的数据 ,作为最后的输出结果
- 最后得到的密文是按照X35 || X34 || X33 || X32的顺序输出,即X35在高位,X32在低位
总结单次加密过程:
1、后3位与秘钥进行异或
2、异或后结果单字节进行s盒置换
3、置换后结果左移(2、10、0、18、24)后与Xi异或得到Xi+4
轮密钥生成

轮密钥生成与函数加密过程大同小异
- 先对128位的key进行拆分成4个4字节密钥记为MK0、MK1、MK2、MK3
- 拆分采用高位 ---------------------------------> 低位 MK0(高位) MK1 MK2 MK3(低位),构造数组的时候是MK0一般放在0-3,方便在后续进行运算
- 将拆分出的秘钥分别与固定参数FK1234进行异或得到K1234,
即 k0=K0⊕FK0,k1=K1⊕FK1,k2=K2⊕FK2,k3=K3⊕FK3,后续统一用i表示 - 将Ki取出用于最后一步,其他的K与固定参数CKi进行异或得到sbox-input
sbox_input=ki+1⊕ki+2⊕ki+3⊕cki - 之后将4字节输入分成4个单字节输入然后与S盒进行置换,置换后进行拼接得到sbox-output
- 将sbox-output分别左移(13、0、23)后得到y0、y13、y23,与Ki进行异或得到Ki+4(第i位轮密钥)
- rki=ki+4=sbox_output⊕y13⊕y23⊕ki
- 执行完 32 轮后,便可获得 32 个用于加解密的 rki
总结轮密钥生成过程:
1、先将MK与FK分别异或得到Ki
2、将Ki+123与固定参数CKi异或得到s盒输入,并进行进行s盒置换
3、将输出结果左移(13、0、23)后与Ki进行异或得到rki轮密钥
解密
解密过程和加密过程采用相同的方式,唯一不同的是,解密时使用的轮密钥是先用rk31,最后再用rk0
注意点:
在最近做SM4的题目时发现SM4的读取方式是一个需要十分注意的点,正常的X86架构下,数据读取都是小端读取,而SM4在加密过程中数据读取是按照大端读取的,最终的结果也是大端拼接,这么说可能有些生硬,我们直接看例子:
假设条件:明文 = 1234567890ABCDEF
密钥 = AABBCCDDEEFFGGHH
按 SM4 的大端分组,变成:
X0 = 0x31323334
X1 = 0x35363738
X2 = 0x39304142
X3 = 0x43444546
但是我们X86读取的方式是X0 = 0x34333231刚好相反,所以加入一端修正进行大端改写

秘钥跟密文同理
最终我们得到密文为:
Y0 = 0xCA752DEB
Y1 = 0xCFEB00CA
Y2 = 0xB4437301
Y3 = 0x0AAE0D1D
输出的时候密文用CA 75 2D EB CF EB 00 CA B4 43 73 01 0A AE 0D 1D拼接出去
所以还会有一段对于密文输出的修正段,此时我们对于SM4大小端的理解就彻底搞懂了

如果要解密,我们拿到的密文,依旧举例看怎么去输入秘钥密文,可以看到秘钥是按小端存储的,此时如果没有对秘钥进行的操作则我们的秘钥直接抄进去即可,最好按照汇编层去抄写,每组4字节,但如果秘钥也进行了前面明文所做的交换操作,则也需要进行倒序输入


密文层面我们前面知道密文做了大小端互换,那么这里我们每四字节也要进行大小端交换,所以输入密文应为b5 c8 ac cf ea 52 4d e3 70 2b 1f 08 3d 47 61 6b


还有种方法,SM4如果没有魔改,那么我们输入进SM4的数据都应该是大端读取之后的,可以看到我们对明文读取和密文读取都做了大小端转换,秘钥没有做大小端转换,那么可以知道内存中我们的秘钥本身就是大端存储的,所以直接输入进秘钥段就可以了,密文做一下大小端交换输入进去也就可以得到明文了
Comments NOTHING