2024年手搓DES算法:从Feistel网络到Python实现,深入理解对称加密原理
2026/6/24 11:22:58 网站建设 项目流程

1. 项目概述:为什么在2024年还要手搓DES算法?

如果你在2024年看到一篇关于用Python实现DES加解密的文章,第一反应可能是:“这都什么年代了,还用DES?” 确实,从现代密码学的角度看,DES(Data Encryption Standard)因其56位的密钥长度,早已被证明是不安全的,AES(Advanced Encryption Standard)才是当前的主流。那么,为什么我们还要花时间去理解和实现它呢?这恰恰是问题的关键所在。

对于一名开发者,尤其是安全领域或底层系统相关的从业者,学习DES绝非为了在实际生产环境中使用它进行加密。它的核心价值在于教学与理解。DES是密码学发展史上一个里程碑式的对称加密算法,其结构清晰,包含了现代分组密码的几乎所有核心思想:Feistel网络结构、S盒(Substitution-box)、P盒(Permutation-box)、密钥调度等。通过亲手实现一遍DES,你能像拆解一台精密的机械钟表一样,透彻理解对称加密算法是如何一步步将明文“打乱”又“还原”的。这种底层的认知,是调用cryptography库中AES.new(key, mode)所无法替代的。它为你理解更复杂的算法(如AES、SM4)乃至设计自己的密码学方案(当然,仅限于学习研究)打下了坚实的基础。

因此,本文的目标不是提供一个“能用”的DES工具(事实上,你绝不应该用它加密真实数据),而是提供一个“能懂”的DES解剖指南。我们将从零开始,用纯Python实现DES算法的每一个步骤,并详细解释其背后的密码学原理。无论你是密码学的初学者,还是想巩固基础的进阶者,这篇文章都将带你穿越到那个密码学的“青铜时代”,亲手锻造一把虽已过时、但原理永存的“密钥”。

2. DES算法核心原理深度拆解

DES是一种分组密码,它以64位为一个分组进行加密或解密,密钥长度名义上是64位,但实际有效长度是56位,另外8位用于奇偶校验。其核心结构是16轮的Feistel网络。理解DES,关键在于吃透以下几个核心部件。

2.1 Feistel网络结构:加解密同构的魔法

Feistel结构是DES乃至许多其他密码(如Blowfish)的灵魂。它的精妙之处在于,加密和解密过程可以使用完全相同的结构,仅仅是子密钥的使用顺序相反。这极大地简化了硬件和软件的实现。

对于一个数据分组,我们将其平分为左右两部分,L0R0。在每一轮i中(i从1到16),运算如下:

  1. Li = R(i-1)
  2. Ri = L(i-1) ⊕ F(R(i-1), Ki)

其中,表示异或(XOR)操作,F是轮函数,Ki是第i轮的子密钥。F函数是DES安全性的核心,我们稍后详解。

经过16轮迭代后,我们得到L16R16,但最终输出前,还需要进行一次最终置换(IP^-1),它与初始置换(IP)互为逆过程。

注意:Feistel网络之所以能实现加解密同构,奥秘在于异或操作的特性。解密时,只需将密文作为输入,并逆序使用子密钥(K16, K15, ..., K1),经过相同的16轮Feistel运算,就能神奇地还原出明文。我们在代码实现时会清晰地看到这一点。

2.2 核心部件详解:IP/FP、F函数与密钥调度

2.2.1 初始置换与最终置换(IP & IP^-1)

在进入Feistel网络前,64位明文需要经过一个固定的初始置换(Initial Permutation, IP)。这只是一个比特位的重新排列,并不增加算法的安全性,其历史原因主要是为了适应早期硬件的布线方便。加密完成后,经过最终置换(Final Permutation, IP^-1),它是IP的逆置换,将比特位恢复成标准的输出顺序。在实现时,我们只需定义好这两个置换表,按表移动比特位即可。

2.2.2 轮函数 F(R, K)

