python手动实现DES算法

密码学实验老师让我们做手算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)



    

上一篇:des 算法


下一篇:uniApp实现swiper和scroll-view联动