DES加密

发布时间 2023-10-22 21:13:25作者: skdtxdy

DES加密简介


DES加密算法是对称密钥加密算法、分组加密算法

DES(Data Encryption Standard,数据加密标准)的出现是现代密码发展史上的一个非常重要的事件,它是密码学历史上第一个广泛应用于商用数据保密的密码算法,开创了公开密码算法、公开竞选密码算法的先例,极大地促进了密码学的发展。尽管AES取代它成为新的数据加密标准,但使用诸如3重DES等方法加强DES密钥强度仍然不失为一个安全的密码系统。因此,DES算法的基本理论和设计思想仍有重要的参考价值。

在国内,DES在POS、ATM、磁卡以及智能卡、高速公路收费站等领域有广泛的应用,如信用卡持卡人的PIN加密传输,IC卡与POS之间的双向认证、金融交易数据包的MAC校验等等。

DES的加密和解密使用的是同一算法,安全性依赖于所用的密钥。DES算法仅使用最大为64比特的标准算术和逻辑运算,运算速度快,密钥产生容易,适合于在计算机上软件实现或专用芯片实现。

曾经在其时间内提供了相对较高的安全性,但由于密钥长度受限以及密码分析技术的进步,它已经不再被认为足够安全,在现代通信和数据安全领域不再广泛使用。

主要特点如下:

  1. 分组加密
    DES采用固定的64位数据块进行加密,需要将数据划分成特定大小的块进行处理。

  2. 对称密钥加密
    DES采用相同的密钥进行加密和解密操作,密钥长度为56位,实际用于加密的位数为48位。

  3. 多种混淆
    采用多种替代和置换操作,包括初始置换、轮函数、扩展置换、S-盒替代和P-盒置换,以混淆和替换数据块中的位。

  4. 轮函数
    DES包括16轮轮函数,每一轮都使用不同的子密钥对数据块进行变换,增加算法的复杂性和安全性。

  5. 密钥长度较小
    DES的密钥长度相对较小(56bit),导致容易受到暴力破解攻击。DES的密钥长度为56位。密钥实际长度为64位,但第8、16、24、40、48、56和64位为奇偶校验位,故使用时的实际有效长度为56位。虽然密钥空间包含2^56种不同的密钥组合,但随着计算能力的增强,暴力破解攻击变得更加可行。现代计算机可以以很高的速度尝试不同的密钥组合,因此56位密钥的保护已经不足以抵御强大的计算资源。


DES加密基本原理

基本流程


DES的基本流程图如下图所示:

其中IP置换后直接将数据从中间一分为二得到\(L_0\)\(R_0\)(64bit变为32bit),在最后将\(R_{16}\)\(L_{16}\)首尾相接得到数据再进行IP逆置换(32bit变为64bit)。


初始置换IP表如下图

逆初始置换表如下图

轮函数


