当前位置: 首页 > news >正文

python实现DES算法

DES算法

一、算法介绍

1.1 背景

DES 算法是由美国 IBM 公司在 20 世纪 70 年代提出,并被美国政府、美国国家标准局和美国国家标准协会采纳和承认的一种标准加密算法。

它属于分组加密算法,即在明文加密和密文解密过程中,信息都是按照固定长度分组后进行处理的。混淆扩散是它采用的两个最重要的安全特性。

混淆是指通过密码算法使明文和密文以及密钥的关系非常复杂,无法从数学上描述或者统计。扩散是指明文和密钥中每一位信息的变动,都会影响到密文中许多位信息的变动,从而隐藏统计上的特性,增加密码的安全。

1.2 原理

DES 算法将明文分成 64 位大小的众多数据块,即分组长度为 64 位,同时用 64 位密钥(有效密钥 56 位)对 64 位明文信息加密,最终形成 64 位的密文。如果明文长度不足 64 位,则将其扩展为 64 位(如补零等方法)。

具体加密过程,首先是将输入的数据进行初始换位( I P IP IP),即将明文 M M M 中数据的排列顺序按一定的规则重新排列,生成新的数据序列,以打乱原来的次序。然后将变换后的数据平分成左右两部分,左边记为 L 0 L_{0} L0,右边记为 R 0 R_{0} R0,然后对 R 0 R_{0} R0 实行在子密钥(由加密密钥产生)控制下的变换 f f f,结果记为 f ( R 0 , K 1 ) f(R_{0},K_{1}) f(R0,K1),再与 L 0 L_{0} L0 做逐位异或运算,其结果记为 R 1 R_{1} R1 R 0 R_{0} R0 则作为下一轮的 L 1 L_{1} L1。如此循环 16 轮,最后得到 L 16 L_{16} L16 R 16 R_{16} R16。再对 L 16 L_{16} L16 R 16 R_{16} R16 实行逆初始置换 I P − 1 IP^{-1} IP1,即可得到加密数据。
解密过程与此类似,不同之处仅在于子密钥的使用顺序正好相反

DES 全部 16 轮的加密过程如图所示:
在这里插入图片描述

1.3 基本功能函数

1.3.1 初始置换函数 I P IP IP

它的作用是把输入的 64 位数据块的排列顺序打乱,每位数据按照下面换位规则重新组合;即将第 58 位换到第 1 位,第 50 位换到第 2 位,……,依次类推;重组后的 64 位输出分为 L 0 L_{0} L0 R 0 R_{0} R0(左、右)两部分,每部分分别为 32 位。初始置换如表如下所示:

在这里插入图片描述

R 0 R_{0} R0 K 1 K_{1} K1 经过 变换后的输出结果,再和 L 0 L_{0} L0进行异或运算,输出结果做为 R 1 R_{1} R1 R 0 R_{0} R0 则赋给 L 1 L_{1} L1 L 1 L_{1} L1 R 1 R_{1} R1 同样再做类似运算生成 L 2 L_{2} L2 R 2 R_{2} R2,……,经过 16次运算后生成 L 16 L_{16} L16 R 16 R_{16} R16

1.3.2 f f f 轮函数

f f f 轮函数是多个置换函数和替代函数的组合函数,它将 32 位比特的输入变换为 32 位的输出; R i R_{i} Ri 经过扩展运算 E E E 变换后扩展为 48 位的 E ( R i ) E(R_{i}) E(Ri) ,与 K i + 1 K_{i+1} Ki+1 进行异或运算后输出的结果分成 8 组,每组 6 比特的并联 B B B B B B= B 1 B_{1} B1 B 2 B_{2} B2 B 3 B_{3} B3 B 4 B_{4} B4 B 5 B_{5} B5 B 6 B_{6} B6 B 7 B_{7} B7 B 8 B_{8} B8,再经过 8 个 S S S 盒的选择压缩运算转换为 4 位,8 个 4 位合并为 32 位后再经过 P P P 变换输出为 32 位的 f ( R i , K i + 1 ) f(R_{i},K_{i+1}) f(Ri,Ki+1) 。其中,扩展运算 E E E 与置换 P P P 主要作用是增加算法的扩展效果。

