DES加密原理及python脚本

一、加密

1、秘钥处理

​ DES算法会先对64位密钥进行处理生成48位子密钥后再参与到算法的轮操作中,在每一轮的迭代过程中,使用不同的子密钥。其中的处理包括置换选择、循环左移、压缩置换。

1.1 置换选择

DES秘钥有64位,其中每8位有一个校验位,所以有56位的子密钥。根据下表生成56位密钥,并将置换后的56位密钥分成两部分C0和D0,每部分28位:

注意:这里的数字表示的是原数据的位置,不是数据,例:把第57位放在第1位

 

# 置换函数,用于密钥置换、IP置换、P置换等
    def __substitution(self, table: str, self_table: list) -> str:
        """
        :param table: 需要进行置换的列表,是一个01字符串
        :param self_table: 置换表,在__init__中初始化了
        :return: 返回置换后的01字符串
        """
        sub_result = ""
        for i in self_table:
            sub_result += table[i - 1]
        return sub_result

# 返回加密过程中16轮的子密钥
    def __get_key_list(self):
        """
        :return: 返回加密过程中16轮的子密钥
        """
        key = self.__substitution(self.K, self.k1)  # 置换
        left_key = key[0:28]
        right_key = key[28:56]
        keys = []
        for i in range(1, 17):     # 循环左移
            move = self.k0[i - 1]
            move_left = left_key[move:28] + left_key[0:move]
            move_right = right_key[move:28] + right_key[0:move]
            left_key = move_left
            right_key = move_right
            move_key = left_key + right_key
            ki = self.__substitution(move_key, self.k2)  #  压缩置换
            keys.append(ki)
        return keys
    def key_conversion(self, key):
        """
        将64位原始密钥转换为56位的密钥,并进行一次置换
        """
        first_key = key
        key_replace_table = (
            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
        )
        return self.replace_block(first_key, key_replace_table)

1.2 循环左移

​ 将C0和D0进行循环左移变化(注:每轮循环左移的位数由轮数决定(如下图)),变换后生成C1和D1,然后C1和D1合并。

    def spin_key(self, key: str):
        """
        旋转获得子密钥
        """
        kc = self.key_conversion(key)
        first, second = kc[0: 28], kc[28: 56]
        spin_table = (1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28)
        for i in range(1, 17):
            first_after_spin = first[spin_table[i - 1]:] + first[:spin_table[i - 1]]
            second_after_spin = second[spin_table[i - 1]:] + second[:spin_table[i - 1]]
            print(f"旋转后的key: left: {first_after_spin}, right: {second_after_spin}")
            yield first_after_spin + second_after_spin

1.3 压缩置换

移动后,从56位中选出48位。这个过程中,既置换了每位的顺序,又选择了子密钥,因此称为压缩置换。压缩置换规则如PC-2表(注意表中没有9,18,22,25,35,38,43和54这8位)

​ 压缩置换后的48位子密钥将参与到轮操作中,而C1、D1也将再进行左移和置换后得到下一轮的子密钥。

    def key_selection_replacement(self, key: str):
        """
        通过选择置换得到48位的子密钥
        """
        key_select_table = (
            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
        )
        for child_key56 in self.spin_key(key):
            self.child_keys.append(self.replace_block(child_key56, key_select_table))
# 置换函数,用于密钥置换、IP置换、P置换等
    def __substitution(self, table: str, self_table: list) -> str:
        """
        :param table: 需要进行置换的列表,是一个01字符串
        :param self_table: 置换表,在__init__中初始化了
        :return: 返回置换后的01字符串
        """
        sub_result = ""
        for i in self_table:
            sub_result += table[i - 1]
        return sub_result

# 返回加密过程中16轮的子密钥
    def __get_key_list(self):
        """
        :return: 返回加密过程中16轮的子密钥
        """
        key = self.__substitution(self.K, self.k1)  # 置换
        left_key = key[0:28]
        right_key = key[28:56]
        keys = []
        for i in range(1, 17):     # 循环左移
            move = self.k0[i - 1]
            move_left = left_key[move:28] + left_key[0:move]
            move_right = right_key[move:28] + right_key[0:move]
            left_key = move_left
            right_key = move_right
            move_key = left_key + right_key
            ki = self.__substitution(move_key, self.k2)  #  压缩置换
            keys.append(ki)
        return keys

2.明文处理

2.1 将明文变为二进制

