转载https://blog.csdn.net/qq_42606051/article/details/81279504
对DES有效的分析方法–差分分析方法,是由E.Biham和A.Shamir提出的。见
Differential Cryptanalysis of DES-like Cryptosystems. E.Biham A.Shamir. The Weizmann Institute of ScienceDepartment of Aplied Mathematics. June 18,1999
该文给出选择性明文攻击,是一个很有效的方法。
对于攻击8轮DES,在486那样的计算机上,只需2分钟可攻破。
我们规定IN[i][j][k],其中i指第几个S-box,取值范围0-7;j指的是输入异或,长度为6位,k指的是输出异或,长度为4位。
生成方法就是穷举,对每个S-box,我们穷举输入异或,根据得出的输出异或将他们的输入放入对应的列表中。
生成差分分布表,放入 diff_excel.json种
IN =[[[[]for i in range(1<<4)]for i in range(1<<6)]for i in range(8)] #IN[s_num][B'][C']
for i in range(1<<6):
for j in range(i,1<<6):
in_xor = i^j
for k in range(8):
i_out = f_s(i,k) #f_s位s-box替换函数
j_out = f_s(j,k)
out_xor = i_out^j_out
if i not in IN[k][in_xor][out_xor]:
IN[k][in_xor][out_xor].append(i)
if j not in IN[k][in_xor][out_xor]:
IN[k][in_xor][out_xor].append(j)
fp = open('diff_excel.json','w')
json.dump(IN,fp)
有了差分分布表,我们只需要把明文对,密文对传入,计算他们的输入输出异或,查表即可获得可能的输入,再与第三轮的输入异或一下就得到了可能的密钥。
```python
def diff_attack(p1,c1,p2,c2,bool_exc):
#init
p1_str = "{:0>64b}".format(p1)
p2_str = "{:0>64b}".format(p2)
c1_str = "{:0>64b}".format(c1)
c2_str = "{:0>64b}".format(c2)
l0 = int(p1_str[0:32],2)
r0 = int(p1_str[32:64],2)
l3 = int(c1_str[0:32],2)
r3 = int(c1_str[32:64],2)
l0_ = int(p2_str[0:32],2)
r0_ = int(p2_str[32:64],2)
l3_ = int(c2_str[0:32],2)
r3_ = int(c2_str[32:64],2)
e_l3 = f_e(l3) E置换
e_l3_ = f_e(l3_)
in_xor = e_l3^e_l3_
out_xor = f_p_inv(r3^r3_^l0^l0_) P置换的逆置换
fp = open('diff_excel.json','r')
IN = json.load(fp)
in_list = IN[0][in_choose(in_xor,0)][out_choose(out_xor,0)]
for i in range(8):
in_list = IN[i][in_choose(in_xor,i)][out_choose(out_xor,i)]
for j in in_list:
key_tmp = j^in_choose(e_l3,i)
bool_exc[i][key_tmp] += 1
key48 = ''
for i in range(8):
key48 = key48 + '{:0>6b}'.format(f_max(bool_exc[i]))
return int(key48,2)
实际测试时发现基本能给到三组明密文就能唯一确定该48位密钥
有了第三轮的密钥,我们只需将他复原成56位,再看看剩下的8位是哪些,穷举填充0/1即可。
考虑到当数据量不足时可能不能唯一确定密钥的48位,因此也对其进行了爆破;当数据足够时,该部分可直接跳过。
def diff_hack(p_list,c_list):
key_bool = {
}
keys=[]
bool_exc = [[0 for i in range(128)]for i in range(8)]
for (pp,cc) in zip(p_list,c_list):
p1 = pp[0]
c1 = cc[0]
p2 = pp[1]
c2 = cc[1]
key = attack.diff_attack(p1,c1,p2,c2,bool_exc)
#到这儿的时候bool_exc其实就给了我们这48位密钥的可能值
s_max = [0 for i in range(8)]
for i in range(8):
max_tmp = -1
for j in bool_exc[i]:
if j>max_tmp:
max_tmp = j
s_max[i] = max_tmp
s_max_elem = [[]for i in range(8)]
for i in range(8):
index = 0
for j in bool_exc[i]:
if j == s_max[i]:
s_max_elem[i].append(index)
index +=1
计算出该48位密钥(分成8部分,对应8个S-box)的可能值,如果不能确定则爆破。
for i0 in s_max_elem[0]:
for i1 in s_max_elem[1]:
for i2 in s_max_elem[2]:
for i3 in s_max_elem[3]:
for i4 in s_max_elem[4]:
for i5 in s_max_elem[5]:
for i6 in s_max_elem[6]:
for i7 in s_max_elem[7]:
key_str = '{:0>6b}'.format(i0)+'{:0>6b}'.format(i1)+'{:0>6b}'.format(i2)+'{:0>6b}'.format(i3)+'{:0>6b}'.format(i4)+'{:0>6b}'.format(i5)+'{:0>6b}'.format(i6)+'{:0>6b}'.format(i7)
key = int(key_str,2)
keys.append(key)
for i in keys:
explode(i,key_bool)
res = f_max(key_bool)
return res
def explode(key,key_bool):
des_per_inv = [4, 23, 6, 15, 5, 9, 19, 17, -1, 11, 2, 14, 22, 0,
8, 18, 1, -1, 13, 21, 10, -1, 12, 3, -1, 16, 20, 7,
46, 30, 26, 47, 34, 40, -1, 45, 27, -1, 38, 31, 24, 43,
-1, 36, 33, 42, 28, 35, 37, 44, 32, 25, 41, -1, 29, 39]
#48 -> 56
p_str=''
for j in des_per_inv:
if j!=-1:
p_str = p_str+str(bin_judge(key,47-j))
else:
p_str = p_str+'x'
#到这一步时,密钥中48位已经确定,还有8个位置是‘x’
l_tmp = left_move(24,p_str[0:28])
r_tmp = left_move(24,p_str[28:56])
#复原成初始密钥,到第三轮时密钥左移了4位,所以再左移24位即可
key = l_tmp+r_tmp
for i in range(1<<8):
i_str = '{:0>8b}'.format(i)
index = 0
key_g=''
for j in range(56):
if key[j] == 'x':
key_g = key_g+ i_str[index]
index = index +1
else:
key_g = key_g+key[j]
this_key = int(key_g,2)
#爆破完比
#检查该密钥能成功加密多少个明文
for (pp,cc) in zip(p_list,c_list):
for (p,c) in zip(pp,cc):
if des.encode(p,this_key,56) == c:
if this_key in key_bool.keys():
key_bool[this_key] +=1
else:
key_bool[this_key] = 1
由于只截取了部分关键代码,完整文件已开源。
开源地址 https://github.com/Psyduck0409/diff-des-attack
使用教程,需下载diff_hack.py diff_attack.py diff_excel.json little_des.py
其中little_des即是三轮des,可调用其中的加密解密函数。
e.g.
little_des.encode(p,k,num=64)
其中p,k是明文密钥,均为数字;num是指密钥长度。
diff_attack模块为攻击密钥的48位。
diff_hack为生成最终密钥。编者偷懒没有写输入输出功能。
调用方法:diff_hack(p_list,c_list)
其中p_list中是明文对的形式,c_list是密文对的形式。
样例:p_list = [[0x375BD31F6ACDFF31,0x486911026ACDFF31],[0x357418DA013FEC86,0x12549847013FEC86],[0x748502CD38451097,0x3874756438451097],[0x02152633A124F6B6,0x52873E68A124F6B6],[0x52873E68A124F6B6,0x19C26156A124F6B6],[0x19C26156A124F6B6,0xDF2D047AA124F6B6],[0xDF2D047AA124F6B6,0x52873E68A124F6B6],[0xDF2D047AA124F6B6,0x02152633A124F6B6]]
c_list = [[0x7d9aefbf2479b043,0x9cff22a4855ffb67],[0x34a4097c3639a9f7,0x274069bf45c63d96],[0x465ec3d02b29239,0x1acaa1a647de5696],[0xaa6b7f98bcfc6d92,0x295822edd97d94a9],[0x295822edd97d94a9,0xd090b9d6abc68491],[0xd090b9d6abc68491,0x8cce692006d01968],[0x8cce692006d01968,0x295822edd97d94a9],[0x8cce692006d01968,0xaa6b7f98bcfc6d92]]
踩过的坑:
原理截的老师的PPT,网上也有,不做过多解释。