f f f 轮函数处理流程如下图所示:

在这里插入图片描述

1.3.3 逆初始置换函数 I P − 1 IP^{-1} IP1

它将 L 16 L_{16} L16 R 16 R_{16} R16 作为输入,进行逆初始换位得到密文输出。逆初始换位是初始位的逆运算,逆初始置换的换位规则如下表所示:

在这里插入图片描述

1.4 子密钥的生成

具体子密钥的产生流程如图所示:
在这里插入图片描述
输入的初始密钥值为 64 位;但 DES 算法规定,64 位初始密钥中第 8、16、……、64 位是奇偶检验位,不参与 DES 运算。所以,实际可用位数只有56 位,经过缩小选择换位表即置换选择 P C 1 PC1 PC1 的变换后,初始密钥的位数由 64 位变成了 56 位,将其平分为两部分 C 0 C_{0} C0(28 位)、 D 0 D_{0} D0(28 位)。然后,分别进行第 1 次循环左移,得到 C 1 C_{1} C1 D 1 D_{1} D1,需要注意的是,循环左移需经过 16 轮次,第 i i i 轮迭代时对应的左移位数要依据移位表的规则进行。接着,将 C 1 C_{1} C1 D 1 D_{1} D1 合并后得到 56 位的输出结果,再经过缩小选择换位表即置换选择 P C 2 PC2 PC2 ,从而得到了密钥 K 1 K_{1} K1(48 位),依次类推,便可得到 K 2 K_{2} K2、……、 K 16 K_{16} K16

二、代码实现

2.1 子密钥生成实现

# ========================================
# 一、子密钥生成
# (1) 初始置换 64->56
# 64位的种子密钥经过PC_1置换后,生成56位的密钥
# (2) 划分 56->(28,28)
# 经过初始置换后的56位密钥被均分成C0和D0两部分
# (3) 循环左移
# 第一轮,C0和D0根据移位次数表各自进行循环左移
# 得到C1和D1
# 每一轮的C和D值是由上一轮的C和D值循环左移得到的
# (4) 合并 (28,28)->56->48
# 左移后的两部分再次合并,通过一个选择压缩表(PC_2)
# 得到这一轮的子密钥
# (5)重复3、4操作,最终得到16个子密钥
# ========================================# 置换选择表1(PC_1) 64->56
PC_1 = [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(PC_2) 56->48
PC_2 = [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]# 移位次数表
shift_num = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]def pc_1_change(bin_key):"""初始置换64位的种子密钥经过PC_1置换后,生成56位的密钥"""return [bin_key[i - 1] for i in PC_1]  # 列表形式def shift_left(bin_key, num):"""实现C和D的循环左移"""return bin_key[num:] + bin_key[:num]def pc_2_change(bin_key):"""选择压缩56位的密钥经过PC_2压缩,生成48位子密钥"""return ''.join([bin_key[i - 1] for i in PC_2])  # 列表转字符串def get_subkey_list(bin_key):"""生成16轮的加解子密钥"""subkey_list = []  # 存储16轮子密钥# 1. 初始置换 64->58temp = pc_1_change(bin_key)# 2. 循环左移for i in shift_num:temp[:28] = shift_left(temp[:28], i)  # C部分循环左移temp[28:] = shift_left(temp[28:], i)  # D部分循环左移subkey_list.append(pc_2_change(temp))  # 生成子密钥return subkey_list

2.2 DES加解密实现

