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("")
   

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/479762.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[HackMyVM]靶场 XMAS

kali:192.168.56.104 靶机:192.168.56.126 注意在/etc/hosts 添加 192.168.56.126 christmas.hmv # cat /etc/hosts 127.0.0.1 localhost 127.0.1.1 kali2 192.168.223.131 dc-2 192.168.223.134 wordy 192.168.56.105 midn…

【嵌入式开发 Linux 常用命令系列 4.3 -- git add 时单独排除某个目录或者文件】

文章目录 git add 时单独排除某个目录或者文件使用 .gitignore 文件使用命令行排除文件或目录 git add 时单独排除某个目录或者文件 在使用 git add 命令时&#xff0c;如果你想要排除特定的目录或文件&#xff0c;可以使用 .gitignore 文件或使用路径规范来指定不想添加的文件…

智能T0算法交易促进年化收益

T0交易越来越得到普及&#xff0c;越来越多的人在关注T0交易。按照交易主体来看&#xff0c;一种是人工T0交易&#xff0c;另一种是自动化智能T0算法交易。人工T0交易会受制于操作员的计算能力、反应速度以及主观判断等因素的影响&#xff0c;稳定性不如智能自动化T0算法交易。…

搭建自己的博客-拾壹博客

写在前面 唠叨两句 作为一个技术开发人员&#xff0c;没有一个自己的博客&#xff0c;人生注定缺少点什么东西&#xff0c;是不是&#xff1f;最近研究了一些博客搭建&#xff0c;本文是使用开源项目”拾壹博客“进行搭建。 推荐等级 所需技术难度&#xff1a;4星 后续自定义…

GPU云服务器与自建GPU服务器的对比

GPU云服务器是一种基于GPU的计算服务&#xff0c;广泛应用于深度学习、图形图像处理和科学计算等领域。其快速、稳定、灵活的特点使其备受青睐。与标准的CVM云服务器一样&#xff0c;GPU云服务器提供方便快捷的管理方式&#xff0c;通过其强大的计算性能&#xff0c;能够快速处…

直播行业网络安全建设

一、引言 直播行业近年来蓬勃发展&#xff0c;吸引了大量用户和资本的关注。然而&#xff0c;随着行业的壮大&#xff0c;网络安全问题也日益凸显。构建一个安全、稳定的直播行业网络对于保障用户权益、维护行业秩序具有重要意义。本文将详细探讨直播行业安全网络的构建与保障…

zookeeper分布式锁原理剖析

在ZooKeeper的CLI中&#xff0c;create命令用于在指定路径上创建一个新的节点。以下是create命令的参数解释&#xff1a; -s&#xff1a;顺序节点标志。如果指定了该选项&#xff0c;则创建的节点将是顺序节点。顺序节点的名称将以“path”后跟一个连字符和递增的数字序列结尾…

基于python+vue食品安全信息管理系统flask-django-nodejs-php

食品安全信息管理系统设计的目的是为用户提供食品信息、科普专栏、食品检测、检测结果、交流论坛等方面的平台。 与PC端应用程序相比&#xff0c;食品安全信息管理系统的设计主要面向于用户&#xff0c;旨在为管理员和用户提供一个食品安全信息管理系统。用户可以通过APP及时查…

在面对一个大型的代码,需要分文件编写的时候,应该怎么办呢;以及在编写出一个功能时,有人想要买这个功能,怎么在不给出源代码的情况下让买家可以使用这个代码功能呢?

我们一点点来&#xff0c;首先&#xff0c;假设我们要写一个加法功能的实现&#xff0c; 这里是在单个文件里调用函数&#xff0c;实现一个加法的功能&#xff0c; 下面我们把自定义函数放在下面&#xff0c;上面对自定义函数进行一个声明&#xff0c; 下面我们把代码放到多个…

httprunner4详解

httpruuner官方文档:https://httprunner.com/docs/introduction/overview/ 案例1:使用电商开源项目演示: 项目地址:https://github.com/macrozheng/mall 案例2:使用erp2项目演示: 开源项目:http://erp2.hzb-it.com/ 1.Httprunner环境搭建 HttpRunner v4.0 同时采用…

