python实现DES加密算法(超级详细)

原理参考:https://blog.csdn.net/qq_27570955/article/details/52442092
流程图大概如图所示:
python实现DES加密算法(超级详细)_第1张图片
原理搞懂之后接下来先做一些准备工作,先创建如下文件(理由后面提到)miwen.txt是我最后用来存生成的密文的,可以不建:
python实现DES加密算法(超级详细)_第2张图片
每个文件的内容分别如下:
E_extend.txt

32,1,2,3,4,5,
4,5,6,7,8,9,
8,9,10,11,12,13,
12,13,14,15,16,17,
16,17,18,19,20,21,
20,21,22,23,24,25,
24,25,26,27,28,29,
28,29,30,31,32,1

IP.txt:

58,50,42,34,26,18,10,2,
60,52,44,36,28,20,12,4,
62,54,46,38,30,22,14,6,
64,56,48,40,32,24,16,8,
57,49,41,33,25,17, 9,1,
59,51,43,35,27,19,11,3,
61,53,45,37,29,21,13,5,
63,55,47,39,31,23,15,7,

IP-1.txt:

40,8,48,16,56,24,64,32,
39,7,47,15,55,23,63,31,
38,6,46,14,54,22,62,30,
37,5,45,13,53,21,61,29,
36,4,44,12,52,20,60,28,
35,3,43,11,51,19,59,27,
34,2,42,10,50,18,58,26,
33,1,41,9,49,17,57,25,

Key.txt:

1,1,0,1,0,0,0,1,
0,1,0,1,1,0,0,1,
0,1,0,0,1,0,0,0,
1,0,1,0,0,0,0,0,
0,0,1,0,1,0,0,1,
0,1,0,1,0,0,0,1,
1,1,1,1,0,1,1,1,
0,1,1,0,1,0,1,1,

mingwen.txt:

0,1,1,1,1,0,0,0,
0,0,1,0,1,0,0,0,
1,1,1,0,1,0,0,0,
1,1,0,0,1,0,1,0,
0,1,0,0,0,0,1,1,
1,1,1,1,0,1,1,1,
1,1,0,1,1,0,0,0,
0,0,1,1,0,0,1,0,

P.txt:

16,7,20,21,29,12,28,17,1,15,23,26,5,18,31,10,
2,8,24,14,32,27,3,9,19,13,30,6,22,11,4,25,

PC-1.txt:

57,49,41,33,25,17,9,
1,58,50,42,34,26,18,
10,2,59,51,43,35,27,
19,11,3,60,52,44,36,
63,55,47,39,31,23,15,
7,62,54,46,38,30,22,
14,6,61,53,45,37,29,
21,13,5,28,20,12,4,

PC-1-Ci.txt:

57,49,41,33,25,17,9,
1,58,50,42,34,26,18,
10,2,59,51,43,35,27,
19,11,3,60,52,44,36,

PC-1-Di.txt:

63,55,47,39,31,23,15,
7,62,54,46,38,30,22,
14,6,61,53,45,37,29,
21,13,5,28,20,12,4,

PC-2.txt:

14,17,11,24,1,5,
3,28,15,6,21,10,
23,19,12,4,26,8,
16,7,27,20,13,2,
41,52,31,37,47,55,
30,40,51,45,33,48,
44,49,39,56,34,53,
46,42,50,36,29,32,

S_box1.txt:

14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7,
0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8,
4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0,
15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13,

S_box2.txt:

15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10,
3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5,
0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15,
13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9,

S_box3.txt:

10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8,
13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1,
13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7,
1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12,12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11,
10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8,
9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6,
4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13,

S_box4.txt:

7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15,
13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9,
10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4,
3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14,

S_box5.txt:

2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9,
14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6,
4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14,
11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3,

S_box6.txt:

12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11,
10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8,
9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6,
4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13,

S_box7.txt:

4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1,
13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6,
1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2,
6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12,

S_box8.txt:

13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7,
1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2,
7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8,
2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11,

由于我们在加密过程中,需要读取很多的矩阵(或者说是二维数组),例如s盒就有八个,所以我们首先要解决的是这些矩阵如何读到我们的程序中,我才用了文件读取的方式,将所有需要的矩阵分别存在一个文件里,每次需要的时候就读取文件,定义一个my_read()函数,参数有文件名和矩阵的行列数,将读取到的文件以二维数组(列表套列表)返回:

def my_read(filename,row,col):               #读取各种矩阵----参数为文件名和目标矩阵的行列数
    sz = [[0 for i in range(col)]for i in range(row)]
    with open(filename,"r") as s1:
        lists = s1.readlines()
        for i in range(len(sz)):
            lists[i] = lists[i].split(',')  #以 , 将字符串分开
            for j in range(len(sz[0])):
                sz[i][j] = lists[i][j]
    return sz                                   #返回一个该矩阵的二维数组

先从密钥入手,流程图大概如下所示,所以第一步要通过PC-1移位得到C0,D0,为了使主函数简单,逻辑性强,我们也定义一个create_L0R0()函数实现:
python实现DES加密算法(超级详细)_第3张图片

def create_L0R0():                               #生成L0,R0
    mingwen = my_read("mingwen.txt",8,8)        #读取明文
    rep = my_read("IP.txt",8,8)         #读取置换矩阵
    rep_mingwen = replace(mingwen,rep,8,8)              #进行初始置换
    L0 = []
    R0 = []
    for i in range(4):                      #得到c0
        for j in range(8):
            #print(rep[i][j],end = ' ')    #检查数值
            x,y = get_xy(int(rep[i][j]),8,8)      #检查坐标
            L0.extend(rep_mingwen[x][y])
    for i in range(4,8):                      #得到d0
        for j in range(8):
            x,y = get_xy(int(rep[i][j]),8,8)      #检查坐标
            R0.extend(rep_mingwen[x][y])
    #print(L0)
    #print(R0)
    return [L0,R0]

其中用到的get_xy()函数是用来把一个整型数字(表示位置)变成我们需要的二维数组的坐标。

python实现DES加密算法(超级详细)_第4张图片
eg:如果我们想知道第42个位置的数在一个7行8列的二维数组中的坐标,可以调用x,y = get_xy(42,7,8)来获得。具体函数实现如下:

def get_xy(n,row,col):                          #n为要转化为坐标的数值
    if n % col == 0:
        x = int(n/col) -1
        y = col - 1
    else:
        x = int(n/col)
        y = n%col - 1
    return [x,y]

replace(temp,rep,row,col)函数如下:

def replace(temp,rep,row,col):                              #定义一个置换函数,参数temp为要替换的矩阵,file为替换矩阵,row列,col行
    new_temp = [[0 for i in range(col)]for i in range(row)]   #用来保存置换后的矩阵并作为返回值
    for i in range(len(temp)):
        for j in range(len(temp[0])):
            #x = int(int(rep[i][j])/8)
            #y = int(rep[i][j])%8
            x,y = get_xy(int(rep[i][j]),row,col)
            ##输出坐标
            #if y == 0:
            #    print(x,y,end = '|')
            #else :
            #    print(x,y,end = '|')
            #输出置换后矩阵
            if int(rep[i][j])%8 == 0:
                new_temp[i][j] = temp[x-1][7]
                #print(temp[x-1][7],end = ' ')
            else:
                new_temp[i][j] = temp[x][y]
                #print(temp[x][y],end = ' ')
        #print('')
    return new_temp[:]

得到C0,D0后,我们在写一个函数child_key()一次性获取所有子密钥:

def child_key():                                #生成k1~k16的子密钥
    key = my_read("Key.txt",8,8)                #读取64位key
    c = []
    d = []
    k = []
    c0,d0 = create_c0d0(key)                      #得到c0,d0
    num = [1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1]     #设置第n次循环左移位数
    for i in range(16):                         #将生成k1~k16的子密钥存放在列表k中
        c0 = my_move(c0,num[i])
        d0 = my_move(d0,num[i])
        k1 = []
        k1.extend(c0)
        k1.extend(d0)
        pc_2 = my_read("PC-2.txt",8,6)
        temp = []                                   #暂时存放56位子密钥
        for m in range(8):
            for n in range(6):
                temp.append(k1[int(pc_2[m][n])-1])
        k.append(temp)
    return k[:]                                 #k位16x48的子密钥二维数组