# ========================================
# 二、DES加解密实现
# ========================================# 初始置换表IP 64->64
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 64->64
_IP = [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]# 扩展置换表E 32->48
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]# S盒 48->32
S1 = [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]
S2 = [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]
S3 = [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]
S4 = [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]
S5 = [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]
S6 = [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]
S7 = [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]
S8 = [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]
S = [S1, S2, S3, S4, S5, S6, S7, S8]# P盒
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]# encrypt
def ip_change(bin_text):"""初始置换"""return [bin_text[i - 1] for i in IP]def s_box(bin_result):"""S盒替换"""int_result = []result = ''for i in range(8):# 二进制行号bin_row = bin_result[i][0] + bin_result[i][5]# 二进制列号bin_col = ''.join(bin_result[i][j] for j in range(1, 5))# 获取对应的十进制数int_result.append(S[i][16 * int(bin_row, base=2) + int(bin_col, base=2)])# 十进制转成二进制result += bin(int_result[-1])[2:].zfill(4)return resultdef p_box(result):"""P盒置换"""return ''.join(result[i - 1] for i in P)def f(R, bin_key):"""轮函数f()"""# 1.将R由32位扩展成48位R_ext = [R[i - 1] for i in E]# 2.与子密钥进行逐位异或bin_temp = [str(int(r) ^ int(k)) for r, k in zip(R_ext, bin_key)]# 6个字符为一组,共8组bin_result = [''.join(bin_temp[i:i + 6]) for i in range(0, len(bin_temp), 6)]# 3.S盒替换 48->32result = s_box(bin_result)# 4.P盒置换 32->32return p_box(result)def _ip_change(bin_text):"""进行IP-1逆置换"""return ''.join(bin_text[i - 1] for i in _IP)def des_cipher(bin_text, bin_key, reverse_keys=False):"""通用DES加密解密函数"""# 1. 初始置换IPbin_text = ip_change(bin_text)# 2. 分成左右两部分L、RL, R = bin_text[:32], bin_text[32:]# 3. 获得16轮子密钥subkey_list = get_subkey_list(bin_key)if reverse_keys:subkey_list = subkey_list[::-1]  # 解密时反转子密钥列表# 4. 进行16轮迭代for i in subkey_list:R_temp = R# 轮函数f()结果和L进行异或R = ''.join(str(int(r) ^ int(l)) for r, l in zip(f(R, i), L))L = R_temp# 5. 进行IP-1逆置换 64->64return _ip_change(R + L)  # 输出二进制字符串# 使用示例
def str2bin(text):"""字符串转二进制字符串"""return ''.join(bin(byte)[2:].zfill(8) for byte in text.encode())def bin2str(bin_text):"""二进制字符串转字符串"""# 1.将二进制字符串按8位分割,并转换为字节数组byte_array = bytearray(int(i, 2) for i in re.findall(r'.{8}', bin_text) if int(i, 2) != 0)# 2.将字节序列解码为字符串return byte_array.decode()def is_valid_key(key):"""检查密钥是否有效 64bit"""return len(key.encode()) == 8def des_encrypt(plaintext, key):"""DES加密"""# 1.明文转成二进制字符串, 0填充至64的倍数bin_plaintext = str2bin(plaintext)padding_len = (64 - (len(bin_plaintext) % 64)) % 64bin_padding_plaintext = bin_plaintext + '0' * padding_len# 2.进行64位分组加密bin_group_64 = re.findall(r'.{64}', bin_padding_plaintext)bin_ciphertext = ''for g in bin_group_64:bin_ciphertext += des_cipher(g, str2bin(key))# 3.密文转为16进制输出bin_group_4 = re.findall(r'.{4}', bin_ciphertext)hex_ciphertext = ''for g in bin_group_4:hex_ciphertext += format(int(g, 2), 'x')return hex_ciphertextdef des_decrypt(hex_ciphertext, key):"""DES解密"""# 1.16进制密文转为2进制字符串bin_ciphertext = ''.join(bin(int(h, 16))[2:].zfill(4) for h in hex_ciphertext)# 2.进行64位分组解密bin_group_64 = re.findall(r'.{64}', bin_ciphertext)bin_deciphertext = ''for g in bin_group_64:bin_deciphertext += des_cipher(g, str2bin(key), reverse_keys=True)# 3.将解密密文转为字符串输出return bin2str(bin_deciphertext)

2.3 完整代码