将字符串的明文转换为二进制,按64位一组,分成若干组,如果不够64位,就补零。

    from bitarray import bitarray
    
    @staticmethod
    def _bit_encode(s: str) -> str:
        """
        将字符串转换为01字符串的形式
        """
        return bitarray(
            ''.join([bin(int('1' + hex(c)[2:], 16))[3:]
                     for c in s.encode('utf-8')])).to01()
    
    def processing_encode_input(self, enter: str) -> list:
        """
        将输入的字符串转换为二进制形式,并没64位为一组进行分割
        """
        result = []
        bit_string = self._bit_encode(enter)
        # 如果长度不能被64整除,就补零
        if len(bit_string) % 64 != 0:
            for i in range(64 - len(bit_string) % 64):
                bit_string += '0'
        for i in range(len(bit_string) // 64):
            result.append(bit_string[i * 64: i * 64 + 64])
        # print(f"转换为二进制后的初始明文: {result}")
        return result

2.2 置换IP

 IP置换目的是将输入的64位明文M按位重新组合,并把输出分为L0、R0两部分,每部分各长32位。置换规则如下表所示:

    @staticmethod
    def replace_block(block: str, replace_table: tuple) -> str:
        """
        对单个块进行置换
        Args:
            block: str, 要进行转换的64位长的01字符串
            replace_table: 转换表
        Return:
            返回转换后的字符串
        """
        result = ""
        for i in replace_table:
            try:
                result += block[i - 1]
            except IndexError:
                print(i)
                print(f"block= {block}, len={len(block)}")
                raise
        return result
    
    def _init_replace_block(self, block: str):
        """
        对一个块进行初态置换
        """
        replace_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
        )
        return self.replace_block(block, replace_table)

2.3 16轮轮函数

每一轮循环加密的过程为:

  1. 将初态置换后或上一次循环后得到的各32位的子块Left和Right
  2. Right经过f函数转换后得到一个32位的串,这个串与Left做异或后得到下一轮循环的Right
  3. 将这一轮原视的Right作为下一轮的Left
  4. 拼接Left和Right,进行下一轮循环
    def iteration(self, block: str, key: str) -> str:
        for i in range(16):
            # 分成左右两个子块
            left, right = block[0: 32], block[32: 64]
            # 将这一轮原视的Right作为下一轮的Left
            next_left = right
            # f函数
            f_result = self._f_function(right, i)
            # f函数的输出与left做异或得到下一轮的right
            right = self._not_or(left, f_result)
            # 拼接,准备进行下一轮
            block = next_left + right
        return block[32:] + block[:32]
2.3.1 扩展置换

将一个32位的串根据【拓展置换表】转换为48位,具体就是将32位的数据分成4*8小块,每个小块拓展为6位。

拓展置换表中,每一行代表拓展后的一个小块,内部数字表示原来子块中01的位置,其实就是在每一个小块前面加上前一个小块的最后一个字符,后面加上下一个小块的第一个字符。

扩展置换目的有两个:生成与密钥相同长度的数据以进行异或运算;提供更长的结果,在后续的替代运算中可以进行压缩。

    @staticmethod
    def block_extend(block: str) -> str:
        """
        拓展置换
        """
        extended_block = ""
        extend_table = (
            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
        )
        for i in extend_table:
            extended_block += block[i - 1]
        return extended_block

扩展置换之后,右半部分R0变为48位,与子密钥进行异或操作。

2.3.2 S盒置换

   1.扩展置换之后,右半部分R0变为48位,与子密钥进行异或操作。

   2.将48位分为8组,每组6位,然后将第一位和第六位合在一起换算为十进制数H,中间六位换算为十进制数L,然后用S盒中H行L列的4位二进制数置换初始的6位,总共有8个S盒。意思就是,8组6位通过8个S盒变为8组4位。

    def _s_box_replace(self, block48: str) -> str:
        """
        S盒置换,将48位的输入转换为32位输出
        """
        s_box_table = (
            (
                (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),
            )
        )
        result = ""
        for i in range(8):
            row_bit = (block48[i * 6] + block48[i * 6 + 5]).encode("utf-8")
            line_bit = (block48[i * 6 + 1: i * 6 + 5]).encode("utf-8")
            row = int(row_bit, 2)
            line = int(line_bit, 2)
            # print(f"第{row}行, 第{line}列")
            data = s_box_table[i][row][line]
            no_full = str(bin(data))[2:]
            while len(no_full) < 4:
                no_full = '0' + no_full
            result += no_full
        return result
