密码学课程设计-DES的加密与解密
DES算法流程:
1. 64位明文经过初始置换(IP)重新排列,并且将其分为左右两个分组:L0,R0。各32位
2. 密钥扩展。
3. 在密钥的参与下,最左右两个分组进行16轮相同函数的迭代,每轮迭代都有置换和代换。注意最后一轮迭代的输出为64位。左半部分和右半部分不进行交换。
4. 最后的与输出再通过逆初始置换(IP-1)产生64位密文。
初始置换(IP)
64位明文经过初始置换(IP)重新排列,并且将其分为左右两个分组:L0,R0。各32位
def Exchagne_IP(M): x = [0] * len(M) for i in range(len(IP_table)): x[i] = M[IP_table[i] - 1] # print(x) L = [0] * (len(M) // 2) R = [0] * (len(M) // 2) for i in range(len(L)): L[i] = x[i] for i in range(len(R)): R[i] = x[i + len(L)] return L, R
密钥扩展
1.64位密钥通过置换选择PC-1得到56位有效密钥。
分成两个28位数据C0, D0。
每轮迭代中,Ci-1和Di-1分别循环左移一定位数,结果作为下一轮输入。同时,结果通过PC-2产生48位输出,作为子密钥。
# 生成子密钥总函数
def Create_FINAL_KEY(C0, D0):
CI = C0
DI = D0
for i in range(16): # 0~15
CI, DI = rol(CI, DI, i) # 循环左移 对
Change_With_PC2(CI, DI) #
def Enlarge_Key(K): K1 = [] D0 = [] C0 = [] t = 0 # 置换选择1 for i in range(len(PC_1)): K1.append(K[PC_1[i] - 1]) # 形成C0,D0 for i in range(28): C0.append(K1[i]) for i in range(28): D0.append(K1[i + 28]) Create_FINAL_KEY(C0, D0)
轮函数F
有四个组成:扩展置换(E盒),密钥加非线性代换(S盒),线性置换(P盒)
# f函数 def f(R, num): # num从0~15 x1 = E_Exchange(R) # 扩展置换 x2 = func_xor(x1, K_final[num]) # 异或 # print("Xor", binarray_to_str(x2)) x3 = S_Exchange(x2) # 48位一维数组进入S盒 # print() # print("S: ", binarray_to_str(x3)) x4 = P_Exchange(x3) # 32位一维数组进入P盒 return x4
扩展置换
32位输入扩展为48位输出。将48位输出按8行6列的E盒进行置换。快速实现雪崩效应。
# 扩展置换 def E_Exchange(R): x = [0] * len(E) for i in range(len(E)): x[i] = R[E[i] - 1] return x
密钥轮加
E盒出的48位于48位子密钥逐个异或。
def func_xor(x1, x2): if len(x1) != len(x2): print("xor:输入字符串长度不等") else: res = [0] * len(x1) for i in range(len(x1)): res[i] = chr_xor(x1[i], x2[i]) # 逐个字符异或 return res
代换盒(S)
密钥轮加48位压缩成32位。8个S盒,均6进4出。查询方法:b1~b6, b1b6两位 ->行, b2b3b4b5四位->列。
# S盒置换 def S_Exchange(input): # 输入是 res = [] s_num = 0 # S盒的编号 # print("S盒16进制:",end = '') for i in range(0, len(input), 6): temp = input[i:i + 6] # 先把当前切片拿出来 x = int(temp[0] + temp[5], 2) # 行 y = int(temp[1] + temp[2] + temp[3] + temp[4], 2) # 列 out = bin(S[s_num][16 * x + y])[2:].rjust(4, "0") # 查表,输出四位二进制字符串 # print(S[s_num][16 * x + y],end=' ') s_num += 1 for j in range(4): # 四位二进制数字符串放进结果,共32位 res.append(out[j]) return res
置换运算(P)
32位数据经过P盒置换。输出。
# P盒置换 def P_Exchange(input): # 32位输入 res = [0] * len(P) for i in range(len(P)): res[i] = input[P[i] - 1] return res
IP-1逆置换
def Exchange_IP_1(input): if len(input) != 64: print("len_input is not 64!") return 0 else: res = [] for i in range(len(IP_1)): res.append(input[IP_1[i] - 1]) return res
DES加密部分
def DES_encrypt(M, K): # 明文字符串,密文字符串,加密结果 # M0 = str_to_bin(M) #√ # K0 = str_to_bin(K) #√ # M = hex_to_bin(M) # K = hex_to_bin(K) L, R = Exchagne_IP(M) # 初始置换,得到L0,R0 #√ # print(bin_to_hex(L+R)) Enlarge_Key(K) # 扩展密钥,直接生成子密钥集合 # for i in range(16): # print(bin_to_hex(K_final[i])) # print(K_final) # 0~14 轮,共前15轮, 最后一轮外面写 for i in range(15): temp = R # 给temp,到时候赋给new_L after_f = f(R, i) # 进入F函数 R = func_xor(L, after_f) # 出来异或 L = temp # R给L # print("ROUND",i,end=' : ') # print(bin_to_hex(L),end=' ') # print(bin_to_hex(R)) # 第16轮 R_final = R after_f = f(R, 15) L_final = func_xor(L, after_f) # IP逆盒 res_bin = Exchange_IP_1(L_final + R_final) res_fianl = bin_to_hex(res_bin) # 16进制输出 # res_fianl = binarray_to_str(res_bin) return res_fianl
DES解密部分
def DES_decrypt(enc, K): # print(enc) # enc1 = hex_to_bin(enc) # 变成0-1数组 # K = hex_to_bin(K) # print(enc1) Enlarge_Key(K) new_L, new_R = Exchagne_IP(enc) for i in range(15, 0, -1): # 15~1 temp = new_R new_R = func_xor(new_L, f(new_R, i)) new_L = temp final_L = func_xor(new_L, f(new_R, 0)) final_R = new_R final = final_L + final_R res = Exchange_IP_1(final) res = bin_to_hex(res) return res
测试正确性
由于代码都是自己手写的,加上本人水平很一般,代码会有很多冗余和错误。在debug的时候我找了很多文本,均没有达到debug的效果。最后我找到了这个网址:
https://www.geeksforgeeks.org/data-encryption-standard-des-set-1/
加密和解密结果都能够对应上。(大小写区别请忽略)
这个DES真的写的头疼,主要原因是自己是真菜,应该多借鉴一下大佬作品,而不是闭门造车。
完整代码
同时也会上传到github上,有兴趣来玩呀。
# 初始密钥:64位(8字节) 有效密钥:56位(7字节) 明文:64位的倍数(8字节) IP_table = [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] # 子密钥集合 K_final = [] IP_1 = [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, ] PC_1 = [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_C = [[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_D = [[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 = [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 = [ [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], [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], [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], [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], [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], [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], [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], [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盒 P = [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, ] E = [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] # 字符串变成二进制流一维数组 def str_to_bin(a): S = a.encode("utf-8").hex() # 转换成16进制ASCII,两位一个字符 z = [0] * 4 * len(S) # 最终存放数组 for i in range(len(S)): x = bin(int(S[i]))[2:].rjust(4, "0") # 转换成4位二进制形式字符串 for j in range(4): z[i * 4 + j] = x[j] return z # 初始置换IP def Exchagne_IP(M): x = [0] * len(M) for i in range(len(IP_table)): x[i] = M[IP_table[i] - 1] # print(x) L = [0] * (len(M) // 2) R = [0] * (len(M) // 2) for i in range(len(L)): L[i] = x[i] for i in range(len(R)): R[i] = x[i + len(L)] return L, R # 循环左移 def rol(C0, D0, num): # C0,D0是32位长度一位数组 rol_num = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1] # 循环次数数组,从0开始 C1 = C0 D1 = D0 for i in range(rol_num[num]): x = C1[0] y = D1[0] for j in range(len(C0) - 1): C1[j] = C1[j + 1] D1[j] = D1[j + 1] C1[len(C1) - 1] = x D1[len(D1) - 1] = y return C0, D0 # PC-2扩展,并且直接放到子密钥表中 def Change_With_PC2(CI, DI): K = [0] * (len(CI) * 2) # 先合并放到K中,一位数组 for i in range(len(K)): if i < len(CI): K[i] = CI[i] else: K[i] = DI[i - len(CI)] K1 = [0] * 48 # PC-2置换 for i in range(48): K1[i] = K[PC_2[i] - 1] # 放到总的K子密钥数组中 K_final.append(K1) # 生成子密钥总函数 def Create_FINAL_KEY(C0, D0): CI = C0 DI = D0 for i in range(16): # 0~15 CI, DI = rol(CI, DI, i) # 循环左移 对 Change_With_PC2(CI, DI) # # 密钥扩展 def Enlarge_Key(K): K1 = [] D0 = [] C0 = [] t = 0 # 置换选择1 for i in range(len(PC_1)): K1.append(K[PC_1[i] - 1]) # 形成C0,D0 for i in range(28): C0.append(K1[i]) for i in range(28): D0.append(K1[i + 28]) Create_FINAL_KEY(C0, D0) # 扩展置换 def E_Exchange(R): x = [0] * len(E) for i in range(len(E)): x[i] = R[E[i] - 1] return x # 实现字符异或 def chr_xor(a, b): if (a == '1' and b == '1') or (a == '0' and b == '0'): return '0' elif (a == '1' and b == '0') or (a == '0' and b == '1'): return '1' else: print("chr_xor num is not 0,1") return '0' # 两个长度相等的字符串的异或(两个一维数组的异或) def func_xor(x1, x2): if len(x1) != len(x2): print("xor:输入字符串长度不等") else: res = [0] * len(x1) for i in range(len(x1)): res[i] = chr_xor(x1[i], x2[i]) # 逐个字符异或 return res # S盒置换 def S_Exchange(input): # 输入是 res = [] s_num = 0 # S盒的编号 # print("S盒16进制:",end = '') for i in range(0, len(input), 6): temp = input[i:i + 6] # 先把当前切片拿出来 x = int(temp[0] + temp[5], 2) # 行 y = int(temp[1] + temp[2] + temp[3] + temp[4], 2) # 列 out = bin(S[s_num][16 * x + y])[2:].rjust(4, "0") # 查表,输出四位二进制字符串 # print(S[s_num][16 * x + y],end=' ') s_num += 1 for j in range(4): # 四位二进制数字符串放进结果,共32位 res.append(out[j]) return res # P盒置换 def P_Exchange(input): # 32位输入 res = [0] * len(P) for i in range(len(P)): res[i] = input[P[i] - 1] return res # f函数 def f(R, num): # num从0~15 x1 = E_Exchange(R) # 扩展置换 x2 = func_xor(x1, K_final[num]) # 异或 # print("Xor", binarray_to_str(x2)) x3 = S_Exchange(x2) # 48位一维数组进入S盒 # print() # print("S: ", binarray_to_str(x3)) x4 = P_Exchange(x3) # 32位一维数组进入P盒 return x4 # IP-1逆置换 def Exchange_IP_1(input): if len(input) != 64: print("len_input is not 64!") return 0 else: res = [] for i in range(len(IP_1)): res.append(input[IP_1[i] - 1]) return res # 二进制一位数组转换成0.1字符串 def binarray_to_str(input): res = '' for i in range(len(input)): res += input[i] return res # 二进制转换成16进制输出 def bin_to_hex(input): a = binarray_to_str(input) res = '' for i in range(0, len(input), 4): temp = a[i:i + 4] # 取当前 res += hex(int(temp, 2))[2:] return res # 16进制字符串转成二进制一位数组 def hex_to_bin(input): res = [] for i in range(len(input)): # 取一位数据,生成4位二进制 a = bin(int(input[i], 16))[2:].rjust(4, "0") for j in range(4): res.append(a[j]) return res # AES加密 def DES_encrypt(M, K): # 明文字符串,密文字符串,加密结果 # M0 = str_to_bin(M) #√ # K0 = str_to_bin(K) #√ # M = hex_to_bin(M) # K = hex_to_bin(K) L, R = Exchagne_IP(M) # 初始置换,得到L0,R0 #√ # print(bin_to_hex(L+R)) Enlarge_Key(K) # 扩展密钥,直接生成子密钥集合 # for i in range(16): # print(bin_to_hex(K_final[i])) # print(K_final) # 0~14 轮,共前15轮, 最后一轮外面写 for i in range(15): temp = R # 给temp,到时候赋给new_L after_f = f(R, i) # 进入F函数 R = func_xor(L, after_f) # 出来异或 L = temp # R给L # print("ROUND",i,end=' : ') # print(bin_to_hex(L),end=' ') # print(bin_to_hex(R)) # 第16轮 R_final = R after_f = f(R, 15) L_final = func_xor(L, after_f) # IP逆盒 res_bin = Exchange_IP_1(L_final + R_final) res_fianl = bin_to_hex(res_bin) # 16进制输出 # res_fianl = binarray_to_str(res_bin) return res_fianl def DES_decrypt(enc, K): # print(enc) # enc1 = hex_to_bin(enc) # 变成0-1数组 # K = hex_to_bin(K) # print(enc1) Enlarge_Key(K) new_L, new_R = Exchagne_IP(enc) for i in range(15, 0, -1): # 15~1 temp = new_R new_R = func_xor(new_L, f(new_R, i)) new_L = temp final_L = func_xor(new_L, f(new_R, 0)) final_R = new_R final = final_L + final_R res = Exchange_IP_1(final) res = bin_to_hex(res) return res # 检查明文长度,如果小于64,用0补齐,如果大于,切片,返回一个整的一维数组 def check_len_M(M): res = [] if len(M) <= 64: res += M for i in range(64 - len(M)): res.append("0") return res else: t = len(M) % 64 for i in range(64 - t): M.append("0") for i in range(len(M) // 64): res += M[i * 64:i * 64 + 64] return res # 密钥不够64位就补齐64位,返回一位数组 def check_len_K(K): res = K if len(K) > 64: print("error!") return 0 for i in range(64 - len(K)): res += '0' return res # 查看密文是否是64位倍数 def check_len_enc(enc): if len(enc) % 64 != 0: print("enc input wrong!") return 0 # 开始加密 def enc_begin(M, K): M = hex_to_bin(M) K = hex_to_bin(K) M0 = check_len_M(M) K0 = check_len_K(K) res = '' for i in range(len(M0) // 64): # 一维大数组切片,然后加密完拼接 res += DES_encrypt(M0[i * 64:i * 64 + 64], K0) return res # 开始解密 def decry_begin(enc, K): enc1 = hex_to_bin(enc) K1 = hex_to_bin(K) check_len_enc(enc1) K2 = check_len_K(K1) res = '' for i in range(len(enc1) // 64): res += DES_decrypt(enc1[i * 64:i * 64 + 64], K2) return res # main # M = '123456ABCD132536' # 8字节明文 # K = 'AABB09182736CCDD' # 64位密钥 print("plz input your choise") print("1: encrypt by DES") print("2:decrypt by DES") flag = input("") if flag == "1": M = input("plz input your text (hex with 64 bit): ") K = input("plz input your key (hex with 64 bit): ") enc = enc_begin(M, K) print("The Cipher Text(hex) is : ", enc) elif flag == "2": enc = input("plz input your Cipher Text (hex Integer multiples of 64): ") K = input("plz input your key (hex with 64 bit): ") res = decry_begin(enc, K) print("The Plain Text(hex) is : ", res) else: print("wrong!")