其中的my_move(list,n)函数是实现移位的,位数以n为参数传入:

def my_move(list,n):                            #循环移位,n为移位数
    for i in range(n):##左移
        list.insert(len(list),list[0])
        list.remove(list[0])
    return list

到此之外,子密钥k1-k16已经全部获取,开启下一段征程----处理明文
首先和处理密钥一样的思路,先获取L0,R0:

def create_L0R0():                               #生成L0,R0
    mingwen = my_read("mingwen.txt",8,8)        #读取明文
    rep = my_read("IP.txt",8,8)         #读取置换矩阵
    rep_mingwen = replace(mingwen,rep,8,8)              #进行初始置换
    L0 = []
    R0 = []
    for i in range(4):                      #得到c0
        for j in range(8):
            x,y = get_xy(int(rep[i][j]),8,8)      #检查坐标
            L0.extend(rep_mingwen[x][y])
    for i in range(4,8):                      #得到d0
        for j in range(8):
            x,y = get_xy(int(rep[i][j]),8,8)      #检查坐标
            R0.extend(rep_mingwen[x][y])
    return [L0,R0]

查看流程图,发现我们还有一个f函数没有完成,干!下面是f函数的大概流程:
python实现DES加密算法(超级详细)_第5张图片
我们分别定义函数E_extend(R0)、yihuo(a,c)、create_B(K,ERi,num)、get_bi(B)、get_lastR(K,R0,num)分别来实现E扩展、异或运算、得到B、得到B0-B7、经过s盒并进行P置换得到last_R的功能

def E_extend(R0):                               #将32位Ri扩展位48位
    Ri = []
    e = my_read("E_extend.txt",8,6)
    for m in range(len(e)):
        for n in range(len(e[0])):
            Ri.append(R0[int(e[m][n])-1])
    #print(Ri)
    return Ri
def yihuo(a,c):                                     #进行异或运算
    B = []
    for n in range(len(a)):
        b = []
        if int(a[n]) == int(c[n]):
            b.append(0)
        else:
            b.append(1)
        B.extend(b)
    return  B   
def create_B(K,ERi,num):               #进行异或运算,K为48位子密钥列表,ERi为48位扩展的Ri,num是轮数
    B = []
    for m in range(len(K)):
        b = []
        for n in range(len(K[0])):
            if K[m][n] == ERi[n]:
                b.append(0)
            else:
                b.append(1)
        B.append(b)
    #print(B)
    return  B[num]                       #返回值为B0~B7的集合列表B
def get_bi(B):
    b0 = ''
    b1 = ''
    b2 = ''
    b3 = ''
    b4 = ''
    b5 = ''
    b6 = ''
    b7 = ''
    for i in range(6):
        b0 = b0 + str(B[i])
    for i in range(6,12):
        b1 = b1 + str(B[i])
    for i in range(12,18):
        b2 = b2 + str(B[i])
    for i in range(18,24):
        b3 = b3 + str(B[i])
    for i in range(24,30):
        b4 = b4 + str(B[i])
    for i in range(30,36):
        b5 = b5 + str(B[i])
    for i in range(36,42):
        b6 = b6 + str(B[i])
    for i in range(42,48):
        b7 = b7 + str(B[i])
    return [b0,b1,b2,b3,b4,b5,b6,b7]
def get_lastR(K,R0,num):                #num为轮数
    ERi = E_extend(R0)                  #E扩展
    B = create_B(K,ERi,num)               #num轮数用来控制Ki      
    b0,b1,b2,b3,b4,b5,b6,b7 = get_bi(B)
    b0 = cut_bi(b0,0)
    b1 = cut_bi(b1,1)
    b2 = cut_bi(b2,2)
    b3 = cut_bi(b3,3)
    b4 = cut_bi(b4,4)
    b5 = cut_bi(b5,5)
    b6 = cut_bi(b6,6)
    b7 = cut_bi(b7,7)
    last_R = []
    last_R.extend(b0)
    last_R.extend(b1)
    last_R.extend(b2)
    last_R.extend(b3)
    last_R.extend(b4)
    last_R.extend(b5)
    last_R.extend(b6)
    last_R.extend(b7)
    return last_R

