本文是对 The Block Cipher Companion 的读书笔记,分为三篇文章简述差分分析的基本思想.
引入
我们熟悉的异或加密可以写成
c=m⊕k
香农证明了如果随机选择的 k 只使用过 1 次(即一次性密码本,OTP),异或加密是无条件安全的.而如果 k 被使用了 2 次,攻击者可以根据两个密文来计算两个消息的异或:
c0⊕c1=(m0⊕k)⊕(m1⊕k)=m0⊕m1
在消息中包含冗余的情况下,攻击者可以从中推断出明文的信息.
从这个例子中我们可以学到:相比于只考虑 1 对明文-密文,考虑 多对 明文-密文之间的关系可能会让攻击者获得更多的信息.
CipherOne
c=S[m⊕k0]⊕k1
其中 S 盒为
x | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|
S[x] | 6 | 4 | c | 5 | 0 | 7 | 2 | e |
x | 8 | 9 | a | b | c | d | e | f |
S[x] | 1 | f | 3 | d | 8 | a | 9 | b |
假设攻击者知道两个明文-密文对 (m0,c0),(m1,c1). 将加密过程逐步展开如下
CipherOne (m0,k0∥k1) | CipherOne (m1,k0∥k1) |
---|
u0=m0⊕k0 | u1=m1⊕k0 |
v0=S[u0] | v1=S[u1] |
c0=v0⊕k1 | c1=v1⊕k1 |
由于 k0 是保密的,攻击者无法获取 u0,u1 的值. 然而,当我们引入 差分 的概念时,攻击者实际上是知道它们的差分的:
u0⊕u1=(m0⊕k0)⊕(m1⊕k0)=m0⊕m1
对于正确的 k1,有 u0⊕u1=S−1[v0]⊕S−1[v1],攻击者可以简单地尝试所有可能的 k1 值 t,一旦获得期望的 S−1[v0]⊕S−1[v1] (也就是等于已知值 u0⊕u1),那么 t 就是一个可能的密钥!接下来可以重复这样的攻击,直到候选的密钥唯一.
从对 CipherOne 的攻击中我们可以学到:
- 尽管我们可能不知道加密过程中内部变量的值,但我们能 描述这些变量的差分!
- 我们能够 猜测部分密钥的值,并 测试某些差分条件是否成立 来恢复密钥信息!
关于第一点,在 CipherOne 中,我们可以 确定地 描述内部变量之间的差分,但在更复杂的密码中,这种描述可能是 不确定的. 接下来请看 CipherTwo.
CipherTwo
c=S[S[m⊕k0]⊕k1]⊕k2
假设攻击者知道两个明文-密文对 (m0,c0),(m1,c1). 将加密过程分步写为
CipherOne (m0,k0∥k1∥k2) | CipherOne (m1,k0∥k1∥k2) |
---|
u0=m0⊕k0 | u1=m1⊕k0 |
v0=S[u0] | v1=S[u1] |
w0=v0⊕k1 | w1=v1⊕k1 |
x0=S[w0] | x1=S[w1] |
c0=x0⊕k2 | c1=x1⊕k2 |
按照 CipherOne 的方法从下往上分析,通过猜测 k2 的值来计算 x0,x1,进而得到 w0,w1. 这时遇到了 k1 ,所以没法直接得到 v0,v1,不过别忘了,计算差分 w0⊕w1 让我们能够得到 v0⊕v1.
从上往下分析,我们知道 m0⊕m1,也就是知道 u0⊕u1.
这时候我们会发现,v0⊕v1 和 u0⊕u1 之间隔了一个 S 盒,而 S 盒是 非线性的,这阻断了我们对 k2 猜测的验证.
理解 S 盒的行为
v0⊕v1 和 u0⊕u1 之间隔了一个 S 盒,这个 S 盒究竟做了什么?
先讨论一个特殊情况:对于 S 盒的两个输入,i 和 j ,其中 j=i⊕f. 对于 i 的所有值,我们计算如下:
i | j | S [i] | S [j] | S [i] ^ S [j] |
---|
0 | f | 6 | b | d |
1 | e | 4 | 9 | d |
2 | d | c | a | 6 |
3 | c | 5 | 8 | d |
4 | b | 0 | d | d |
5 | a | 7 | 3 | 4 |
6 | 9 | 2 | f | d |
7 | 8 | e | 1 | f |
8 | 7 | 1 | e | f |
9 | 6 | f | 2 | d |
a | 5 | 3 | 7 | 4 |
b | 4 | d | 0 | d |
c | 3 | 8 | 5 | d |
d | 2 | a | c | 6 |
e | 1 | 9 | 4 | d |
f | 0 | b | 6 | d |
很容易注意到 S[i] ^ S[j]
这一列并不均匀,d
在 16 次中出现了 10 次. 前面提到,我们对 k2 的猜测被阻断了. 如果我们能够指定消息去进行加密,而不是只是简单地截取明文-密文对(也就是能够进行 选择密文攻击),我们就能够利用这种不均匀的概率分布:
随机选择 m1,令 m1=m0⊕f,我们能够知道 u0⊕u1=m0⊕m1=f. 当然,我们无法直接确切地知道 u0,u1 具体的取值,不过根据上面的表,我们能够确定: S[u0]⊕S[u1]=d 成立的概率为 1610.
这就为验证 k2 的正确性提供了依据:我们可以假设,如果 k2 的猜测是错的,那么 v0⊕v1 应该「看上去很随机」. 实际上我们可以这样做:维护一组初始化为 0 的计数器(对应 k2 的每一种取值),对于一个给定的明文-密文对,遍历所有可能的 k2 值,如果 v0⊕v1=d,那么将对应计数器的值 +1. 注意正确的 k2 使得这个关系成立的概率是 1610,而错误的 k2 使得这个关系成立的概率只有 101. 如果我们使用 N 个明文-密文对,正确的 k2 对应的计数器应该明显大于其他计数器.
刚刚我们是在讨论 j=i⊕f 的特殊情况,实际上我们可以对所有可能的输入差分进行类似操作,画出一张 差分分布表. 每一行表示一个输入 din ,表中每项表示对应的输出 dout 出现的频率.
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c | d | e | f |
---|
0 | 16 | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - |
1 | - | - | 6 | - | - | - | - | 2 | - | 2 | - | - | 2 | - | 4 | - |
2 | - | 6 | 6 | - | - | - | - | - | - | 2 | 2 | - | - | - | - | - |
3 | - | - | - | 6 | - | 2 | - | - | 2 | - | - | - | 4 | - | 2 | - |
4 | - | - | - | 2 | - | 2 | 4 | - | - | 2 | 2 | 2 | - | - | 2 | - |
5 | - | 2 | 2 | - | 4 | - | - | 4 | 2 | - | - | 2 | - | - | - | - |
6 | - | - | 2 | - | 4 | - | - | 2 | 2 | - | 2 | 2 | 2 | - | - | - |
7 | - | - | - | - | - | 4 | 4 | - | 2 | 2 | 2 | 2 | - | - | - | - |
8 | - | - | - | - | - | 2 | - | 2 | 4 | - | - | 4 | - | 2 | - | 2 |
9 | - | 2 | - | - | - | 2 | 2 | 2 | - | 4 | 2 | - | - | - | - | 2 |
a | - | - | - | - | 2 | 2 | - | - | - | 4 | 4 | - | 2 | 2 | - | - |
b | - | - | - | 2 | 2 | - | 2 | 2 | 2 | - | - | 4 | - | - | 2 | - |
c | - | 4 | - | 2 | - | 2 | - | - | 2 | - | - | - | - | - | 6 | - |
d | - | - | - | - | - | - | 2 | 2 | - | - | - | - | 6 | 2 | - | 4 |
e | - | 2 | - | 4 | 2 | - | - | - | - | - | 2 | - | - | - | - | 6 |
f | - | - | - | - | 2 | - | 2 | - | - | - | - | - | - | 10 | - | 2 |