这是DES算法中最复杂、最核心的部分。它接受32位的右半部分R和48位的子密钥K,输出一个32位的结果。其内部流程如下:

  1. 扩展置换(E-box):将32位的R扩展为48位。这不是简单补零,而是通过重复某些比特位来实现。目的是让32位的输入能与48位的子密钥进行异或,同时让输出的一位能影响下一轮S盒的多个输入,从而产生更好的扩散效果。
  2. 与子密钥异或:将扩展后的48位结果与48位的子密钥Ki进行按位异或。
  3. S盒替代(S-box Substitution):这是DES非线性特性的唯一来源,是算法的安全核心。将异或后的48位数据分成8组,每组6位,分别送入8个不同的S盒(S1到S8)。每个S盒是一个固定的4行16列的查找表,它根据6位输入(头尾两位组成行号,中间四位组成列号),输出一个4位的结果。这样,48位输入就被压缩成了32位输出。S盒的设计是保密的,其强度直接决定了DES的抗攻击能力。
  4. P盒置换(P-box Permutation):将S盒输出的32位结果进行一次固定的比特位置换。目的是将S盒的输出位更好地扩散到下一轮的多个S盒输入中,增强算法的混淆性。
2.2.3 密钥调度算法

从原始的56位有效密钥(去掉校验位后),生成16个48位的子密钥K1K16。过程如下:

  1. 置换选择1(PC-1):将64位密钥(含校验位)置换并筛选,得到56位的密钥,并分为左右各28位的C0D0
  2. 循环左移:对于每一轮iC(i-1)D(i-1)分别进行循环左移。左移的位数由轮数决定:第1、2、9、16轮左移1位,其余轮次左移2位。
  3. 置换选择2(PC-2):将每一轮移位后合并的56位(Ci+Di)进行置换和压缩,最终输出48位的子密钥Ki

3. 手把手实现:Python代码逐行解析

理解了原理,我们开始用Python实现。我们将避免使用任何高级密码学库,仅用基本的位运算和列表操作来还原整个过程。代码将分为几个清晰的函数模块。

3.1 准备工作:定义常量与辅助函数

首先,我们需要定义DES算法中所有固定的置换表、S盒等常量。这些数据是标准化的,可以从任何密码学教材或标准文档中找到。

# -*- coding: utf-8 -*- """ DES (Data Encryption Standard) 算法的纯Python实现。 警告:仅用于教学和理解原理,绝对不应用于任何真实数据的加密! """ # 初始置换表 (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) FP = [ 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-box) 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 ] # 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 ] # S盒 (8个,每个是4x16的矩阵) S_BOX = [ # 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 ... S8 (此处为节省篇幅省略,完整实现需补全所有8个S盒) # 实际代码中必须包含完整的S1到S8 ] # 密钥置换表 PC-1 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 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 ] # 每轮密钥循环左移的位数 KEY_SHIFT = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]

接下来,我们实现一些关键的辅助函数。位操作是DES实现的基础,Python的整数类型非常适合进行位运算。

def text_to_bits(text: str, encoding='utf-8') -> str: """将文本转换为二进制比特串。""" bytes_data = text.encode(encoding) bits = ''.join(format(byte, '08b') for byte in bytes_data) return bits def bits_to_text(bits: str, encoding='utf-8') -> str: """将二进制比特串转换回文本。""" # 确保长度是8的倍数 if len(bits) % 8 != 0: bits = bits.ljust((len(bits) // 8 + 1) * 8, '0') bytes_list = [int(bits[i:i+8], 2) for i in range(0, len(bits), 8)] # 去除可能因填充产生的空字符 data = bytes(bytes_list).decode(encoding, errors='ignore').rstrip('\x00') return data def permute(bits: str, table: list) -> str: """根据给定的置换表对比特串进行置换。""" # 注意:置换表table中的数字是从1开始计数的,而Python字符串索引从0开始。 return ''.join(bits[i-1] for i in table) def left_shift(bits: str, n: int) -> str: """循环左移n位。""" n = n % len(bits) return bits[n:] + bits[:n] def xor(bits1: str, bits2: str) -> str: """对两个等长的比特串进行异或操作。""" if len(bits1) != len(bits2): raise ValueError("比特串长度必须相等") return ''.join('1' if b1 != b2 else '0' for b1, b2 in zip(bits1, bits2))