import re# ========================================
# 一、子密钥生成
# (1) 初始置换 64->56
# 64位的种子密钥经过PC_1置换后,生成56位的密钥
# (2) 划分 56->(28,28)
# 经过初始置换后的56位密钥被均分成C0和D0两部分
# (3) 循环左移
# 第一轮,C0和D0根据移位次数表各自进行循环左移
# 得到C1和D1
# 每一轮的C和D值是由上一轮的C和D值循环左移得到的
# (4) 合并 (28,28)->56->48
# 左移后的两部分再次合并,通过一个选择压缩表(PC_2)
# 得到这一轮的子密钥
# (5)重复3、4操作,最终得到16个子密钥
# ========================================# 置换选择表1(PC_1) 64->56
PC_1 = [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(PC_2) 56->48
PC_2 = [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]# 移位次数表
shift_num = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]def pc_1_change(bin_key):"""初始置换64位的种子密钥经过PC_1置换后,生成56位的密钥"""return [bin_key[i - 1] for i in PC_1]  # 列表形式def shift_left(bin_key, num):"""实现C和D的循环左移"""return bin_key[num:] + bin_key[:num]def pc_2_change(bin_key):"""选择压缩56位的密钥经过PC_2压缩,生成48位子密钥"""return ''.join([bin_key[i - 1] for i in PC_2])  # 列表转字符串def get_subkey_list(bin_key):"""生成16轮的加解子密钥"""subkey_list = []  # 存储16轮子密钥# 1. 初始置换 64->58temp = pc_1_change(bin_key)# 2. 循环左移for i in shift_num:temp[:28] = shift_left(temp[:28], i)  # C部分循环左移temp[28:] = shift_left(temp[28:], i)  # D部分循环左移subkey_list.append(pc_2_change(temp))  # 生成子密钥return subkey_list# ========================================
# 二、DES加解密实现
# ========================================# 初始置换表IP 64->64
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 64->64
_IP = [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]# 扩展置换表E 32->48
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]# S盒 48->32
S1 = [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]
S2 = [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]
S3 = [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]
S4 = [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]
S5 = [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]
S6 = [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]
S7 = [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]
S8 = [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]
S = [S1, S2, S3, S4, S5, S6, S7, S8]# P盒
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]# encrypt
def ip_change(bin_text):"""初始置换"""return [bin_text[i - 1] for i in IP]def s_box(bin_result):"""S盒替换"""int_result = []result = ''for i in range(8):# 二进制行号bin_row = bin_result[i][0] + bin_result[i][5]# 二进制列号bin_col = ''.join(bin_result[i][j] for j in range(1, 5))# 获取对应的十进制数int_result.append(S[i][16 * int(bin_row, base=2) + int(bin_col, base=2)])# 十进制转成二进制result += bin(int_result[-1])[2:].zfill(4)return resultdef p_box(result):"""P盒置换"""return ''.join(result[i - 1] for i in P)def f(R, bin_key):"""轮函数f()"""# 1.将R由32位扩展成48位R_ext = [R[i - 1] for i in E]# 2.与子密钥进行逐位异或bin_temp = [str(int(r) ^ int(k)) for r, k in zip(R_ext, bin_key)]# 6个字符为一组,共8组bin_result = [''.join(bin_temp[i:i + 6]) for i in range(0, len(bin_temp), 6)]# 3.S盒替换 48->32result = s_box(bin_result)# 4.P盒置换 32->32return p_box(result)def _ip_change(bin_text):"""进行IP-1逆置换"""return ''.join(bin_text[i - 1] for i in _IP)def des_cipher(bin_text, bin_key, reverse_keys=False):"""通用DES加密解密函数"""# 1. 初始置换IPbin_text = ip_change(bin_text)# 2. 分成左右两部分L、RL, R = bin_text[:32], bin_text[32:]# 3. 获得16轮子密钥subkey_list = get_subkey_list(bin_key)if reverse_keys:subkey_list = subkey_list[::-1]  # 解密时反转子密钥列表# 4. 进行16轮迭代for i in subkey_list:R_temp = R# 轮函数f()结果和L进行异或R = ''.join(str(int(r) ^ int(l)) for r, l in zip(f(R, i), L))L = R_temp# 5. 进行IP-1逆置换 64->64return _ip_change(R + L)  # 输出二进制字符串# 使用示例
def str2bin(text):"""字符串转二进制字符串"""return ''.join(bin(byte)[2:].zfill(8) for byte in text.encode())def bin2str(bin_text):"""二进制字符串转字符串"""# 1.将二进制字符串按8位分割,并转换为字节数组byte_array = bytearray(int(i, 2) for i in re.findall(r'.{8}', bin_text) if int(i, 2) != 0)# 2.将字节序列解码为字符串return byte_array.decode()def is_valid_key(key):"""检查密钥是否有效 64bit"""return len(key.encode()) == 8def des_encrypt(plaintext, key):"""DES加密"""# 1.明文转成二进制字符串, 0填充至64的倍数bin_plaintext = str2bin(plaintext)padding_len = (64 - (len(bin_plaintext) % 64)) % 64bin_padding_plaintext = bin_plaintext + '0' * padding_len# 2.进行64位分组加密bin_group_64 = re.findall(r'.{64}', bin_padding_plaintext)bin_ciphertext = ''for g in bin_group_64:bin_ciphertext += des_cipher(g, str2bin(key))# 3.密文转为16进制输出bin_group_4 = re.findall(r'.{4}', bin_ciphertext)hex_ciphertext = ''for g in bin_group_4:hex_ciphertext += format(int(g, 2), 'x')return hex_ciphertextdef des_decrypt(hex_ciphertext, key):"""DES解密"""# 1.16进制密文转为2进制字符串bin_ciphertext = ''.join(bin(int(h, 16))[2:].zfill(4) for h in hex_ciphertext)# 2.进行64位分组解密bin_group_64 = re.findall(r'.{64}', bin_ciphertext)bin_deciphertext = ''for g in bin_group_64:bin_deciphertext += des_cipher(g, str2bin(key), reverse_keys=True)# 3.将解密密文转为字符串输出return bin2str(bin_deciphertext)def des_run():"""DES启动界面"""flag = Truewhile flag:print('=' * 3, "DES加密解密", '=' * 3)print('[1]加密')print('[2]解密')print('[0]退出')choice = input('请输入你的选择:')match choice:case '0':flag = Falsecase '1':plaintext = input('请输入明文:')key = input('请输入密钥(64bit):')if not is_valid_key(key):print('密钥长度错误')continueciphertext = des_encrypt(plaintext, key)print(f'密文:{ciphertext}')case '2':ciphertext = input('请输入密文:')key = input('请输入密钥(64bit):')if not is_valid_key(key):print('密钥长度错误')continueprint(f'解密:{des_decrypt(ciphertext, key)}')case _:print('输入错误')print('=' * 15)if __name__ == '__main__':des_run()