2.3.3 P盒置换

使用P盒置换表进行混淆

    def p_box_replacement(self, block32: str) -> str:
        """
        P盒置换
        Return:
            返回经过P盒置换后的32位01串
        """
        p_box_replace_table = (
            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,
        )
        return self.replace_block(block32, p_box_replace_table)

2.4 IP逆置换

与初态置换表不一样

    def _end_replace_block(self, block: str) -> str:
        """
        对某一个块进行终态转换
        """
        replace_table = (
            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
        )
        return self.replace_block(block, replace_table)

二、解密

解密使用与加密相同的算法,只不过使用子密钥的顺序不同而已,加密过程第一轮循环使用key1 解密过程第一轮循环使用key16,可以在循环加密处添加一个标志位完成.

三、python脚本

import binascii


class ArrangeSimpleDES():
    def __init__(self):
        # 出初始化DES加密的参数
        self.ip = [
            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置换

        self.ip1 = [
            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,
        ]  # 逆ip置换
        self.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,
        ]  # E置换(扩展置换),将32位明文置换位48位
        self.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,
        ]  # P置换,对经过S盒之后的数据再次进行置换

        # 设置默认密钥
        self.K = '0111010001101000011010010111001101101001011100110110100101110110'
        self.k1 = [
            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,
        ]  # 密钥的K1初始置换

        self.k2 = [
            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,
        ]

        self.k0 = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, ]  # 秘钥循环移位的位数

        self.S = [
            [
                0xe, 0x4, 0xd, 0x1, 0x2, 0xf, 0xb, 0x8, 0x3, 0xa, 0x6, 0xc, 0x5, 0x9, 0x0, 0x7,
                0x0, 0xf, 0x7, 0x4, 0xe, 0x2, 0xd, 0x1, 0xa, 0x6, 0xc, 0xb, 0x9, 0x5, 0x3, 0x8,
                0x4, 0x1, 0xe, 0x8, 0xd, 0x6, 0x2, 0xb, 0xf, 0xc, 0x9, 0x7, 0x3, 0xa, 0x5, 0x0,
                0xf, 0xc, 0x8, 0x2, 0x4, 0x9, 0x1, 0x7, 0x5, 0xb, 0x3, 0xe, 0xa, 0x0, 0x6, 0xd,
            ],
            [
                0xf, 0x1, 0x8, 0xe, 0x6, 0xb, 0x3, 0x4, 0x9, 0x7, 0x2, 0xd, 0xc, 0x0, 0x5, 0xa,
                0x3, 0xd, 0x4, 0x7, 0xf, 0x2, 0x8, 0xe, 0xc, 0x0, 0x1, 0xa, 0x6, 0x9, 0xb, 0x5,
                0x0, 0xe, 0x7, 0xb, 0xa, 0x4, 0xd, 0x1, 0x5, 0x8, 0xc, 0x6, 0x9, 0x3, 0x2, 0xf,
                0xd, 0x8, 0xa, 0x1, 0x3, 0xf, 0x4, 0x2, 0xb, 0x6, 0x7, 0xc, 0x0, 0x5, 0xe, 0x9,
            ],
            [
                0xa, 0x0, 0x9, 0xe, 0x6, 0x3, 0xf, 0x5, 0x1, 0xd, 0xc, 0x7, 0xb, 0x4, 0x2, 0x8,
                0xd, 0x7, 0x0, 0x9, 0x3, 0x4, 0x6, 0xa, 0x2, 0x8, 0x5, 0xe, 0xc, 0xb, 0xf, 0x1,
                0xd, 0x6, 0x4, 0x9, 0x8, 0xf, 0x3, 0x0, 0xb, 0x1, 0x2, 0xc, 0x5, 0xa, 0xe, 0x7,
                0x1, 0xa, 0xd, 0x0, 0x6, 0x9, 0x8, 0x7, 0x4, 0xf, 0xe, 0x3, 0xb, 0x5, 0x2, 0xc,
            ],
            [
                0x7, 0xd, 0xe, 0x3, 0x0, 0x6, 0x9, 0xa, 0x1, 0x2, 0x8, 0x5, 0xb, 0xc, 0x4, 0xf,
                0xd, 0x8, 0xb, 0x5, 0x6, 0xf, 0x0, 0x3, 0x4, 0x7, 0x2, 0xc, 0x1, 0xa, 0xe, 0x9,
                0xa, 0x6, 0x9, 0x0, 0xc, 0xb, 0x7, 0xd, 0xf, 0x1, 0x3, 0xe, 0x5, 0x2, 0x8, 0x4,
                0x3, 0xf, 0x0, 0x6, 0xa, 0x1, 0xd, 0x8, 0x9, 0x4, 0x5, 0xb, 0xc, 0x7, 0x2, 0xe,
            ],
            [
                0x2, 0xc, 0x4, 0x1, 0x7, 0xa, 0xb, 0x6, 0x8, 0x5, 0x3, 0xf, 0xd, 0x0, 0xe, 0x9,
                0xe, 0xb, 0x2, 0xc, 0x4, 0x7, 0xd, 0x1, 0x5, 0x0, 0xf, 0xa, 0x3, 0x9, 0x8, 0x6,
                0x4, 0x2, 0x1, 0xb, 0xa, 0xd, 0x7, 0x8, 0xf, 0x9, 0xc, 0x5, 0x6, 0x3, 0x0, 0xe,
                0xb, 0x8, 0xc, 0x7, 0x1, 0xe, 0x2, 0xd, 0x6, 0xf, 0x0, 0x9, 0xa, 0x4, 0x5, 0x3,
            ],
            [
                0xc, 0x1, 0xa, 0xf, 0x9, 0x2, 0x6, 0x8, 0x0, 0xd, 0x3, 0x4, 0xe, 0x7, 0x5, 0xb,
                0xa, 0xf, 0x4, 0x2, 0x7, 0xc, 0x9, 0x5, 0x6, 0x1, 0xd, 0xe, 0x0, 0xb, 0x3, 0x8,
                0x9, 0xe, 0xf, 0x5, 0x2, 0x8, 0xc, 0x3, 0x7, 0x0, 0x4, 0xa, 0x1, 0xd, 0xb, 0x6,
                0x4, 0x3, 0x2, 0xc, 0x9, 0x5, 0xf, 0xa, 0xb, 0xe, 0x1, 0x7, 0x6, 0x0, 0x8, 0xd,
            ],
            [
                0x4, 0xb, 0x2, 0xe, 0xf, 0x0, 0x8, 0xd, 0x3, 0xc, 0x9, 0x7, 0x5, 0xa, 0x6, 0x1,
                0xd, 0x0, 0xb, 0x7, 0x4, 0x9, 0x1, 0xa, 0xe, 0x3, 0x5, 0xc, 0x2, 0xf, 0x8, 0x6,
                0x1, 0x4, 0xb, 0xd, 0xc, 0x3, 0x7, 0xe, 0xa, 0xf, 0x6, 0x8, 0x0, 0x5, 0x9, 0x2,
                0x6, 0xb, 0xd, 0x8, 0x1, 0x4, 0xa, 0x7, 0x9, 0x5, 0x0, 0xf, 0xe, 0x2, 0x3, 0xc,
            ],
            [
                0xd, 0x2, 0x8, 0x4, 0x6, 0xf, 0xb, 0x1, 0xa, 0x9, 0x3, 0xe, 0x5, 0x0, 0xc, 0x7,
                0x1, 0xf, 0xd, 0x8, 0xa, 0x3, 0x7, 0x4, 0xc, 0x5, 0x6, 0xb, 0x0, 0xe, 0x9, 0x2,
                0x7, 0xb, 0x4, 0x1, 0x9, 0xc, 0xe, 0x2, 0x0, 0x6, 0xa, 0xd, 0xf, 0x3, 0x5, 0x8,
                0x2, 0x1, 0xe, 0x7, 0x4, 0xa, 0x8, 0xd, 0xf, 0xc, 0x9, 0x0, 0x3, 0x5, 0x6, 0xb,
            ],
        ]  # 16进制表示S盒的数据,S盒是为了将48位转换为32位,有8个盒子

    # 置换函数,用于密钥置换、IP置换、P置换等
    def __substitution(self, table: str, self_table: list) -> str:
        """
        :param table: 需要进行置换的列表,是一个01字符串
        :param self_table: 置换表,在__init__中初始化了
        :return: 返回置换后的01字符串
        """
        sub_result = ""
        for i in self_table:
            sub_result += table[i - 1]
        return sub_result

    # 将明文转化为二进制字符串
    def str2bin(self, string: str) -> str:
        """
        将明文转为二进制字符串:
        :param string: 任意字符串
        :return:二进制字符串
        """
        plaintext_list = list(bytes(string, 'utf8'))  # 将字符串转成bytes类型,再转成list
        result = []  # 定义返回结果
        for num in plaintext_list:
            result.append(bin(num)[2:].zfill(8))  # 将列表的每个元素转成二进制字符串,8位宽度;zfill(x),不足x位,左侧填充0
        return "".join(result)  # 连起来

    # 二进制字符串转化为字符串
    def bin2str(self, binary: str) -> str:
        """
        二进制字符串转成字符串
        :param binary:
        :return:
        """
        list_bin = [binary[i:i + 8] for i in range(0, len(binary), 8)]  # 对二进制字符串进行切分,每8位为一组
        list_int = []
        for b in list_bin:
            list_int.append(int(b, 2))  # 对二进制转成int
        result = bytes(list_int).decode()  # 将列表转成bytes,在进行解码,得到字符串
        return result

    # 由于加密之后的二进制无法直接转成字符,有不可见字符在,utf8可能无法解码,所以需要将二进制字符串每8位转成int型号列表,用于转成bytes再转hex
    def __bin2int(self, binary: str) -> list:
        """
        由于加密之后的二进制无法直接转成字符,有不可见字符在,utf8可能无法解码,所以需要将二进制字符串每8位转成int型号列表,用于转成bytes再转hex
        :param binary: 二进制字符串
        :return: int型列表
        """
        list_bin = [binary[i:i + 8] for i in range(0, len(binary), 8)]  # 对二进制字符串进行切分,每8位为一组
        list_int = []
        for b in list_bin:
            list_int.append(int(b, 2))
        return list_int

    # 将int类型的列表转成二进制串
    def __int2bin(self, list_int: list) -> str:
        result = []
        for num in list_int:
            result.append(bin(num)[2:].zfill(8))
        return ''.join(result)

    def __get_block_list(self, binary: str) -> list:
        """
        对明文二进制串进行切分,每64位为一块,DES加密以64位为一组进行加密的
        :type binary: 二进制串
        """
        len_binary = len(binary)
        if len_binary % 64 != 0:
            binary_block = binary + ("0" * (64 - (len_binary % 64)))
            return [binary_block[i:i + 64] for i in range(0, len(binary_block), 64)]
        else:
            return [binary[j:j + 64] for j in range(0, len(binary), 64)]

    # 修改默认密钥函数
    def modify_secretkey(self):
        """
        修改默认密钥函数
        :return: None
        """
        print('当前二进制形式密钥为:{}'.format(self.K))
        print("当前字符串形式密钥为:{}".format(self.bin2str(self.K)))
        newkey = input("输入新的密钥(长度为8):")
        if len(newkey) != 8:
            print("密钥长度不符合,请重新输入:")
            self.modify_secretkey()
        else:
            bin_key = self.str2bin(newkey)
            self.K = bin_key
            print("当前二进制形式密钥为:{}".format(self.K))