实操心得:在实现permute函数时,最容易出错的就是忘记置换表的索引是从1开始的,而Python列表索引是从0开始的。bits[i-1]这个细节至关重要。另外,在文本与比特串的转换中,我们使用了UTF-8编码,这是一种通用且能处理多语言字符的方案。但在处理非ASCII字符时,一个字符可能对应多个字节,分组加密时需要填充机制(如PKCS#7)来确保数据长度是64位的倍数。为了简化核心算法演示,我们的示例会假设处理的是ASCII字符或已填充好的数据。

3.2 密钥调度算法的实现

密钥调度是一个独立且重要的模块,它负责生成16轮所需的子密钥。

def generate_subkeys(key_bits: str): """从64位密钥(含8位奇偶校验位)生成16个48位子密钥。""" # 1. 通过PC-1置换,得到56位密钥并分成C0, D0 key_pc1 = permute(key_bits, PC1) C = key_pc1[:28] D = key_pc1[28:] subkeys = [] for i in range(16): # 2. 循环左移 shift = KEY_SHIFT[i] C = left_shift(C, shift) D = left_shift(D, shift) # 3. 通过PC-2置换,生成48位子密钥Ki combined = C + D subkey = permute(combined, PC2) subkeys.append(subkey) return subkeys

3.3 轮函数 F(R, K) 的实现

这是DES算法的“心脏”,代码需要精确对应原理中的每一步。

def f_function(R: str, K: str) -> str: """轮函数F。输入:32位R,48位K。输出:32位。""" # 1. 扩展置换:32位 -> 48位 R_expanded = permute(R, E) # 2. 与子密钥异或 xor_result = xor(R_expanded, K) # 3. S盒替代:48位 -> 32位 sbox_output = '' for i in range(8): # 取出6位 block = xor_result[i*6: (i+1)*6] # 计算行号和列号(二进制字符串转整数) row = int(block[0] + block[5], 2) # 首位和末位组成行号 col = int(block[1:5], 2) # 中间4位组成列号 # 查询S盒,得到4位输出,并转换为4位二进制字符串 val = S_BOX[i][row][col] sbox_output += format(val, '04b') # 4. P盒置换 output = permute(sbox_output, P) return output

注意事项:S盒查询是DES实现中最容易引入错误的地方。rowcol的计算必须严格按照标准:block[0]block[5]是行比特,block[1:5]是列比特。format(val, '04b')确保了即使S盒输出是0,也会被格式化为‘0000’这样的4位字符串,否则后续的位操作会因长度不一致而出错。

3.4 核心加密/解密单轮处理

基于Feistel网络,我们可以写出处理单轮(或多轮)的通用函数。

def des_crypt_block(block_bits: str, subkeys: list, is_encrypt: bool = True) -> str: """对一个64位数据分组进行DES加密或解密。 Args: block_bits: 64位二进制字符串。 subkeys: 16个48位子密钥的列表。 is_encrypt: True为加密,False为解密。 Returns: 加密或解密后的64位二进制字符串。 """ # 1. 初始置换 block = permute(block_bits, IP) L = block[:32] R = block[32:] # 2. 16轮Feistel网络 # 加密时使用K1到K16,解密时使用K16到K1 key_iter = range(16) if is_encrypt else range(15, -1, -1) for i in key_iter: L_next = R # F函数运算 f_result = f_function(R, subkeys[i]) R_next = xor(L, f_result) L, R = L_next, R_next # 3. 最后一轮后交换左右(Feistel网络的特性,但我们的循环已经包含了交换) # 合并前需要交换最后一轮的结果,因为我们的循环结束时 L=R_{16}, R=L_{16} combined = R + L # 4. 最终置换 cipher_block = permute(combined, FP) return cipher_block

核心逻辑解析:注意key_iter的处理。这正是Feistel网络精妙之处的体现:加密时按K1, K2, ..., K16的顺序使用子密钥;解密时,只需将子密钥列表逆序使用K16, K15, ..., K1,而算法结构(f_function)完全不变。L, R = L_next, R_next这行代码完成了每一轮的左右部分更新。在16轮结束后,按照标准,我们需要将最后一轮的L16R16交换后再合并,但我们的循环设计(L_next = R)已经隐含了交换,所以循环结束时LR已经是交换后的状态,直接R + L合并即可。

3.5 完整的加解密与工作模式封装

单个分组的加解密只是基础。实际中,数据往往很长,需要分组密码的工作模式(Mode of Operation),如ECB、CBC等。这里我们实现最简单的ECB(电子密码本)模式作为示例,并完成最终的封装。

def pad_data(bits: str) -> str: """PKCS#7风格填充:确保比特串长度是64的倍数。""" block_size_bits = 64 bit_length = len(bits) pad_len = block_size_bits - (bit_length % block_size_bits) # 填充的每个比特都是0,并记录填充长度(这里简化,实际PKCS#7填充的是字节值) # 为简化演示,我们采用补零到64位倍数的方式 if pad_len != block_size_bits: bits += '0' * pad_len return bits def depad_data(bits: str) -> str: """去除填充(针对简单的补零填充)。""" # 在实际PKCS#7中,需要根据最后一个字节的值来移除相应数量的字节。 # 此处为简化,我们假设原始数据末尾没有多余的零,直接返回。 # 这是一个不严谨的实现,仅用于演示。 return bits.rstrip('0') def des_encrypt(plaintext: str, key: str, mode='ECB') -> str: """DES加密。 Args: plaintext: 明文字符串。 key: 8字节(64位)密钥的字符串形式。例如“12345678”。 mode: 工作模式,目前仅支持‘ECB’。 Returns: 十六进制表示的密文字符串。 """ # 1. 文本和密钥转比特 plain_bits = text_to_bits(plaintext) # 密钥必须是8字节,我们取前64位(如果用户输入过长)或补足(如果过短) key_bits = text_to_bits(key.ljust(8, '\0')[:8]) # 2. 数据填充 plain_bits_padded = pad_data(plain_bits) # 3. 生成子密钥 subkeys = generate_subkeys(key_bits) # 4. 分块加密 cipher_bits = '' for i in range(0, len(plain_bits_padded), 64): block = plain_bits_padded[i:i+64] if len(block) < 64: block = block.ljust(64, '0') encrypted_block = des_crypt_block(block, subkeys, is_encrypt=True) cipher_bits += encrypted_block # 5. 转换为十六进制输出,便于阅读和传输 cipher_hex = hex(int(cipher_bits, 2))[2:].upper().zfill(len(cipher_bits)//4) return cipher_hex def des_decrypt(ciphertext_hex: str, key: str, mode='ECB') -> str: """DES解密。 Args: ciphertext_hex: 十六进制表示的密文字符串。 key: 8字节(64位)密钥的字符串形式,必须与加密时相同。 mode: 工作模式,必须与加密时相同。 Returns: 解密后的明文字符串。 """ # 1. 十六进制转比特串 cipher_bits = bin(int(ciphertext_hex, 16))[2:].zfill(len(ciphertext_hex)*4) # 2. 密钥处理 key_bits = text_to_bits(key.ljust(8, '\0')[:8]) # 3. 生成子密钥 subkeys = generate_subkeys(key_bits) # 4. 分块解密 plain_bits = '' for i in range(0, len(cipher_bits), 64): block = cipher_bits[i:i+64] decrypted_block = des_crypt_block(block, subkeys, is_encrypt=False) plain_bits += decrypted_block # 5. 去除填充并转回文本 plain_bits_depad = depad_data(plain_bits) plaintext = bits_to_text(plain_bits_depad) return plaintext # 示例用法 if __name__ == "__main__": key = "8bytekey" # 必须是8个字符 plaintext = "HelloDES" print(f"密钥: {key}") print(f"明文: {plaintext}") ciphertext = des_encrypt(plaintext, key) print(f"密文 (十六进制): {ciphertext}") decrypted_text = des_decrypt(ciphertext, key) print(f"解密后: {decrypted_text}") print(f"加解密结果是否一致: {plaintext == decrypted_text}")

4. 从理论到实践:常见问题与深度排查

自己动手实现一个复杂的算法,调试过程就是最好的学习。下面是我在实现和教学过程中总结的几个典型问题和排查技巧。

4.1 密文与标准结果对不上?逐层验证法

这是最常见的问题。你的输出和教科书、在线工具的结果不一致。不要慌张,采用逐层验证法进行隔离排查。

  1. 验证基础置换:用一个简单的、已知的输入(比如全零或全一的64位比特串),手动计算经过IP置换、FP置换后的结果,与程序输出对比。确保permute函数正确无误。
  2. 验证密钥调度:给定一个标准测试密钥(如全零密钥),打印出每一轮生成的子密钥Ki的前几位,与标准值对比。网上可以找到DES的官方测试向量(Test Vectors)。
  3. 验证轮函数F:在已知RK的情况下,手动计算扩展、异或、S盒查询、P盒置换的结果,与程序f_function的输出对比。S盒的输出是重点排查对象,确保行号和列号计算正确。
  4. 验证单轮加密:在已知L0R0K1的情况下,手动计算一轮Feistel后的L1R1,与程序在循环第一轮结束后的结果对比。
  5. 验证完整加密:使用完整的官方测试向量(例如,NIST发布的已知答案测试)。输入标准的明文和密钥,比较最终输出的密文。

实操心得:准备一个“调试模式”开关非常有用。在关键函数(如generate_subkeys,f_function,des_crypt_block)中加入verbose参数,当打开时,打印出每一轮的中间状态(L,R,Ki,F输出等)。对比这些中间值,能快速定位错误发生在哪一步。例如,如果F函数的输出错了,但扩展和异或都对了,那问题一定出在S盒或P盒。

4.2 中文或特殊字符加解密乱码?编码与填充的坑

我们的示例代码使用了简单的补零填充和bits_to_texterrors='ignore'来处理解密后的数据。这在处理纯英文文本时可能没问题,但一旦涉及中文或多字节字符,极易出问题。

  • 根本原因:UTF-8编码下,一个中文字符可能由3个字节(24位)表示。当我们将文本转换成比特流并切割成64位分组时,很可能在一个分组的中间切断一个字符的字节序列。解密后,被切断的字节序列无法被正确解码,导致乱码或解码错误。
  • 解决方案:使用标准的、与字节对齐的填充方案,如PKCS#7。它的思想是,如果需要填充N个字节,那么每个填充字节的值都是N。例如,如果块大小是8字节,最后一块差3字节,那么就填充0x03 0x03 0x03。这样在解密后,可以通过检查最后一个字节的值,准确移除填充。
  • 改进代码
    import struct def pkcs7_pad(data_bytes: bytes, block_size=8) -> bytes: """PKCS#7 填充。""" padding_len = block_size - (len(data_bytes) % block_size) padding = bytes([padding_len] * padding_len) return data_bytes + padding def pkcs7_unpad(padded_data_bytes: bytes) -> bytes: """PKCS#7 去除填充。""" padding_len = padded_data_bytes[-1] # 简单验证填充有效性 if padding_len > len(padded_data_bytes): raise ValueError("无效的PKCS#7填充") return padded_data_bytes[:-padding_len] # 在加解密函数中,先处理字节,再转换比特 plain_bytes = plaintext.encode('utf-8') plain_bytes_padded = pkcs7_pad(plain_bytes, block_size=8) # 然后将 padded_bytes 转换成比特串进行处理... # 解密后,得到比特串,转回字节,然后 unpad decrypted_bytes = bytes(int(plain_bits[i:i+8], 2) for i in range(0, len(plain_bits), 8)) decrypted_bytes_unpadded = pkcs7_unpad(decrypted_bytes) decrypted_text = decrypted_bytes_unpadded.decode('utf-8')

4.3 性能慢得令人发指?Python位运算的优化思路

纯Python逐位操作字符串('0''1')的性能非常低下,尤其是在处理大量数据时。我们的实现是教学优先,但了解优化方向很有必要。

  1. 使用整数代替比特串:Python的整数类型本身就可以看作一个比特序列。我们可以将64位数据存储为一个Pythonint,然后使用位掩码和移位操作(&,|,<<,>>,^)来实现置换和异或。这比操作字符串快几个数量级。
  2. 预计算S盒:S盒查询是查表操作,本身很快。但我们可以将8个S盒合并或优化数据结构,减少循环和索引开销。
  3. 使用arraynumpy:对于批量数据处理,使用array.array('B')numpy数组可以显著提升性能。
  4. 关键函数用C扩展或Cython重写:对于真正需要性能的场景(虽然DES本身已不推荐使用),可以将核心的Feistel轮函数用C语言写成扩展模块,或在Python中使用ctypes调用优化过的C库。

避坑技巧:在教学的初期,清晰比性能更重要。使用字符串表示比特,虽然慢,但便于打印、调试和理解每一步的数据流动。当你完全理解算法后,可以将其重构成基于整数的版本作为一个有趣的练习。你可以写一个BitString类,内部用整数存储,但对外提供类似字符串的接口和详细的调试信息,兼顾可读性和性能。

4.4 安全性警示与算法局限性

我们必须一再强调:这个Python DES实现,以及DES算法本身,都不应用于任何真实的、需要安全保护的场景。

  • 密钥长度过短:56位密钥在当今计算能力(特别是暴力破解和专用硬件)面前不堪一击。
  • 算法存在理论弱点:DES的S盒设计虽然精妙,但经过几十年研究,已发现其存在一些密码学弱点(如互补性、弱密钥、半弱密钥等)。
  • 工作模式简单:示例中使用的ECB模式是极不安全的,相同的明文块会产生相同的密文块,会暴露数据模式。实际应用必须使用CBC、CTR等更安全的模式,并需要初始化向量(IV)。
  • 侧信道攻击:我们的纯软件实现没有考虑时序攻击、缓存攻击等侧信道威胁。

那么,在实际项目中应该用什么?

  • 对称加密:使用AES(Advanced Encryption Standard)。密钥长度至少128位,推荐256位。在Python中,使用标准库cryptography是首选。
    from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.backends import default_backend import os key = os.urandom(32) # AES-256 iv = os.urandom(16) # CBC模式需要的初始化向量 cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend()) encryptor = cipher.encryptor() # ... 使用 encryptor.update() 和 encryptor.finalize()
  • 非对称加密/密钥交换:使用RSAECC(椭圆曲线密码学)。
  • 哈希函数:使用SHA-256SHA-3
  • 密码学原则不要自己发明密码算法,使用经过广泛审查和验证的库和算法;正确管理密钥使用经过充分测试的工作模式和填充方案

实现DES的过程,就像在安全博物馆里修复一件古老的铠甲。你能学到锻造的技术、结构的智慧,但绝不会穿着它上现代的战场。这份理解,才是我们此行最大的收获。当你下次在代码中轻松调用AES.new(key, modes.GCM(nonce))时,你会对那个黑盒子里发生的复杂而优美的变换,多一份了然于胸的底气。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询