三、演示效果

在这里插入图片描述

相关文章:

python实现DES算法

DES算法 一、算法介绍1.1 背景1.2 原理1.3 基本功能函数1.3.1 初始置换函数 I P IP IP1.3.2 f f f 轮函数1.3.3 逆初始置换函数 I P − 1 IP^{-1} IP−1 1.4 子密钥的生成 二、代码实现2.1 子密钥生成实现2.2 DES加解密实现2.3 完整代码 三、演示效果 一、算法介绍 1.1 背景…...

基于LORA的一主多从监测系统_框架搭建

第一节、框架搭建 打开CubeMAX,选择好芯片,进行基础配置 第一步、先配置时钟源 第二步、配置SYS选项 配置debug口以及计数器源,我这里选择TIM1 第三步、选择I2C接口 配置如下即可,默认配置不用改 第四步、串口选择 我们这里使…...

优化理论及应用精解【25】

文章目录 优化学习率调度1. 阶梯衰减(Step Decay)2. 余弦退火(Cosine Annealing)3. 多项式衰减(Polynomial Decay)4. 指数衰减(Exponential Decay)总结 梯度弥散效应 参考文献 优化 …...

贝锐蒲公英网盘首发,秒建私有云,高速远程访问

虽然公共网盘带来了不少便利,但是大家对隐私泄露和重要数据泄密的担忧也随之增加。如果想要确保数据安全,自建私有云似乎是一条出路,然而面对搭建私有云的复杂步骤,许多人感到力不从心,NAS设备的成本也往往让人望而却步…...

