密码学实验老师让我们做手算DES加密的课堂解压小游戏,我这么懒怎么可能手算…(于是我悄悄用python了)
回到宿舍又把DES算法仔细研究并独立实现了一遍,经调试验证,每个细节的数据都和课本上给出的样例数据对照无误。
完整的每一步的数据在 张焕国的《密码学引论》第三版的66页,感兴趣的可以自行验证。
import numpy as np """ code by bak """ class DES: # 初始置换表,长度为64 IP_table = np.array([ 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, ]) # 初始置换表的逆置换表,长度为64 IP_table_reverse = np.array([ 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, ]) # f函数中的扩展运算E置换表,长度为48 E_table = np.array([ 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, ]) # f函数中的置换运算P置换表,长度为32 P_table = np.array([ 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, ]) # 8个S盒 S_BOXS = np.array([ [ [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], ] ]) # 子密钥生成算法中的置换选择1的置换表 substitution_table_1 = np.array([ 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, ]) # 子密钥生成算法中的置换选择2的置换表 substitution_table_2 = np.array([ 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, ]) def IP(self, bit64): """ 初始置换 """ return bit64[self.IP_table-1] def IP_reverse(self, bit64): """ 初始置换的逆置换 """ return bit64[self.IP_table_reverse-1] def f(self, R, K): """ 加密函数f,参数R为右32位待加密数据,参数K为本轮48位子密钥 """ def E(bit32): """ 扩展运算,用来32位数据扩展成48位数据以便于后续步骤运算 """ return bit32[self.E_table-1] def xor(bit48_a, bit48_b): """ 逐位异或 """ return np.array([(int(bit_a != bit_b)) for (bit_a, bit_b) in zip(bit48_a, bit48_b)]) def S(bit48): """ S盒置换,将48位输入数据经过8个S盒置换得到32位数据输出 """ bit32_After_Sub = np.ndarray(shape=(32,)) for i in range(0,48, 6): # 48位数据每6位分成一组,共分成了8组 bit6 = bit48[i:i+6] # 每一组的6位数据的第1、6比特组成行号 row_index = int("".join(map(str, bit6[[0,5]])), base=2) # 每一组的6位数据的第2、3、4、5比特组成列号 col_index = int("".join(map(str, bit6[[1,2,3,4]])), base=2) # 在当前组对应的那个S盒中依据行号列号取得对应数字 num_selected = self.S_BOXS[i//6][row_index][col_index] # 将取得数字(该数字小于16)转化为4比特保存到输出结果向量 bit4 = np.array([(num_selected&(1<<i))>>i for i in range(4)]) bit4 = bit4[::-1] bit32_After_Sub[(i//6)*4:(i//6)*4+4] = bit4 # 48位输入已经转成32位输出 return bit32_After_Sub def P(bit32): """ 置换运算P,将输入32数据打乱重排得到32位数据输出 """ return bit32[self.P_table-1] # 输入32位数据经过扩展得到48位输出 bit48 = E(R) # 得到的48位结果与48位子密钥逐位异或 bit48 = xor(bit48, K) # print(f"key xor {bit48}") # 得到的48位结果送入S盒中替换得到32位输出 bit32 = S(bit48) # print(f"after S {bit32}") # 得到的32位数据经过选择重排得到32位输出 output_bit32 = P(bit32) # print(f"after P {output}") return output_bit32.astype(np.int32) def key_generator(self, init_key_bit64): """ 子密钥生成算法,依据给定64位初始密钥生成16个48位子密钥 """ # 循环左移位数表 shift_table = [1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1] # 置换选择1 bit56 = init_key_bit64[self.substitution_table_1-1] # 取得 C0, D0 C, D = bit56[:28], bit56[28:] for i in range(16): # 按照循环左移位数表取得当前应该位移的位数 shift = shift_table[i] # C和D循环左移对应位数 C = np.concatenate([C[shift:], C[:shift]]) D = np.concatenate([D[shift:], D[:shift]]) # 拼接C、D bit56 = np.concatenate([C, D]) # 置换选择2 sub_key_bit48 = bit56[self.substitution_table_2-1] # 输出 yield sub_key_bit48 def encrypt_bit64(self, data_bit64, init_key_bit64): """ 应用DES算法加密64比特数据,参数init_key_bit64为指定的64位初始密钥 """ def xor(bit32_a, bit32_b): """ 逐位异或 """ return np.array([int(bit_a != bit_b) for (bit_a, bit_b) in zip(bit32_a, bit32_b)]) # 初始置换 bit64_After_IP = self.IP(data_bit64) # print(bit64_After_IP) # 取得L0, R0 L, R = bit64_After_IP[:32], bit64_After_IP[32:] # print(f"L0 {''.join(map(str, L))}") # print(f"R0 {''.join(map(str, R))}") # 取得本轮子密钥并进行加密迭代 for i, key in enumerate(self.key_generator(init_key_bit64)): if not i==16-1: L, R = R, xor(L, self.f(R, key)) else: # 按照DES规定,最后一轮不需要L、R不互换 R, L = R, xor(L, self.f(R, key)) # print(f"L{i+1} {L}") # print(f"R{i+1} {R}") # 拼接L、R bit64 = np.concatenate([L, R]) # 初始置换的逆置换 output = self.IP_reverse(bit64) # print(f"IP reverse {output}") # 加密完成,输出 return output def decrypt_bit64(self, data_bit64_encrypted, init_key_bit64): """ 应用DES算法解密64比特数据,参数init_key_bit64为指定的64位初始密钥 """ def xor(bit32_a, bit32_b): return np.array([int(bit_a != bit_b) for (bit_a, bit_b) in zip(bit32_a, bit32_b)]) bit64_After_IP = self.IP(data_bit64_encrypted) # print(bit64_After_IP) L, R = bit64_After_IP[:32], bit64_After_IP[32:] # print(f"L0 {''.join(map(str, L))}") # print(f"R0 {''.join(map(str, R))}") # DES的解密相对于加密来说唯一的区别就是子密钥生成的顺序倒过来了 for i, key in enumerate(list(self.key_generator(init_key_bit64))[::-1]): if not i==16-1: L, R = R, xor(L, self.f(R, key)) else: R, L = R, xor(L, self.f(R, key)) # print(f"L{i+1} {L}") # print(f"R{i+1} {R}") bit64 = np.concatenate([L, R]) output = self.IP_reverse(bit64) # print(f"IP reverse {output}") return output if __name__ == "__main__": data_bit64 = np.array(list(map(int, "00110000 00110001 00110010 00110011 00110100 00110101 00110110 00110111".replace(" ", "")))) key_bit64 = np.array(list(map(int, "00110001 00110010 00110011 00110100 00110101 00110110 00110111 00111000".replace(" ", "")))) des = DES() data_bit64_encrypted = des.encrypt_bit64(data_bit64, key_bit64) print(data_bit64_encrypted) data_bit64_decrypted = des.decrypt_bit64(data_bit64_encrypted, key_bit64) print(data_bit64_decrypted)