# F函数,right加密过程中的右半部分,key表示参与的子密钥。函数实现:对right进行E扩展,与key 进行异或操作,进入S盒替代,进行P置换,返回
    def __f_funtion(self, right: str, key: str):
        """
        :param right: 明文二进制的字符串加密过程的右半段
        :param key: 当前轮数的密钥
        :return: 进行E扩展,与key异或操作,S盒操作后返回32位01字符串
        """
        # 对right进行E扩展
        e_result = self.__substitution(right, self.E)
        # 与key 进行异或操作
        xor_result = self.__xor_function(e_result, key)
        # 进入S盒子
        s_result = self.__s_box(xor_result)
        # 进行P置换
        p_result = self.__substitution(s_result, self.P)
        return p_result
# 返回加密过程中16轮的子密钥
    def __get_key_list(self):
        """
        :return: 返回加密过程中16轮的子密钥
        """
        key = self.__substitution(self.K, self.k1)
        left_key = key[0:28]
        right_key = key[28:56]
        keys = []
        for i in range(1, 17):
            move = self.k0[i - 1]
            move_left = left_key[move:28] + left_key[0:move]
            move_right = right_key[move:28] + right_key[0:move]
            left_key = move_left
            right_key = move_right
            move_key = left_key + right_key
            ki = self.__substitution(move_key, self.k2)
            keys.append(ki)
        return keys