[ 蓝桥 ·算法双周赛 ] 第 19 场 小白入门赛

&#x1f525;博客介绍&#xff1a; EvLast &#x1f3a5;系列专栏&#xff1a; <<数据结构与算法>> << 算法入门>> << C项目>> &#x1f3a5; 当前专栏: << 算法入门>> 专题 : 帮助小白快速入门算法竞赛 &#x1f44d…...

HTML+CSS基础 第二季课堂笔记

一、列表 列表都不是单打独斗的&#xff0c;通常都是一组标签组成 1 无序列表 作用&#xff1a;定义一个没有顺序的列表结构 由两个标签组成&#xff0c;ul&#xff08;容器级标签&#xff09;&#xff0c;li&#xff08;容器级&#xff09; ul&#xff1a;英文ulordered …...

【Easy RL】Easy RL蘑菇书全书学习笔记

【Easy RL】Easy RL蘑菇书全书学习笔记 第一章 强化学习基础1.1 强化学习概述监督学习强化学习与监督学习的不同之处二者的区别总结强化学习的特征强化学习的优越性预演&#xff08;rollout&#xff09;和 轨迹&#xff08;trajectory&#xff09;的概念端到端的概念深度强化学…...

JavaWeb(二)

Servlet开发技术 [外链图片转存中…(img-Cnu8X2V4-1728026684827)] 简述Servlet的创建过程&#xff1f; package servlet; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; …...

【C++】--类和对象(2)

&#x1f44c;个人主页: 起名字真南 &#x1f446;个人专栏:【数据结构初阶】 【C语言】 【C】 目录 1 类的默认成员函数2 构造函数3 析构函数4 拷贝构造5 赋值运算符重载5.1 运算符重载5.2 赋值运算符的重载 1 类的默认成员函数 默认成员函数就是用户没有显示实现&#xff0c;…...

最新BurpSuite2024.9专业中英文开箱即用版下载

1、工具介绍 本版本更新介绍 此版本对 Burp Intruder 进行了重大改进&#xff0c;包括自定义 Bambda HTTP 匹配和替换规则以及对扫描 SOAP 端点的支持。我们还进行了其他改进和错误修复。 Burp Intruder 的精简布局我们对 Burp Intruder 进行了重大升级。现在&#xff0c;您可…...

C++ 观察者模式

观察者模式&#xff08;Observer Pattern&#xff09;是一种行为设计模式&#xff0c;用于在对象之间建立一对多的依赖关系&#xff0c;当一个对象的状态发生变化时&#xff0c;它的所有依赖对象都会得到通知并自动更新。 在观察者模式中&#xff0c;主题和观察者之间是松耦合…...

基于pytorch的手写数字识别-训练+使用

import pandas as pd import numpy as np import torch import matplotlib import matplotlib.pyplot as plt from torch.utils.data import TensorDataset, DataLoadermatplotlib.use(tkAgg)# 设置图形配置 config {"font.family": serif,"mathtext.fontset&q…...

SpringBoot接收前端传递参数

1&#xff09;URL 参数 参数直接 拼接在URL的后面&#xff0c;使用 ? 进行分隔&#xff0c;多个参数之间用 & 符号分隔。例如&#xff1a;http://localhost:8080/user?namezhangsan&id1后端接收&#xff08;在Controller方法的参数列表中使用 RequestParam 注解&…...

【LeetCode周赛】第 418 场

