SM4密码

SM4

SM4是一个对称加密算法

  • 明文分组长度:128位 16字节 4字
  • 密钥长度:128位 16字节 4字
  • 迭代次数:32次

字:SM4 内部把 128 位分成 4 个 32 位字,记作:

$$
X_{0},X_{1},X_{2},X_{3}
$$

轮:SM4 要迭代 32 轮。每一轮用一个 32 位“轮密钥”

S 盒:一个固定的 8 位进、8 位出的替换表,用来制造非线性。SM4 的 S 盒有 256 项,教学时先理解“查表替换”即可。

循环左移:把 32 位二进制整体左移,移出去的高位补到低位。记作 B<<<n,用于在比特层面进一步扩散复杂度

概览

正如所有的对称加密一样,加密和解密用的是同一个密钥和密文。

可以记住以下流程:

128 位主密钥 → 密钥扩展 → 32 个轮密钥
128 位明文 → 32 轮加密 → 128 位密文
解密 = 同样的 32 轮,但轮密钥倒着用

全流程大概是:

1
2
3
4
5
6
初始: X0  X1  X2  X3
第0轮: X1 X2 X3 X4
第1轮: X2 X3 X4 X5
...
第31轮:X32 X33 X34 X35
密文: X35 X34 X33 X32 ← 注意最后要反序

密码学中的零件

异或⊕

异或凭借自逆的特点,被广泛运用在加解密中。

$$
a \oplus b \oplus b = a
$$

那么A就是明文,经过密钥处理两次后就能够还原回明文。

S盒

凯撒密码是一种单表替换密码,通过将明文中的每个字母沿字母表固定位移若干位来加密消息。 位移量为 3 时,A 变为 D,B 变为 E,Z 循环回绕变为 C。

实际上线性是非常危险的,因为一旦攻击者摸清了位移量,加密就不再有意义,所以采取一次非线性措施是非常重要的。

把 32 位字拆成 4 个字节,每个字节查一张固定的 8 进 8 出表,输入一个字节,输出一个字,而这张表就是S盒

循环左移异或

32 位循环左移记作 B⋘n:左移 n 位,移出去的位补到低位。

相当于将密文放到一个环中,朝着某个方向转动几位,随后敲定。

这能够将之前某一段的变化扩大到整个密文中,这种操作叫做扩散

轮函数

一轮的变换函数为:

$$
T \left( x \right)=L \left( S \left( x \right) \right)
$$

其中S(x)对32位字的4个字节做S盒替换

L为之前提到的循环左移异或

所以 T 的流程是:

32 位输入 → 4 字节 S 盒替换 → 五个循环移位版本异或 → 32 位输出

轮加密

$$
\text{设轮密钥为} rk_{0},rk_{1},\ldots,rk_{31}, \text{明文四字为} X_{0},X_{1},X_{2},X_{3}, \text{对} i=0 \text{到} 31\colon
$$

$$
X_{i+4}=X_{i}\oplus T\big(X_{i+1}\oplus X_{i+2}\oplus X_{i+3}\oplus rk_{i} \big)
$$

每一轮都做四件事

  • 取出后三个字

  • 将后三个字和轮密钥异或

  • 经过轮函数T

  • 与最旧的字异或得到新字X(i+4)

    经过32轮后再加上倒反序,就形成了

    $$
    ( Y_{0},Y_{1},Y_{2},Y_{3} ) = ( X_{35},X_{34},X_{33},X_{32} )
    $$

密钥扩展

上一个条目提到,需要32次加密,那就需要32个密钥,但是主密钥只有一个128位的,这就需要密钥扩展

主密钥 128 位也拆成四个 32 位字:

$$
MK_{0},MK_{1},MK_{2},MK_{3}
$$

与固定向量FK异或

$$
K_{0}=MK_{0}\oplus FK_{0},\quad\ldots,\quad K_{3}=MK_{3}\oplus FK_{3}
$$

然后将K值用和轮加密相近的方式拿到密钥

$$
rk_{i}=K_{i+4}=K_{i}\oplus T^{\prime}(K_{i+1}\oplus K_{i+2}\oplus K_{i+3} \oplus CK_{i})
$$

CK是一个32轮常向量,用公式生成

$$
ck_{i,j}=(4i+j)\times7\ \mathrm{mod}\ 256
$$

解密

注,解密结构和加密完全一样。

$$
Y_{i+4}=Y_i\oplus T(Y_{i+1}\oplus Y_{i+2}\oplus Y_{i+3}\oplus rk_{31-i})
$$

最后输出

$$
(Y_{35},Y_{34},Y_{33},Y_{32})
$$

唯一区别是轮密钥逆序使用。原因很直观:加密每轮用异或把新字“叠”进去,异或可逆;把轮密钥倒过来,就能一层层还原。