其中上述用到的函数还有
read_s(num)–用来实现读取S盒,n为读取的S盒盒数;
cut_bi()–将bi过s盒在返回,6位变成4位

def read_s(num):
    if num+1 == 1:
        s = my_read("S_box1.txt",4,16)
    elif num+1 == 2:
        s = my_read("S_box2.txt",4,16)
    elif num+1 == 3:
        s = my_read("S_box3.txt",4,16)
    elif num+1 == 4:
        s = my_read("S_box4.txt",4,16)
    elif num+1 == 5:
        s = my_read("S_box5.txt",4,16)
    elif num+1 == 6:
        s = my_read("S_box6.txt",4,16)
    elif num+1 == 7:
        s = my_read("S_box7.txt",4,16)
    else:
        s = my_read("S_box8.txt",4,16)
    return s
def cut_bi(b,n):
    x = my_int2(b[0],b[5])
    y = my_int4(b[1],b[2],b[3],b[4])
    s = read_s(n+1)
    s =[]
    temp = read_s(n)
    s.append(my_bin(int(temp[x][y])))
    return s

还有三个函数my_int4(a1,a2,a3,a4)、my_int2(a1,a2)、my_bin(a)是实现数据转换的,前两个是在读取s盒时,将字符串转化为S盒的坐标,第三个时将十进制整数转化为字符串形式的二进制数。

def my_int4(a1,a2,a3,a4):
    a = a1 + a2 + a3 + a4
    if a == '0000':
        a = int(0)
    elif a == '0001':
        a = int(1)
    elif a == '0010':
        a = int(2)
    elif a == '0011':
        a = int(3)
    elif a == '0100':
        a = int(4)
    elif a == '0101':
        a = int(5)
    elif a == '0110':
        a = int(6)
    elif a == '0111':
        a = int(7)
    elif a == '1000':
        a = int(8)
    elif a == '1001':
        a = int(9)
    elif a == '1010':
        a = int(10)
    elif a == '1011':
        a = int(11)
    elif a == '1100':
        a = int(12)
    elif a == '1101':
        a = int(13)
    elif a == '1110':
        a = int(14)
    else:
        a = int(15)
    return a
def my_int2(a1,a2):
    a = a1 + a2
    if a == '00':
        a = int(0)
    elif a == '01':
        a = int(1)
    elif a == '10':
        a = int(2)
    else:
        a = int(3)
    return a
def my_bin(a):
    if a == 0:
        a = '0000'
    elif a == 1:
        a = '0001'
    elif a == 2:
        a = '0010'
    elif a == 3:
        a = '0011'
    elif a == 4:
        a = '0100'
    elif a == 5:
        a = '0101'
    elif a == 6:
        a = '0110'
    elif a == 7:
        a = '0111'
    elif a == 8:
      a = '1000'
    elif a == 9:
        a = '1001'
    elif a == 10:
        a = '1010'
    elif a == 11:
        a = '1011'
    elif a == 12:
        a = '1100'
    elif a == 13:
        a = '1101'
    elif a == 14:
        a = '1110'
    else:
        a = '1111'
    return a

最后还有一个函数change(temp)是实现格式化控制的:

def change(temp):
    list = []
    for m in range(len(temp)):
        for n in range(len(temp[0])):
            list.append(temp[m][n])
    return list

现在我们得到了L16,R16,距离明文还差最后一步逆置换,就在主函数中实现好了,毕竟我们已经定义了18个子函数(太多啦!)

K = child_key()                     #获取k1~k16的子密钥存依次放在列表K中
L0,R0 = create_L0R0()               #获取L0,R0
for num in range(16):               #有限月读
    L = R0
    temp = get_lastR(K,R0,num)
    temp = change(temp)             #改变一下格式,使temp和L0格式一样,方便实现异或运算
    R = yihuo(L0,temp)
    L0 = L
    R0 = R
mw = []                             #存放最终的L,R
mw.extend(L)
mw.extend(R)
rep = my_read("IP-1.txt",8,8)       #进行最后一步逆置换并输出密文
miwen = []
for m in range(len(rep)):
    for n in range(len(rep[0])):
        print(mw[int(rep[m][n])-1],end = ' ')
    print('')

python实现DES加密算法(超级详细)_第6张图片

你可能感兴趣的:(密码学实验)