3309. 连接二进制表示可形成的最大数值 给你一个长度为 3 的整数数组 nums。 现以某种顺序 连接 数组 nums 中所有元素的 二进制表示 &#xff0c;请你返回可以由这种方法形成的 最大 数值。 注意 任何数字的二进制表示 不含 前导零 思路&#xff1a;暴力枚举 class Soluti…...

Android学习7 -- NDK2 -- 几个例子

学习 Android 的 NDK&#xff08;Native Development Kit&#xff09;可以帮助你用 C/C 来开发高性能的 Android 应用&#xff0c;特别适合对性能要求较高的任务&#xff0c;如音视频处理、游戏开发和硬件驱动等。下面是学习 NDK 的建议步骤和具体例子&#xff1a; ### 1. **准…...

问:说说JVM不同版本的变化和差异?

在Java程序的执行过程中&#xff0c;Java虚拟机&#xff08;JVM&#xff09;扮演着至关重要的角色。它不仅负责解释和执行Java字节码&#xff0c;还管理着程序运行时的内存。根据JVM规范&#xff0c;JVM将其所管理的内存划分为多个不同的数据区域&#xff0c;包括程序计数器、J…...

计算机毕业设计 基于Python的社交音乐分享平台的设计与实现 Python+Django+Vue 前后端分离 附源码 讲解 文档

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…...

51单片机的水位检测系统【proteus仿真+程序+报告+原理图+演示视频】

1、主要功能 该系统由AT89C51/STC89C52单片机LCD1602显示模块水位传感器继电器LED、按键和蜂鸣器等模块构成。适用于水位监测、水位控制、水位检测相似项目。 可实现功能: 1、LCD1602实时显示水位高度 2、水位传感器采集水位高度 3、按键可设置水位的下限 4、按键可手动加…...

Python和R及Julia妊娠相关疾病生物剖析算法

&#x1f3af;要点 算法使用了矢量投影、现代优化线性代数、空间分区技术和大数据编程利用相应向量空间中标量积和欧几里得距离的紧密关系来计算使用妊娠相关疾病&#xff08;先兆子痫&#xff09;、健康妊娠和癌症测试算法模型使用相关性投影利用相关性和欧几里得距离之间的关…...

Web安全 - 重放攻击(Replay Attack)

文章目录 OWASP 2023 TOP 10导图1. 概述2. 重放攻击的原理攻击步骤 3. 常见的重放攻击场景4. 防御重放攻击的技术措施4.1 使用时效性验证&#xff08;Time-Based Tokens&#xff09;4.2 单次令牌机制&#xff08;Nonce&#xff09;4.3 TLS/SSL 协议4.4 HMAC&#xff08;哈希消息…...

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇&#xff0c;在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下&#xff1a; 【Note】&#xff1a;如果你已经完成安装等操作&#xff0c;可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作&#xff0c;重…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

centos 7 部署awstats 网站访问检测

一、基础环境准备&#xff08;两种安装方式都要做&#xff09; bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats&#xff0…...

大语言模型如何处理长文本?常用文本分割技术详解

为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明

AI 领域的快速发展正在催生一个新时代&#xff0c;智能代理&#xff08;agents&#xff09;不再是孤立的个体&#xff0c;而是能够像一个数字团队一样协作。然而&#xff0c;当前 AI 生态系统的碎片化阻碍了这一愿景的实现&#xff0c;导致了“AI 巴别塔问题”——不同代理之间…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

【配置 YOLOX 用于按目录分类的图片数据集】

现在的图标点选越来越多&#xff0c;如何一步解决&#xff0c;采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集&#xff08;每个目录代表一个类别&#xff0c;目录下是该类别的所有图片&#xff09;&#xff0c;你需要进行以下配置步骤&#x…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成

厌倦手动写WordPress文章&#xff1f;AI自动生成&#xff0c;效率提升10倍&#xff01; 支持多语言、自动配图、定时发布&#xff0c;让内容创作更轻松&#xff01; AI内容生成 → 不想每天写文章&#xff1f;AI一键生成高质量内容&#xff01;多语言支持 → 跨境电商必备&am…...

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...