轮函数是对称密钥加密算法中的一个关键组成部分,用于将输入数据转化为输出数据。这里我将详细介绍轮函数的原理以及每一步的操作方法:

  1. 扩展置换
    • 原理:扩大数据块的大小,增加数据的复杂性,从而提高密码的安全性。将输入数据的某些位复制,将输入数据块(32bit)扩展为48位。使密文的每一位更加依赖明文和密钥的每一位,实现了扩散原则。

    • 操作方法:输入数据块中的每一位根据一个预定义的置换表(EXPANSION)被复制和重新排列,生成一个更大的数据块(48位)。这个置换表定义了每个输入位应该被复制到扩展数据块的哪个位置,以及是否需要重复。

    • EXPANSION表如下图

    • 扩展示意图

  1. 子密钥异或

    • 原理:初始密钥经过一系列操作生成一组轮密钥,每轮使用一个不同的轮密钥,一共有16个轮密钥,分别用于16轮加密。在每轮中,扩展置换后的数据与对应轮的轮密钥进行按位异或操作。将密钥的影响混合到数据中,增加密码的变化性和安全性。

    • 操作方法:对每个位,将扩展置换后的数据位与对应位的轮密钥位执行异或运算。

    • 轮密钥生成详细过程见“密钥k生成”部分

  2. S-盒替换

    • 原理:S-盒是一种非线性替代函数,它将一组输入位映射到一组输出位。S-盒替换是DES中的核心部分,它引入非线性性,将6位的输入映射到4位的输出,每个S盒由一个4行16列的表组成,可以增加数据的混乱度,增强密码的非线性特性。

    • 操作方法:将异或后的48位数据分成8组,每组6位,分别放入8个S-盒进行代换。每个S-盒通过查找表将6位输入映射为4位输出,替换每个6位块,得到32位输出。

    • 8个S-盒数据见代码S_BOXES部分

    • 详细置换过程

      • 使用S1作为示例S-盒:

      • 假设输入数据为 110110101011,它被分成8个6位的块,每个块分别是:110110101011。首先分别对这两个块进行S1的替换:

      • STEP1:对第一个块 110110 的S-盒替换:

        • 行号(row)计算:第1位和第6位为 11,这对应行号 3
        • 列号(col)计算:第2位到第5位为 1011,这对应列号 11
        • 在S1的S-盒中,第3行和第11列的交叉点的值是 5
        • 5 转化为4位二进制为 0101
      • STEP2:对第二个块 101011 的S-盒替换:

        • 行号(row)计算:第1位和第6位为 11,这对应行号 3
        • 列号(col)计算:第2位到第5位为 0101,这对应列号 5
        • 在S1的S-盒中,第3行和第5列的交叉点的值是 0
        • 0 转化为4位二进制为 0000
      • 现在有了两个S-盒替换后的结果:

        • 第一个块替换后为 0101
        • 第二个块替换后为 0000
      • 将这两个结果拼接在一起,得到最终的32位输出数据块为 01010000

  3. P-盒置换

    • 原理:重新排列32位数据块的位,增加数据的扩散性,为下一轮的轮函数准备数据。将数据再次混淆,以增加密码的安全性。

    • 操作方法:对32位数据块中的每一位根据一个预定义的置换表(P_BOX)进行重新排列。

    • P-盒数据如下图所示

    • P盒的设计的特点
      ①每个S盒的4位输出影响下一轮6个不同的S盒,但是没有2位影响同一S盒;
      ②在第i轮S盒的4位输出中,2位将影响i+1轮中间位,其余2位将影响两端位;
      ③如果一个S盒的4位输出影响另一个S盒的中间的1位,则后一个的输出位不会影响前面一个S盒的中间位。


轮函数具体流程如下图所示

密钥k生成


在DES加密算法中,密钥生成是关键的步骤之一,它通过对主密钥进行置换、左移操作和再次置换,生成16轮加密所需的子密钥。下面是生成子密钥的简要描述:

  1. 初始密钥置换

    • 原理:使用置换表PC1对主密钥进行置换,将64位的主密钥压缩为56位。去除主密钥中的奇偶校验位,以及排列密钥位的顺序。

    • 操作方法:主密钥的每一位根据置换表PC1被复制和重新排列,生成一个56位的中间密钥。

  2. 分成左右两部分

    • 原理:将初始的56位密钥分成两个28位的部分,通常称为左半部分和右半部分。

    • 操作方法:将中间密钥的前28位作为左半部分,后28位作为右半部分。

  3. 子密钥生成

    • 原理首先,使用包含16个不同的左移位数的SHIFT_SCHEDULE数组,每轮使用一个不同的左移数来生成子密钥。其次,左移操作将左半部分和右半部分的位数进行循环左移,根据SHIFT_SCHEDULE中的指定位数。通过循环移位和置换,DES的密钥调度方法确保了原密钥中各位的使用次数基本上相同。然后,将左半部分和右半部分重新组合成56位的中间密钥,再次使用一个置换表(PC2)对中间密钥进行置换,得到48位的子密钥。**最后,重复这个操作16次,每次生成一个不同轮次的子密钥。
    • 操作方法
      • 对左半部分和右半部分分别执行左移操作,左移位数由SHIFT_SCHEDULE数组决定。
      • 合并左半部分和右半部分,得到56位的中间密钥。
      • 使用置换表PC2对中间密钥进行置换,生成48位的子密钥。
      • 重复这个过程16次,每次生成一个不同的子密钥。

轮密钥生成的过程图

DES加密主函数(以及解密主函数)