大数据--hdfs--java编程

环境&#xff1a; virtualbox ubantu1604 Linux idea社区版2023 jdk1.8 hadoop相关依赖 使用java操作 1. 判断/user/stu/input/test.txt文件是否存在&#xff0c;存在则读出文件内容&#xff0c;打印在控制台上。反之&#xff0c;输出“文件不存在”。 package abc;impo…

【JS进阶】第二天

JavaScript 进阶 - 第2天 了解面向对象编程的基础概念及构造函数的作用&#xff0c;体会 JavaScript 一切皆对象的语言特征&#xff0c;掌握常见的对象属性和方法的使用。 了解面向对象编程中的一般概念能够基于构造函数创建对象理解 JavaScript 中一切皆对象的语言特征理解引用…

字节跳动面试被拷打:高效处理大量数据的JavaScript技巧

一、文章内容 时间分片宏任务微任务前置内容实现时间分片 二、时间切片 什么是时间切片&#xff1f;通过字面意思我们不难理解时间切片就是将时间分成多个片段进行一一渲染数据,时间切片是个抽象的问题,我们可能会想到JavaScript中window自带的setTimeout的延迟函数或者是 w…

(附源码)基于Spring Boot和Vue的前后端分离考研资料分享平台的设计与实现

前言 &#x1f497;博主介绍&#xff1a;✌专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f447;&#x1f3fb; 精彩专栏 推荐订阅&#x1f447;&#x1f3fb; 2024年Java精品实战案例《100套》 &#x1f345;文末获取源码联系&#x1f345; &#x1f31…

操作符详解(C语言)—第三期

逻辑操作符 逻辑操作符有哪些&#xff1a; && 逻辑与 || 逻辑或区分逻辑与和按位与 区分逻辑或和按位或 1&2----->0 1&&2---->1 1|2----->3 1||2---->1逻辑与和或的特点&#xff1a; 360笔试题 #include <stdio.h&…

乐企数字化电子发票(基础版)开票能力测试报告

能力简介&#xff1a;纳税人销售货物或提供服务时&#xff0c;可以通过本能力开具数电票。 纳税人可将本能力中的各类规则和接口嵌入本单位信息化系统中&#xff08;如&#xff1a;销售、 收款、结算等&#xff09;&#xff0c;实现数电票开具流程和商业行为的融合&#xff0c;…

20240317-2-推荐算法FTRL

FTRL FTRL(Follow the Regularized Leader) 由Google的H. Berendan McMahan 等人于2010年提出【4】,FTRL是一种在线最优化求解算法,结合L1-FOBOS和L1-RDA算法,用于解决在线学习中,权重参数不能产生较好的稀疏性的问题。 由于在线学习涉及内容较多&#xff0c;本文从提升模型稀疏…

吴恩达深度学习笔记:浅层神经网络(Shallow neural networks)3.1-3.5

目录 第一门课&#xff1a;神经网络和深度学习 (Neural Networks and Deep Learning)第三周&#xff1a;浅层神经网络(Shallow neural networks)3.1 神经网络概述&#xff08;Neural Network Overview&#xff09; 第一门课&#xff1a;神经网络和深度学习 (Neural Networks an…

【数据结构与算法】算法复杂度

一、什么是复杂度&#xff1f; 程序执行时需要的计算量和内存空间&#xff0c;其中计算量是指时间复杂度&#xff0c;计算量大则需要时间久&#xff1b;内存空间是指空间复杂度和代码是否简洁无关&#xff0c;而是指计算机的cpu和内存计算复杂程度。 复杂度是数量级&#xff0…

Day43:WEB攻防-PHP应用SQL注入符号拼接请求方法HTTP头JSON编码类

目录 PHP-MYSQL-数据请求类型 PHP-MYSQL-数据请求方法 PHP-MYSQL-数据请求格式 知识点&#xff1a; 1、PHP-MYSQL-SQL注入-数据请求类型 2、PHP-MYSQL-SQL注入-数据请求方法 3、PHP-MYSQL-SQL注入-数据请求格式 PHP-MYSQL-数据请求类型 SQL语句由于在黑盒中是无法预知写法的…