python实现DES算法
DES算法
- 一、算法介绍
- 1.1 背景
- 1.2 原理
- 1.3 基本功能函数
- 1.4 子密钥的生成
- 二、代码实现
- 2.1 子密钥生成实现
- 2.2 DES加解密实现
- 2.3 完整代码
- 三、演示效果
一、算法介绍
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} IP−1,即可得到加密数据。
解密过程与此类似,不同之处仅在于子密钥的使用顺序正好相反
。
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} IP−1
它将 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 场 小白入门赛
🔥博客介绍: EvLast 🎥系列专栏: <<数据结构与算法>> << 算法入门>> << C项目>> 🎥 当前专栏: << 算法入门>> 专题 : 帮助小白快速入门算法竞赛 👍…...

HTML+CSS基础 第二季课堂笔记
一、列表 列表都不是单打独斗的,通常都是一组标签组成 1 无序列表 作用:定义一个没有顺序的列表结构 由两个标签组成,ul(容器级标签),li(容器级) ul:英文ulordered …...

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

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

【C++】--类和对象(2)
👌个人主页: 起名字真南 👆个人专栏:【数据结构初阶】 【C语言】 【C】 目录 1 类的默认成员函数2 构造函数3 析构函数4 拷贝构造5 赋值运算符重载5.1 运算符重载5.2 赋值运算符的重载 1 类的默认成员函数 默认成员函数就是用户没有显示实现,…...

最新BurpSuite2024.9专业中英文开箱即用版下载
1、工具介绍 本版本更新介绍 此版本对 Burp Intruder 进行了重大改进,包括自定义 Bambda HTTP 匹配和替换规则以及对扫描 SOAP 端点的支持。我们还进行了其他改进和错误修复。 Burp Intruder 的精简布局我们对 Burp Intruder 进行了重大升级。现在,您可…...

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

基于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)URL 参数 参数直接 拼接在URL的后面,使用 ? 进行分隔,多个参数之间用 & 符号分隔。例如:http://localhost:8080/user?namezhangsan&id1后端接收(在Controller方法的参数列表中使用 RequestParam 注解&…...

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

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

问:说说JVM不同版本的变化和差异?
在Java程序的执行过程中,Java虚拟机(JVM)扮演着至关重要的角色。它不仅负责解释和执行Java字节码,还管理着程序运行时的内存。根据JVM规范,JVM将其所管理的内存划分为多个不同的数据区域,包括程序计数器、J…...

计算机毕业设计 基于Python的社交音乐分享平台的设计与实现 Python+Django+Vue 前后端分离 附源码 讲解 文档
🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点…...

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

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

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

Python项目文档生成常用工具对比
写在前面: 通过阅读本片文章,你将了解:主流的Python项目文档生成工具(Sphinx,MkDocs,pydoc,Pdoc)简介及对比,本文档不涉及相关工具的使用。 概述 近期,由于…...

教育领域的技术突破:SpringBoot系统实现
2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统,它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等,非常…...

RabbitMQ入门3—virtual host参数详解
在 RabbitMQ 中,创建 Virtual Host 时会涉及到一些参数配置,比如 tags 和 Default Queue Type。下面是对这两个参数的详细解释: 1. Tags Tags 是 Virtual Host 的标记,用来为 Virtual Host 添加元数据,帮助你管理和组…...

【Nacos入门到实战十四】Nacos配置管理:集群部署与高可用策略
个人名片 🎓作者简介:java领域优质创作者 🌐个人主页:码农阿豪 📞工作室:新空间代码工作室(提供各种软件服务) 💌个人邮箱:[2435024119qq.com] 📱…...

UE5+ChatGPT实现3D AI虚拟人综合实战
第11章 综合实战:UE5ChatGPT实现3D AI虚拟人 通过结合Unreal Engine 5(UE5)的强大渲染能力和ChatGPT的自然语言处理能力,我们可以实现一个高度交互性的AI虚拟人。本文将详细介绍如何在UE5中安装必要的插件,配置OpenAI…...

[图形学]smallpt代码详解(2)
一、简介 本文紧接在[图形学]smallpt代码详解(1)之后,继续详细讲解smallpt中的代码,包括自定义函数(第41到47行)和递归路径跟踪函数(第48到74行)部分。 二、smallpt代码详解 1.自…...

vmstat命令:系统性能监控
一、命令简介 vmstat 是一种在类 Unix 系统上常用的性能监控工具,它可以报告虚拟内存统计信息,包括进程、内存、分页、块 IO、陷阱(中断)和 CPU 活动等。 二、命令参数 2.1 命令格式 vmstat [选项] [ 延迟 [次数] ]2…...

linux部署NFS和autofs自动挂载
目录 (一)NFS: 1. 什么是NFS 2. NFS守护进程 3. RPC服务 4. 原理 5. 部署 5.1 安装NFS服务 5.2 配置防火墙 5.3 创建服务端共享目录 5.4 修改服务端配置文件 (1). /etc/exports (2). nfs.conf 5.5 启动nfs并加入自启 5.6 客户端…...

WPF RadioButton 绑定boolean值
<RadioButtonMargin"5"Content"替换"IsChecked"{Binding CorrectionOption.ReCorrectionMode}" /> <RadioButtonMargin"5"Content"平均"IsChecked"{Binding CorrectionOption.ReCorrectionMode, Converter{St…...

2024 ciscn WP
一、MISC 1.火锅链观光打卡 打开后连接自己的钱包,然后点击开始游戏,答题八次后点击获取NFT,得到有flag的图片 没什么多说的,知识问答题 兑换 NFT Flag{y0u_ar3_hotpot_K1ng} 2.Power Trajectory Diagram 方法1: 使用p…...