差分攻击DES

差分攻击三轮DES

  • DES算法简介
  • 差分攻击原理
  • 流程图
  • 数学依据
  • 差分分布表的生成
  • 差分攻击获取第三轮密钥(48位)
  • 爆破剩余的8位
  • 使用说明
  • 编者的话

DES算法简介

转载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分钟可攻破。

流程图

差分攻击DES_第1张图片

数学依据

差分攻击DES_第2张图片
差分攻击DES_第3张图片
差分攻击DES_第4张图片
差分攻击DES_第5张图片
差分攻击DES_第6张图片
差分攻击DES_第7张图片
差分攻击DES_第8张图片
差分攻击DES_第9张图片
差分攻击DES_第10张图片

差分分布表的生成

我们规定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)

差分攻击获取第三轮密钥(48位)

有了差分分布表,我们只需要把明文对,密文对传入,计算他们的输入输出异或,查表即可获得可能的输入,再与第三轮的输入异或一下就得到了可能的密钥。


```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位密钥

爆破剩余的8位

有了第三轮的密钥,我们只需将他复原成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]]

编者的话

踩过的坑:

  1. DES的端序问题,例如二进制数0b001101,第一位为0。
  2. 该程序中所用的DES舍去了很多初始(逆)置换,只需要Li和Ri; 同时一般情况下在加密时最后一轮会对调L16和R16,而在该实验中并不需要。
  3. 本次实验需求是56位密钥,注意调整加解密函数。

原理截的老师的PPT,网上也有,不做过多解释。

你可能感兴趣的:(python,密码学)