加密主函数包含以下步骤:

  1. 初始置换:将明文进行IP初始置换,将数据重新排列成64位的形式。

  2. 生成子密钥:根据输入的初始密钥,生成16个轮次所需的子密钥。

  3. 数据分割:将初始置换后的数据分成左右两部分,每部分32位。

  4. 16轮加密:循环执行16轮加密过程,每轮中:

    a. 右半部分和子密钥一起放入轮函数生成轮输出。

    b. 将轮输出与左半部分进行异或操作,生成新的右半部分。

    c. 更新左半部分和右半部分,将左半部分设为之前的右半部分,右半部分设为新的右半部分。

  5. 数据合并:将左半部分和右半部分合并成一个64位的数据块。

  6. 逆初始置换:对合并的数据块进行IP_INV逆初始置换,得到最终密文。


密钥加密流程如下图所示:

DES在解密时,根据对称加密的基本原则,通过将加密相同密钥应用于密文,但以相反的顺序应用相同的变换和操作,可以确保解密的逆操作,从而还原明文。

解密函数与加密函数唯一不同的地方是,在进行轮函数中的异或时,加密函数正向遍历轮密钥进行异或,解密函数相反(从第16个轮密钥开始异或)


DES加密的破解


DES可以通过以下方式进行破解:

  1. 暴力破解
    通过尝试所有可能的密钥组合来解密DES加密消息。由于DES密钥长度为56位,暴力破解需要尝试2^56个不同的密钥。需要大量计算资源和时间,因此在实践中通常不使用。

  2. 差分密码分析
    基于已知明文和对应密文之间的差异进行攻击。攻击者通过比较不同密钥下的差异,试图获得有关密钥的信息。虽然这种方法比暴力破解更有效,但它仍然需要大量的计算和数据。

  3. 线性密码分析
    基于线性逼近进行攻击,通过构建密钥与明文和密文之间的线性关系来尝试破解密钥。它通常需要更多的已知明文-密文对。

  4. 针对弱密钥的攻击
    DES有一些弱密钥和半弱密钥,这些密钥在加密中表现出特定的性质,可能容易受到攻击。攻击者可以尝试利用这些性质来减少破解的难度。

  5. 针对多轮DES的攻击
    在多轮DES中,可以尝试针对每一轮的子密钥,逐步获取主密钥的信息。需要大量的计算分析。

  6. 生日攻击
    攻击者可以使用生日攻击来找到两个不同的密钥,这两个密钥都可以加密相同的明文,从而推断原始明文。

其他还有工作密钥攻击等方法。


多重DES


多重DES(Triple Data Encryption Standard)是DES(Data Encryption Standard)的一种变种,旨在提高加密的安全性,通过多次应用DES算法来增加密钥长度和加密强度。它使用三个独立的DES算法来连续加密数据。

