0x00 概述
线性分析法、差分分析法作为SPN(Substitution Permutation Network)的常用解法,一直让密码学家痴迷。最近也因为0ctf的一些密码学题目,对线性分析法有了一定的了解,并想写篇博客将具体内容详细展示!
0x01 SPN网络介绍
首先我们来看看这个spn网络
每轮都包含3个步骤:substitution(代替)、permutation(置换)、key-mixing(轮密钥加)
1.1 substitution
输入4比特,输出4比特。这是一个双射,让集合$0-(2^4-1)$ 与其本身一一对应。
input | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
output | E | 4 | D | 1 | 2 | F | B | 8 | 3 | A | 6 | C | 5 | 9 | 0 | 7 |
它起到混淆的作用!
1.2 permutation
输入16比特的数,对其各个比特进行置换。
input | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
output | 1 | 5 | 9 | 13 | 2 | 6 | 10 | 14 | 3 | 7 | 11 | 15 | 4 | 8 | 12 | 16 |
其实可以看出,这是对上面4组S盒输出的16个比特进行简单的置换。
这是一个可逆的操作!
1.3 轮密钥加
提到轮密钥加,我们不得不提轮密钥的产生。一般的轮密钥产生都是利用一种具有雪崩效应的算法,根据初始密钥,生成每一轮的密钥!比较少见的是给出一段较长的密钥,直接切割出每轮的密钥。
最好不要出现以下几种密钥:
- 简单密钥。对于使用的0000....00或者0101..0101类型的密钥,最好不要使用
- 可通过某一轮的密钥反解出所有密钥。(前提是你知道某一轮的密钥。。。)
- 轮密钥不要相关。如果轮密钥只是简单的进行了固定的循环左移或右移变换,那么所有的密钥将会有相同数量的1,以及相同距离的1。这都是很危险的。Related-key attack
1.4 解密
其实,由于上面的所有变换都是可逆的运算,所以最终都能根据轮密码求解出原文。
0x02 线性分析法简述
线性分析法的基本想法是生成一系列大概可用的线性表达式,如:
$X_{i_1}\oplus X_{i_2} ... X_{i_u} \oplus Y_{j_1} \oplus Y_{j_2} ... Y_{j_v}=0$
其中 $X_i$ 表示第i个比特的输入,$Y_j$ 表示第j个比特的输出
其实当我们比较随机的选取这u+v个比特,最终上述表达式成功的概率大概是1/2。
线性分析法基本原理:如果线性表达式成立的概率距离1/2越远,那么越容易使用线性分析法。若线性表达式发生概率为$p_L$, 那么$|p_L-1/2|$越大越好。
能够使用线性分析法的环境:线性分析可行一般取决于S盒设计,如果S盒导致出现多个线性表达式成立的概率距离1/2很远,那么最终分析结果将会越好;其次就是密钥长度不要太长,轮次不能太多,否则分析难度将会急剧增加。
2.1 Piling-Up Principle(叠加原理)
$$
\begin{equation}
P_r(X_1=i)=\left [
\begin{array}{lr}
p_1, i=0 \newline
1-p_1, i=1 \newline
\end{array}
\right]\
\end{equation}
$$
而
$$
P_r(X_2=i)=\left [
\begin{array} {lr}
p_2, i=0 \newline
1-p_2, i=1 \newline
\end{array}
\right]
$$
于是有:
$$
P_r(X_1 \oplus X_2) = P_r(X_1=X_2)=p_1 p_2 + (1-p_1)(1-p_2)
$$
令 $p_1=1/2+\epsilon_1$, $p_2=1/2+\epsilon_2$
则有 $P_r(X_1 \oplus X_2 = 0)=1/2+2\epsilon_1 \epsilon_2$
我们可以简写 $\epsilon_{1,2} = 2\epsilon_1 \epsilon_2$
根据Piling-Up Lemma (Matsui) ,我们可以快速得到:
$P_r(X_1 \oplus ... \oplus X_n = 0) = 1/2 + 2^{n-1} \prod_{i=1} ^n \epsilon_i$
如果其中某一个$p_i=1/2$, 那么最终的 $P_r(X_1 \oplus ... \oplus X_n = 0) = 1/2$
假设 $X_1 \oplus X_2$ 与 $X_2 \oplus X_3$ 是相互独立的,那么我么有:
$P_r(X_1 \oplus X_3 = 0) = 1/2 +2\epsilon_{1,2} \epsilon_{2,3}$
所以在这种情况下有 $\epsilon_{1,3} = 2\epsilon_{1,2} \epsilon_{2,3}$
2.2 分析S盒
假设S盒输入四位,输出四位,如下图所示:
假设现在使用的查看的是$X_2 \oplus X_3 \oplus =Y_1 \oplus Y_3 \oplus Y_4$
我们首先输入16个可能的输入作为X,然后检查对应的可能输出作为Y。我们发现这16个中有12个符合上面的等式。所以上式发生的概率偏差为 $12/16-1/2=1/4$
假设现在使用的查看的是$X_1 \oplus X_4 \oplus =Y_2$
我们首先输入16个可能的输入作为X,然后检查对应的可能输出作为Y。我们发现这16个中有8个符合上面的等式。所以上式发生的概率偏差为 $8/16-1/2=0$
上述讲述了通常意义上的方法,那么我们如何运用算法来求解呢?
|
|
根据上述算法,我们得到下面这张表linear Approximation Table:
我们来讲一讲这张表的含义:
Input sum代表的是所有比特位的累加和,output sum表示所有比特位的累加和。而在表中的数字代表的是:输入和的2进制表达式对应的输入与输出和的2进制表达式对应的输出组成的线性表达式,其成立的次数减去所有可能数的一半。
例如:$X_2 \oplus X_3 \oplus =Y_1 \oplus Y_3 \oplus Y_4$ 对应的就是$(2^2+2^1,2^3+2+2^0)=(6,11)=+4$,概率偏差就是1/4
$X_1 \oplus X_4 \oplus =Y_2$ 对应的就是$(2^3+1,2^2)=(9,4)=0$ 其概率偏差为0
几个常用的引理:
- 任何输出位的线性组合,在遍历ii,求得sbox[ii] & output_sum后,必定具有相同数量的0和1
- 所有无输出比特的线性组合与所有无输入的线性组合相等,都是1/2,即左上角(0,0)是sbox_size/2,而(0,i)=(i,0)=0, 其中i不为0。
- 所有行和的绝对值为sbox_size/2,所有列和的绝对值为sbox_size/2。
2.3 引理的证明
根据算法,我们可以写出下列表达式
我们首先看一下input_sum确定的情况:
$$
\sum_{j=0} ^n \sum_{i=0} ^n P(output_{mask},input_{mask})=\sum_{j=0} ^n \sum_{i=0} ^n P(i \& input_{sum}, sbox[i] \& j)
= \sum_{i=0} ^n \sum_{j=0} ^n P(i \& input_{sum}, sbox[i] \& j) = \sum_{sbox[i]=0} P(i \& input_{sum}, sbox[i] \& j) = -sbox_{size}/2 或者 +sbox_{size}/2
$$
0x03 线性分析法整体分析
3.1 具体步骤
根据上面那种线性分析表格,我们有:
$S_{12}: X_1 \oplus X_3 \oplus X_4 = Y_2; 概率12/16, 偏差1/4$
$S_{22}: X_2= Y_2 \oplus Y_4; 概率4/16, 偏差-1/4$
$S_{32}: X_2= Y_2 \oplus Y_4; 概率4/16, 偏差-1/4$
$S_{34}: X_2= Y_2 \oplus Y_4; 概率416, 偏差-1/4$
设 $U_{i,j}(V_{i,j})$ 表示第i轮的16比特中的第j比特输入或输出,$P_i$ 代表16位明文的第i位输入
于是我们有:
第一轮: $V_{1,6} = U_{1,5} \oplus U_{1,7} \oplus U_{1,8} = (P_5 \oplus K_{1,5}) \oplus (P_7 \oplus K_{1,7}) \oplus (P_8 \oplus K_{1,8})$ (2)
第二轮:$V_{2,6} \oplus V_{2,8} = U_{2,6} = V_{1,6} \oplus K_{2,6}$
带入第一轮的数据,有:$V_{2,6} \oplus V_{2,8} \oplus P_5 \oplus P_7 \oplus P_8 \oplus K_{1,5} \oplus K_{1,7} \oplus K_{1,8} \oplus K_{2,6} =0 $ (3)
(2)式的概率偏差是1/4,概率为3/4,带入(3)式有其概率为: 1/2+2(3/4-1/2)(1/4-1/2)=3/8 (偏差-1/8)
第三轮:$V_{3,6} \oplus V_{3,8} = U_{3,6} = V_{2,6} \oplus K_{3,6}$
$V_{3,14} \oplus V_{3,16} = U_{3,14} = V_{2,8} \oplus K_{3,14}$
带入之后有: $V_{3,6} \oplus V_{3,8} \oplus V_{3,14} \oplus V_{3,16} \oplus V_{2,6} \oplus K_{3,6} \oplus V_{2,8} \oplus K_{3,14} = 0$ (4)
(4)式的概率为 1/2+2(1/4-1/2)(1/4-1/2) = 5/8 (偏差为1/8)
结合(3)、(4)式,我们有: $V_{3,6} \oplus V_{3,8} \oplus V_{3,14} \oplus V_{3,16} \oplus P_5 \oplus P_7 \oplus P_8 \oplus K_{1,5} \oplus K_{1,7} \oplus K_{1,8} \oplus K_{2,6} \oplus K_{3,6} \oplus K_{3,14} = 0$
第四轮:由$U_{4,6} = V_{3,6} \oplus K_{4,6}$,$U_{4,8} = V_{3,14} \oplus K_{4,8}$, $U_{4,14}=V_{3,8} \oplus K_{4,14}$ ,$U_{4,16} = V_{3,16} \oplus K_{4,16}$
我们有:$U_{4,6} \oplus U_{4,8} \oplus U_{4,14} \oplus U_{4,16} \oplus P_5 \oplus P_7 \oplus P_8 \oplus \sum_K = 0$
其中:$\sum_K = K_{1,5} \oplus K_{1,7} \oplus K_{1,8} \oplus K_{2,6} \oplus K_{3,6} \oplus K_{3,14} \oplus K_{4,6} \oplus K_{4,8} \oplus K_{4,14} \oplus K_{4,16}$
其中$\sum_K$ 的值为0或1,并且由叠加原理,有其概率为 $1/2+2^3(3/4-1/2)(1/4-1/2)^3=15/32$ (偏差-1/32)
$U_{4,6} \oplus U_{4,8} \oplus U_{4,14} \oplus U_{4,16} \oplus P_5 \oplus P_7 \oplus P_8 = 0$ (5)
第5轮:
3.2 获取Key的各比特位的值
上面之所以不进行第5轮的计算,是因为若R-1轮线性分析后,从密文反推会更为容易。
对于给出对应位置的部分目标子密钥$[K_{5,5} ... K_{5,8}, K_{5,13} ... K_{5,16}]$,解密出对应的密文得到$[V_{4,5} ... V_{4,8}, V_{4,13} ... V_{4,16}]$。通过S和的逆变换,我们可以求解出$[U_{4,5} ... U_{4,8}, U_{4,13} ... U_{4,16}]$ 。然后依据(5)式,可以算出符合该线性表达式的次数。
之所以可以使用这种方法,是因为如果部分目标子密钥正确,那么(5)式成立的概率将会与1/2有很大不同。而其他不正确的子密钥,将会造成(5)式概率接近于1/2。
(5)式影响S盒$S_{42}$ 和 $S_{44}$ 的输入。对于每对明密文对,我们将会尝试256种可能的部分目标子密钥$[K_{5,5} ... K_{5,8}, K_{5,13} ... K_{5,16}]$ 。对于每种可能的部分子密钥,我们都会求出(5)式为真时的次数。这些次数偏离最远的就是正确的解,当然不用管这些次数是正向偏移还是逆向偏移(其取决于$\sum_K$)。
当$\sum_K=0$ 时,(5)式成立的概率 < 1/2
当$\sum_K=1$ 时,(5)式成立的概率 > 1/2
我们测试了10000组已知明密文对,用下列公式计算偏移:
$|bias| = |count - 5000|/10000$
最终得到下面的表格:
根据表格可以看出$[K_{5,5} ... K_{5,8}]=0010, [K_{5,13} ... K_{5,16}]=0100$ 时,偏移概率最大,为0.0336。其实1/32=0.03125。注意到这些之后,我们可以肯定这两部分的密钥值就是这些。
而直到这两部分的值之后,我们完全可以爆破求解另外两部分的密钥(如果密钥是可以反向求解的!)
3.3 攻击的复杂度
成功原因:如果S盒偏差越大,线性分析的偏差也会越大。
设$\epsilon$ 为线性表达式距离1/2的偏差,Matsui表示要使攻击成功,那么已知明文的数量要与$\epsilon^-2$ 的数量成正比。
如果$N_L$ 表示线性表达式需要的已知明文数量,则有 $N_L \approx 1/\epsilon^2$
由于偏差使用线性叠加的方式来计算的,所以很容易看出偏差依赖于S盒的线性近似表达式和触发的S盒数量。
0x04 范例
既然讲到了线性分析法,那么我们就必须使用其进行解题。下面是2018 0ctf的一道题,zer0SPN
zer0SPN.py
|
|
使用下面脚本获取S盒的缺陷表达式:(find_linear_approxmation)
|
|
得到:
|
|
然后我们来获得到第四轮时的表达式(未亦或):(这里选择性地用了几组开始数据)
|
|
获得表达式:
|
|
最后我们看看上面的表达式,我们能够爆破的只有两个字节,因此应该选择合适的表达式进行展开。
由于性能的要求,这里使用的是c语言(这里用的是倒数第2个表达式):
|
|
结果为:
|
|
于是我们可以认为最后1轮中,第0字节为130,第6个字节是194。
当然我们可用类似的办法求出另外一些字节:
|
|
最终的flag为flag{48667ec1a5fb3383}
0x05 引用
https://www.engr.mun.ca/~howard/PAPERS/ldc_tutorial.pdf
https://gist.github.com/ngg/f534e51c14a832d69c41289837078773