# 异或操作返回结果
    def __xor_function(self, xor1: str, xor2: str):
        """
        :param xor1: 01字符串
        :param xor2: 01字符串
        :return: 异或操作返回的结果
        """
        size = len(xor1)
        result = ""
        for i in range(0, size):
            result += '0' if xor1[i] == xor2[i] else '1'
        return result
# 进行S盒替代的函数,48位替换为32位
    def __s_box(self, xor_result: str):
        """
        :param xor_result: 48位01字符串
        :return: 返回32位01字符串
        """
        result = ""
        for i in range(0, 8):
            # 将48位数据分为6组,循环进行
            block = xor_result[i * 6:(i + 1) * 6]
            line = int(block[0] + block[5], 2)
            colmn = int(block[1:4], 2)
            res = bin(self.S[i][line * 16 + colmn])[2:]
            if len(res) < 4:
                res = '0' * (4 - len(res)) + res
            result += res
        return result
# 因为右半部分是操作了16轮,所以合并在一起组成一个函数,返回进行F函数以及和left异或操作之后的字符串。
    def __iteration(self, bin_plaintext: str, key_list: list):
        """
        :param bin_plaintext: 01字符串,64位
        :param key_list: 密钥列表,共16个
        :return: 进行F函数以及和left异或操作之后的字符串
        """
        left = bin_plaintext[0:32]
        right = bin_plaintext[32:64]
        for i in range(0, 16):
            next_lift = right
            f_result = self.__f_funtion(right, key_list[i])
            next_right = self.__xor_function(left, f_result)
            left = next_lift
            right = next_right
        bin_plaintext_result = left + right
        return bin_plaintext_result[32:] + bin_plaintext_result[:32]

    def encode(self, plaintext):
        """
        :param plaintext: 明文字符串
        :return: 密文字符串
        """
        # 将字符串变为二进制
        bin_plaintext = self.str2bin(plaintext)
        # 进行分组,64位一组
        bin_plaintext_block = self.__get_block_list(bin_plaintext)
        ciphertext_bin_list = []
        # 获得子密钥
        key_list = self.__get_key_list()
        # 对一组明文进行加密
        for block in bin_plaintext_block:
            # 初代ip置换
            sub_ip = self.__substitution(block, self.ip)
            # 轮加密
            ite_result = self.__iteration(sub_ip, key_list)
            # 逆ip置换
            sub_ip1 = self.__substitution(ite_result, self.ip1)
            ciphertext_bin_list.append(sub_ip1)
        ciphertext_bin = ''.join(ciphertext_bin_list)
        result = self.__bin2int(ciphertext_bin)
        return bytes(result).hex().upper()

    def decode(self, ciphertext):
        '''
        :param ciphertext: 密文字符串
        :return: 明文字符串
        '''
        b_ciphertext = binascii.a2b_hex(ciphertext)
        bin_ciphertext = self.__int2bin(list(b_ciphertext))
        bin_plaintext_list = []
        key_list = self.__get_key_list()
        key_list = key_list[::-1]
        bin_ciphertext_block = [bin_ciphertext[i:i + 64] for i in range(0, len(bin_ciphertext), 64)]
        for block in bin_ciphertext_block:
            sub_ip = self.__substitution(block, self.ip)
            ite = self.__iteration(sub_ip, key_list)
            sub_ip1 = self.__substitution(ite, self.ip1)
            bin_plaintext_list.append(sub_ip1)
        bin_plaintext = ''.join(bin_plaintext_list).replace('00000000', '')
        return self.bin2str(bin_plaintext)

    def main(self):
        select = input("Please selecting:\n1、Encryption\t 2、Decrpytion\nYour selecting:")
        if select == '1':
            plaintext = input("Input plaintext:")
            # print("Your plaintext is:{}".format(plaintext))
            ciphertext = self.encode(plaintext)
            print("The ciphertext is:{}".format(ciphertext))
        elif select == '2':
            plaintext = input("Input ciphertext:")
            # print("Your ciphertext is:{}".format(plaintext))
            plaintext = self.decode(plaintext)
            print("The plaintext is:{}".format(plaintext))
            # print(len(plaintext))
        else:
            input("Please selecting again!")
            self.main()


if __name__ == '__main__':
    mydes = ArrangeSimpleDES()
    mydes.modify_secretkey()
    while True:
        mydes.main()
        print("")
   
  • 9
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值