多重DES主要模式有以下两种:

  1. 2-DES

    • 2-DES使用两次独立的DES加密过程来加密数据。
    • 首先,明文数据被用一个DES密钥进行加密。
    • 然后,密文再次被用另一个DES密钥进行加密,这个过程涉及两个不同的密钥。
    • 2-DES的密钥长度为112位(两个56位的密钥),相对于原始DES的56位密钥,它提供了更高的安全性。
    • 加密过程可以表示为:C = E(K2, D(E(K1, P))),其中C是密文,E代表加密,K1和K2是两个DES密钥,D代表解密,P是明文。
  2. 3-DES

    • 3-DES使用三次独立的DES加密过程来加密数据。
    • 明文首先被用一个DES密钥进行加密,然后再用另一个DES密钥进行解密,最后再用第三个DES密钥进行加密。
    • 3-DES的密钥长度为168位(三个56位的密钥),相对于原始DES,它提供了更高的加密强度。
    • 加密过程可以表示为:C = E(K3, D(E(K2, E(K1, P))),其中C是密文,E代表加密,K1、K2和K3是三个DES密钥,D代表解密,P是明文。
    • 3-DES提供更高的安全性,因为它涉及更多的加密和解密轮次,而且密钥空间更大。

多重DES的主要优点是保留了DES算法的结构和算法,同时增加了密钥长度,从而提高了安全性。缺点是需要多次执行DES加密和解密操作,速度较慢。


DES加密解密实现


python代码

'''
20231022
skdtxdy

# 初始置换IP
# 逆初始置换IP_INV
# 初始密钥置换PC1
# 循环左移位数表SHIFT_SCHEDULE
# 子密钥置换PC2
# S-盒S_BOXES
# 扩展置换EXPANSION
# P盒P_BOX
'''

# 初始置换IP
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^-1
IP_INV = [
    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
]

# 循环左移位数表
SHIFT_SCHEDULE = [
    1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
]

# 初始密钥置换PC-1
'''
PC-1是用于从初始密钥中生成56位的中间密钥(C0和D0)的置换表。
它从64位的初始密钥中筛选出56位,并丢弃了8位奇偶校验位。
这个置换是DES算法中的第一步,用于准备子密钥生成。
'''
PC1 = [
    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-2
'''
PC-2是用于从56位中间密钥生成每一轮的48位子密钥的置换表。
在DES中,子密钥是通过对中间密钥进行轮次迭代和置换生成的。
PC-2负责选择并排列中间密钥的位,以生成48位的子密钥。
'''
PC2 = [
    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-盒
S_BOXES = [
    # S-盒 1
    [
        [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]
    ],

    # S-盒 2
    [
        [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]
    ],

    # S-盒 3
    [
        [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]
    ],

    # S-盒 4
    [
        [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]
    ],

    # S-盒 5
    [
        [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]
    ],

    # S-盒 6
    [
        [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]
    ],

    # S-盒 7
    [
        [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]
    ],

    # S-盒 8
    [
        [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]
    ]
]

# 扩展置换 E置换
EXPANSION = [
    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
]

# P-盒
P_BOX = [
    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
]


def text_to_binary(text):
    binary_data = [int(bit) for char in text for bit in format(ord(char), '08b')]
    return binary_data


# 生成密钥校验位
def add_parity_bits(key_without_parity):
    key_with_parity = []
    for i in range(0, 56, 7):
        # 从每7位中计算奇偶校验位
        key_chunk = key_without_parity[i:i + 7]
        parity_bit = key_chunk.count(1) % 2  # 计算1的数量
        key_chunk.append(1 - parity_bit)  # 添加奇偶校验位
        key_with_parity.extend(key_chunk)
    return key_with_parity


# 左移位操作
def left_shift(bits, shift):
    return bits[shift:] + bits[:shift]


# 通用置换函数
def permutation(data, table):
    return [data[i - 1] for i in table]


# 生成16个子密钥的函数 
'''
首先进行初始密钥置换(PC-1表),然后将密钥分为左右两部分,并根据循环左移位数表(SHIFT_SCHEDULE)进行左移操作。
接着,将左右两部分合并,再进行子密钥置换(PC-2表),最终得到一个子密钥。这个过程重复16次,生成所有的子密钥。
'''
def generate_subkeys(key):
    # 初始密钥置换
    key = permutation(key, PC1)
    # 分成左右两部分
    left_half = key[:28]
    right_half = key[28:]

    subkeys = []

    for i in range(16):
        # 左移操作
        left_half = left_shift(left_half, SHIFT_SCHEDULE[i])
        right_half = left_shift(right_half, SHIFT_SCHEDULE[i])
        # 合并左右两部分
        combined_key = left_half + right_half
        # 子密钥置换PC-2
        subkey = permutation(combined_key, PC2)
        subkeys.append(subkey)

    return subkeys


# S-盒替换函数
def s_box_substitution(data):
    s_box_output = []
    for i in range(8):
        # 分割为6位块
        chunk = data[i * 6:(i + 1) * 6]
        row = chunk[0] * 2 + chunk[5]  # 行号
        col = chunk[1] * 8 + chunk[2] * 4 + chunk[3] * 2 + chunk[4]  # 列号
        s_box_value = S_BOXES[i][row][col]
        # 转为4位二进制
        s_box_output.extend([(s_box_value >> j) & 1 for j in range(3, -1, -1)])
    return s_box_output


# 轮函数
def round_function(data, subkey):
    # 扩展置换
    expanded_data = permutation(data, EXPANSION)
    # 与子密钥异或
    data_xor_subkey = [expanded_data[i] ^ subkey[i] for i in range(48)]
    # S-盒替换
    s_box_output = s_box_substitution(data_xor_subkey)
    # P-盒置换
    round_output = permutation(s_box_output, P_BOX)

    return round_output


# 主DES加密函数
def des_encrypt(plain_text, key):
    # 初始置换
    plain_text = permutation(plain_text, IP)
    # 生成16个子密钥,接受一个初始密钥作为输入,并返回一个包含16个子密钥的列表
    subkeys = generate_subkeys(key)
    # 分成左右两部分
    left_half = plain_text[:32]
    right_half = plain_text[32:]

    for i in range(16):
        # 执行轮函数
        round_output = round_function(right_half, subkeys[i])
        # 异或
        new_right_half = [left_half[j] ^ round_output[j] for j in range(32)]
        # 更新左右两部分
        left_half = right_half
        right_half = new_right_half

    # 合并左右两部分
    combined_data = right_half + left_half
    # 逆初始置换
    cipher_text = permutation(combined_data, IP_INV)

    return cipher_text


# des解密函数
def des_decrypt(cipher_text, key):
    # 逆初始置换
    cipher_text = permutation(cipher_text, IP)
    # 生成16个子密钥,接受一个初始密钥作为输入,并返回一个包含16个子密钥的列表
    subkeys = generate_subkeys(key)
    # 分成左右两部分
    left_half = cipher_text[:32]
    right_half = cipher_text[32:]

    for i in range(16):
        # 执行轮函数的逆操作
        round_output = round_function(right_half, subkeys[15 - i])
        # 异或
        new_right_half = [left_half[j] ^ round_output[j] for j in range(32)] # 加解密唯一区别
        # 更新左右两部分
        left_half = right_half
        right_half = new_right_half

    # 合并左右两部分
    combined_data = right_half + left_half
    # 初始置换
    plain_text = permutation(combined_data, IP_INV)

    return plain_text


if __name__ == "__main__":
    # 明文字符串
    plain_text = "HelloWorld"
    # 转换为二进制对应的整型数组
    binary_plain_text = text_to_binary(plain_text)
    # 计算需要填充零位的数量
    remainder = 64 - len(binary_plain_text) % 64
    # 将整数数组拆分成64位一组的二维整数数组,并在末尾添加零位
    n = 64  # 定义每个子数组的长度
    binary_plain_text_2d = [binary_plain_text[i:i + n] + [0] * remainder for i in range(0, len(binary_plain_text), n)]

    # 密钥字符串(需要确保长度为56位)8位字符 64
    key = "SecretKey"
    # 转换为二进制对应的整型数组
    binary_key = text_to_binary(key)
    # 从整型数组中去掉每8个整型数据中的第8个
    binary_key_partitioned = [int(bit) for binary_value in binary_key for i, bit in
                                            enumerate(str(binary_value)) if i % 8 != 7]
    # 添加奇偶校验位
    key_with_parity = add_parity_bits(binary_key_partitioned)

    cipher_texts = []
    text = ""
    # 加密
    for i in range(len(binary_plain_text_2d)):
        cipher_text_int = des_encrypt(binary_plain_text_2d[i], key_with_parity)
        cipher_texts.append(cipher_text_int)

    for i in range(len(cipher_texts)):
        # 将整型数组转化为8位一组的二进制
        binary_str = ''.join(map(str, cipher_texts[i]))
        # 将二进制转化为字符串
        text += ''.join(chr(int(binary_str[i:i + 8], 2)) for i in range(0, len(binary_str), 8))

    # 加密后的字符串
    print("字符串密钥(8位):")
    print(key)
    print("加密:")
    print(text)

# ////////////////////////////////////////////////  解密

    # 密文字符串
    cipher_text = text

    # 转换为二进制对应的整型数组
    binary_cipher_text = text_to_binary(cipher_text)
    # 计算需要填充零位的数量
    remainder_2 = 64 - len(binary_cipher_text) % 64
    # 将整数数组拆分成64位一组的二维整数数组,并在末尾添加零位
    n_2 = 64  # 定义每个子数组的长度
    binary_cipher_text_2d = [binary_cipher_text[i:i + n] + [0] * remainder_2 for i in range(0, len(binary_cipher_text), n_2)]

    decrypted_binary_text = []
    decrypted_text = ""
    # 解密
    for i in range(len(binary_cipher_text_2d)):
        decrypted_binary_text.append(des_decrypt(binary_cipher_text_2d[i], key_with_parity))

    for i in range(len(decrypted_binary_text)):
        # 将整型数组转化为8位一组的二进制
        binary_str = ''.join(map(str, decrypted_binary_text[i]))
        # 将二进制转化为字符串
        decrypted_text += ''.join(chr(int(binary_str[i:i + 8], 2)) for i in range(0, len(binary_str), 8))

    # 解密后的明文
    print("解密:")
    print(decrypted_text)


运行结果测试


图片(流程图)来源于网络