Python实现XTEA加密算法:从Feistel结构到分组密码核心原理
1. 项目概述:为什么要在Python里实现一个“过时”的加密算法?
最近在整理一个旧项目的代码,里面用到了一个叫XTEA的加密算法来处理一些本地配置文件的保护。说实话,第一次看到这个算法名时我也愣了一下,现在AES不是遍地开花吗,谁还用这个?但仔细一琢磨,这事儿还真有点意思。XTEA(eXtended TEA)算是加密算法发展史上的一个“老前辈”了,它设计于1997年,是对更早的TEA算法的一次关键修补。在那个计算资源还很金贵的年代,XTEA以其极致的简洁、高效和足够的安全性,在很多嵌入式系统、游戏存档、甚至早期的一些通信协议里留下了身影。
你可能会问,现在学它还有用吗?直接上AES不香吗?我的看法是,对于纯粹的生产环境,尤其是涉及网络传输或高安全等级数据的场景,AES等现代算法无疑是首选。但学习XTEA,价值在于“解剖麻雀”。它的结构清晰得惊人——核心加密函数只有寥寥数行代码,却完整包含了分组密码的核心概念:Feistel网络结构、循环移位、密钥加、与轮常数混合。通过亲手实现它,你能像看X光片一样,把分组加密的“骨骼”看得一清二楚。这对于理解更复杂的AES、SM4等算法,有莫大的帮助。这就像学编程先学C语言,不是因为它能写出最花哨的网页,而是它能让你理解内存和指针。
所以,这个项目的目的很明确: 不是鼓励你在新项目里用XTEA替代AES,而是通过从零实现XTEA这个经典算法,来深入理解对称加密的核心原理与编码实践。 我们会用Python一步步构建出完整的XTEA,包括加密、解密、以及应对不同数据长度的ECB模式操作,并附上可直接运行、逐行注释的完整源码。无论你是刚学完Python语法想找个练手项目,还是对密码学感到好奇却苦于理论晦涩,这篇文章都能给你一份清晰的“地图”。
2. XTEA算法核心原理拆解:简洁之美
在动手写代码之前,我们必须先搞懂XTEA到底是怎么工作的。不用担心,我会尽量用大白话和图示来解释,避免直接甩出一堆数学公式吓跑人。
2.1 算法的基本设定
首先,XTEA是一个 分组对称加密算法 。
- 分组 :它一次处理固定长度的数据块。XTEA的分组大小是64位(8个字节)。如果你的原始数据(明文)长度不是8字节的整数倍,就需要先进行填充(Padding),我们后面会具体处理。
- 对称 :加密和解密使用同一把密钥。这把密钥的长度是128位(16个字节)。
- Feistel结构 :这是XTEA的核心框架。它把64位的输入块分成左右两半,各32位,称为L(左)和R(右)。然后经过多轮(Round)的迭代运算,每一轮中,右半部分R经过一个轮函数F处理后,与左半部分L进行异或操作,然后左右两部分交换位置。这种结构有个巨大优点: 加密和解密的流程几乎一样 ,只是轮密钥的使用顺序相反,这极大地简化了实现。
XTEA的标准轮数是64轮。是的,64轮,听起来很多,但因为每轮运算极其简单,所以整体速度依然很快。
2.2 一轮加密的魔鬼细节
一轮加密,是理解整个算法的关键。我们定义:
L[i],R[i]是第i轮开始时的左右两部分。K[0],K[1],K[2],K[3]是我们128位密钥拆分成的4个32位整数。delta是一个魔法常数,定义为0x9E3779B9。这个数是黄金分割率相关的一个值,目的是确保每轮使用的“轮常数”都有良好的伪随机性。sum是一个累加变量,在加密过程中从0开始,每轮增加delta。
那么,第i轮的操作可以用下面这个式子概括,这也是XTEA最精华的部分: R[i+1] = L[i] + ((((R[i] << 4) ^ (R[i] >> 5)) + R[i]) ^ (sum + K[sum & 3])) L[i+1] = R[i]
我拆开给你看:
- 对R[i]做混淆 :
((R[i] << 4) ^ (R[i] >> 5)) + R[i]。这里先将R左移4位,右移5位,然后让它们异或,最后再加上R本身。这个操作的目的不是进行复杂的数学变换,而是 极大地打乱R的位信息 ,让R的每一个比特位的变化都能快速扩散到整个32位值中。移位和加法的组合,是实现非线性混淆的一个经典技巧。 - 生成轮密钥 :
(sum + K[sum & 3])。这里用当前的sum值加上密钥的一部分。sum & 3的结果只能是0,1,2,3,这就循环地从我们的4个子密钥K[0]到K[3]中选取一个。因为sum每轮都在变,所以每一轮实际使用的密钥材料都不同。 - 异或与加法 :将第1步混淆后的结果,与第2步生成的轮密钥进行异或(
^),然后再与左半部分L[i]相加。注意这里是 加法 ,不是异或。加法模2^32(即结果超过32位部分溢出丢弃),这提供了另一种非线性特性。 - 交换 :最后,将原来的
R[i]作为下一轮的L[i+1],将上面计算出的新值作为下一轮的R[i+1]。这就完成了一轮。
关键理解 :这一系列操作(移位、异或、加法、与密钥混合)的目标是制造“混淆”和“扩散”。混淆是让密钥和明文的关系变得极其复杂;扩散是让明文中一个比特的改变,影响到密文中多个比特。XTEA用非常少的操作就达到了不错的效果。
2.3 加密与解密的对称性
加密过程, sum 从0开始,每轮加上 delta 。在解密时,过程完全对称,但 sum 的初始值变成了 delta * 轮数 (64轮就是 delta * 64 ),然后每轮 减去 delta 。同时,解密时轮操作的顺序和加密是相反的(因为Feistel结构的特性),但在代码实现上,我们可以用一种非常巧妙的方式让加密和解密的函数几乎完全相同,只是传入的 sum 初始值和 delta 的符号不同。这会在源码部分看到。
3. Python实现XTEA:从理论到代码
理解了原理,现在我们来动手实现。我们会采用自底向上的方式,先实现最核心的加密/解密单块函数,再处理多块数据和填充。
3.1 核心工具函数:处理字节与整数的转换
加密算法操作的是32位整数,但我们的输入通常是字节串(bytes)。所以我们需要两个辅助函数来做转换。
import struct
def _bytes_to_uint32_list(data: bytes) -> list:
"""
将字节串转换为32位无符号整数列表。
使用struct模块按小端序(Little-Endian)解包。
"""
if len(data) % 4 != 0:
# 填充到4的倍数,这里先简单补零,实际由外层处理
data += b'\x00' * (4 - len(data) % 4)
# '<' 表示小端序, 'I' 表示32位无符号整数
# 计算有多少个整数:总字节数 / 4
count = len(data) // 4
return list(struct.unpack(f'<{count}I', data))
def _uint32_list_to_bytes(uint32_list: list) -> bytes:
"""
将32位无符号整数列表转换回字节串。
使用struct模块按小端序打包。
"""
# 将列表转换为打包格式
packed_data = struct.pack(f'<{len(uint32_list)}I', *uint32_list)
return packed_data
注意 :这里涉及一个关键概念“字节序”(Endianness)。XTEA算法原始论文中定义的操作是基于 大端序 的。然而,在常见的x86/ARM计算机系统和网络协议中, 小端序 更为普遍。许多现成的XTEA实现(包括一些C语言库)在实际中采用了小端序。为了与更多实践案例兼容, 我们的实现将采用小端序 。这是一个重要的实现细节,如果你需要与其他系统交互,必须确认双方的字节序约定是否一致。
3.2 密钥的预处理
我们的密钥是128位(16字节)。需要将它转换成4个32位整数用于运算。
def _setup_key(key: bytes) -> list:
"""
将128位(16字节)的密钥转换为4个32位整数列表。
如果密钥长度不足,用0填充;如果过长,只取前16字节。
"""
if len(key) < 16:
key = key.ljust(16, b'\x00')
elif len(key) > 16:
key = key[:16]
# 使用我们上面的转换函数
return _bytes_to_uint32_list(key)
3.3 核心的加密与解密单块函数
这是整个算法的心脏。我们实现一个函数,通过参数控制是加密还是解密。
def _crypt_block(v: list, k: list, decrypt: bool = False) -> list:
"""
加密或解密一个64位数据块。
v: 包含两个32位整数的列表,[v0, v1],代表64位数据块。
k: 4个32位整数组成的密钥列表。
decrypt: 是否为解密模式。
返回加密或解密后的两个32位整数列表。
"""
v0, v1 = v[0], v[1]
# 定义XTEA的魔数delta
delta = 0x9E3779B9
# 总轮数
n = 64
if not decrypt:
# 加密模式
sum_ = 0
for _ in range(n):
# 核心运算,对应原理部分的公式
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum_ + k[sum_ & 3])
v0 &= 0xFFFFFFFF # 模拟32位溢出
sum_ = (sum_ + delta) & 0xFFFFFFFF
# 交换v0和v1,准备下一轮
v0, v1 = v1, v0
# 最后一轮后多交换了一次,需要换回来?不,在Feistel网络中,最后一轮后不交换是标准实现。
# 仔细看我们的循环:每次循环结束前交换,循环n次。
# 当n为偶数时,最终v0, v1正好是加密后的左右部分。XTEA的n=64是偶数,所以这里正确。
else:
# 解密模式
sum_ = (delta * n) & 0xFFFFFFFF
for _ in range(n):
# 注意这里先交换,因为解密是加密的逆过程
v1, v0 = v0, v1 # 先交换,使得运算顺序与加密对应
# 解密运算,是加密运算的逆
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum_ + k[(sum_ >> 11) & 3]) # 注意密钥索引方式不同
v1 &= 0xFFFFFFFF
sum_ = (sum_ - delta) & 0xFFFFFFFF
# 解密循环结束后,需要再交换一次得到最终结果
v0, v1 = v1, v0
return [v0, v1]
实操心得1:关于“交换”的陷阱 上面代码中加密和解密部分对
v0,v1的交换处理看起来不对称,很容易写错。我最初实现时就栽在这里,解密出来的数据不对。关键是要理解:在标准的Feistel网络描述中,加密最后一轮结束后 不交换 。我们的加密循环for _ in range(n):内部,是先计算再交换。对于偶数轮(n=64),循环结束后,v0和v1已经处于最终加密状态(即最后一轮计算后未交换的状态)。解密是逆过程,所以我们需要先交换,再计算,循环结束后再交换回来。多花时间画一下2轮、4轮的数据流向图,就能彻底搞清楚。
实操心得2:32位溢出处理 Python的整数没有位数限制,但XTEA要求所有运算在32位内进行,即结果要对2^32取模。我们通过
& 0xFFFFFFFF来实现。 这一点至关重要 ,忘记这个操作会导致结果完全错误,而且这种错误很难从密文上看出来。
3.4 工作模式与填充:让算法处理任意长度数据
单块加密只能处理8字节。真实数据是任意长度的,这就需要“工作模式”和“填充”。
1. 选择工作模式:ECB 最简单的工作模式是ECB(电子密码本)模式。它就是把数据分成8字节一块,每块独立加密。ECB的缺点是,如果明文中有重复的块,加密后密文中也会出现重复的块,这会泄露信息。对于学习目的,ECB最简单直观。我们这里就实现ECB模式。
2. 处理填充:PKCS#7 当数据长度不是8字节的整数倍时,需要填充。最常用的是PKCS#7填充。规则是:缺n个字节,就填充n个值为n的字节。 例如,一个13字节的数据,块大小8字节,缺3字节,就填充 0x03 0x03 0x03 。 解密后,读取最后一个字节的值n,去掉末尾的n个字节,就得到原始数据。
def _pkcs7_pad(data: bytes, block_size: int = 8) -> bytes:
"""使用PKCS#7标准对数据进行填充。"""
padding_len = block_size - (len(data) % block_size)
padding = bytes([padding_len] * padding_len)
return data + padding
def _pkcs7_unpad(data: bytes) -> bytes:
"""移除PKCS#7填充。"""
if not data:
return data
padding_len = data[-1]
# 简单的有效性检查
if padding_len > len(data) or not all(b == padding_len for b in data[-padding_len:]):
raise ValueError("无效的PKCS#7填充")
return data[:-padding_len]
3.5 完整的加密/解密函数
现在,我们把所有部分组合起来,提供对用户友好的接口。
class XTEA:
"""XTEA加密算法的Python实现类。"""
def __init__(self, key: bytes):
"""
初始化XTEA加密器。
key: 密钥,应为16字节的字节串。如果不足或超过,会自动处理。
"""
if not isinstance(key, bytes):
raise TypeError("密钥必须是字节串(bytes)类型")
self.key = _setup_key(key)
def encrypt(self, plaintext: bytes) -> bytes:
"""
使用ECB模式加密数据。
plaintext: 明文字节串。
返回密文字节串。
"""
# 1. 填充明文
padded_data = _pkcs7_pad(plaintext, 8)
# 2. 分块
cipher_blocks = []
for i in range(0, len(padded_data), 8):
block = padded_data[i:i+8]
# 3. 将8字节块转换为两个32位整数
v = _bytes_to_uint32_list(block)
# 4. 加密这个块
encrypted_v = _crypt_block(v, self.key, decrypt=False)
# 5. 将加密结果转换回8字节
cipher_block = _uint32_list_to_bytes(encrypted_v)
cipher_blocks.append(cipher_block)
# 6. 连接所有密文块
return b''.join(cipher_blocks)
def decrypt(self, ciphertext: bytes) -> bytes:
"""
使用ECB模式解密数据。
ciphertext: 密文字节串,长度必须是8的倍数。
返回明文字节串。
"""
if len(ciphertext) % 8 != 0:
raise ValueError("密文长度必须是8字节的倍数")
# 1. 分块
plain_blocks = []
for i in range(0, len(ciphertext), 8):
block = ciphertext[i:i+8]
# 2. 将8字节块转换为两个32位整数
v = _bytes_to_uint32_list(block)
# 3. 解密这个块
decrypted_v = _crypt_block(v, self.key, decrypt=True)
# 4. 将解密结果转换回8字节
plain_block = _uint32_list_to_bytes(decrypted_v)
plain_blocks.append(plain_block)
# 5. 连接所有解密后的块
padded_plaintext = b''.join(plain_blocks)
# 6. 去除填充
return _pkcs7_unpad(padded_plaintext)
4. 完整源码与测试用例
将上面所有代码整合,并添加一些测试和示例,就得到了完整的可运行源码。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
XTEA (eXtended TEA) 加密算法的Python实现。
实现特性:
1. 完整的加密/解密功能。
2. 小端序(Little-Endian)字节处理。
3. ECB工作模式。
4. PKCS#7 填充。
5. 包含详细的注释和测试用例。
"""
import struct
def _bytes_to_uint32_list(data: bytes) -> list:
"""将字节串按小端序转换为32位无符号整数列表。"""
if len(data) % 4 != 0:
data += b'\x00' * (4 - len(data) % 4)
count = len(data) // 4
return list(struct.unpack(f'<{count}I', data))
def _uint32_list_to_bytes(uint32_list: list) -> bytes:
"""将32位无符号整数列表按小端序打包为字节串。"""
packed_data = struct.pack(f'<{len(uint32_list)}I', *uint32_list)
return packed_data
def _setup_key(key: bytes) -> list:
"""准备密钥:确保为16字节并转换为4个32位整数。"""
if len(key) < 16:
key = key.ljust(16, b'\x00')
elif len(key) > 16:
key = key[:16]
return _bytes_to_uint32_list(key)
def _crypt_block(v: list, k: list, decrypt: bool = False) -> list:
"""
加密或解密一个64位数据块。
v: [v0, v1] 两个32位整数。
k: 4个32位整数密钥。
decrypt: False为加密,True为解密。
"""
v0, v1 = v[0], v[1]
delta = 0x9E3779B9
n = 64
if not decrypt:
# 加密
sum_ = 0
for _ in range(n):
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum_ + k[sum_ & 3])
v0 &= 0xFFFFFFFF
sum_ = (sum_ + delta) & 0xFFFFFFFF
v0, v1 = v1, v0 # 交换
else:
# 解密
sum_ = (delta * n) & 0xFFFFFFFF
for _ in range(n):
v1, v0 = v0, v1 # 先交换
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum_ + k[(sum_ >> 11) & 3])
v1 &= 0xFFFFFFFF
sum_ = (sum_ - delta) & 0xFFFFFFFF
v0, v1 = v1, v0 # 最终交换
return [v0, v1]
def _pkcs7_pad(data: bytes, block_size: int = 8) -> bytes:
"""PKCS#7填充。"""
padding_len = block_size - (len(data) % block_size)
padding = bytes([padding_len] * padding_len)
return data + padding
def _pkcs7_unpad(data: bytes) -> bytes:
"""移除PKCS#7填充。"""
if not data:
return data
padding_len = data[-1]
if padding_len > len(data) or not all(b == padding_len for b in data[-padding_len:]):
raise ValueError("无效的PKCS#7填充")
return data[:-padding_len]
class XTEA:
"""XTEA加密器。"""
def __init__(self, key: bytes):
self.key = _setup_key(key)
def encrypt(self, plaintext: bytes) -> bytes:
padded_data = _pkcs7_pad(plaintext, 8)
cipher_blocks = []
for i in range(0, len(padded_data), 8):
block = padded_data[i:i+8]
v = _bytes_to_uint32_list(block)
encrypted_v = _crypt_block(v, self.key, decrypt=False)
cipher_block = _uint32_list_to_bytes(encrypted_v)
cipher_blocks.append(cipher_block)
return b''.join(cipher_blocks)
def decrypt(self, ciphertext: bytes) -> bytes:
if len(ciphertext) % 8 != 0:
raise ValueError("密文长度必须是8字节的倍数")
plain_blocks = []
for i in range(0, len(ciphertext), 8):
block = ciphertext[i:i+8]
v = _bytes_to_uint32_list(block)
decrypted_v = _crypt_block(v, self.key, decrypt=True)
plain_block = _uint32_list_to_bytes(decrypted_v)
plain_blocks.append(plain_block)
padded_plaintext = b''.join(plain_blocks)
return _pkcs7_unpad(padded_plaintext)
# ==================== 测试与示例 ====================
if __name__ == "__main__":
# 测试1:基本加密解密
print("测试1: 基本功能")
key = b'ThisIsA16ByteKey!' # 正好16字节
plaintext = b'HelloXTEA!123' # 长度13,不是8的倍数
cipher = XTEA(key)
encrypted = cipher.encrypt(plaintext)
decrypted = cipher.decrypt(encrypted)
print(f"密钥: {key}")
print(f"明文: {plaintext}")
print(f"密文(hex): {encrypted.hex()}")
print(f"解密后: {decrypted}")
assert decrypted == plaintext, "加解密失败!"
print("断言成功:加解密一致。\n")
# 测试2:空数据
print("测试2: 空数据")
plaintext = b''
encrypted = cipher.encrypt(plaintext)
decrypted = cipher.decrypt(encrypted)
print(f"空明文加密后长度: {len(encrypted)}") # 应该是8(一个填充块)
print(f"解密后: {decrypted}")
assert decrypted == plaintext
print("断言成功。\n")
# 测试3:长数据
print("测试3: 长数据")
plaintext = b'A' * 100 # 100个'A'
encrypted = cipher.encrypt(plaintext)
decrypted = cipher.decrypt(encrypted)
assert decrypted == plaintext
print(f"长数据({len(plaintext)}字节)加解密成功。\n")
# 测试4:密钥长度不足和过长
print("测试4: 密钥处理")
short_key = b'short'
long_key = b'ThisIsAVeryLongKeyThatIsMoreThan16Bytes'
cipher1 = XTEA(short_key)
cipher2 = XTEA(long_key)
plaintext = b'test data'
enc1 = cipher1.encrypt(plaintext)
dec1 = cipher1.decrypt(enc1)
enc2 = cipher2.encrypt(plaintext)
dec2 = cipher2.decrypt(enc2)
assert dec1 == plaintext and dec2 == plaintext
print("不同长度密钥处理成功。\n")
print("所有测试通过!XTEA实现基本功能正常。")
# 示例:简单字符串加密
print("\n--- 使用示例 ---")
my_key = b'MySecretKey12345' # 16字节
my_message = "这是一条需要加密的敏感信息。".encode('utf-8')
xtea = XTEA(my_key)
cipher_msg = xtea.encrypt(my_message)
print(f"原始信息: {my_message.decode('utf-8')}")
print(f"加密后(Hex): {cipher_msg.hex()[:50]}...") # 只显示前50字符
recovered_msg = xtea.decrypt(cipher_msg)
print(f"解密后: {recovered_msg.decode('utf-8')}")
5. 常见问题、排查技巧与进阶思考
即使代码写出来了,在实际运行和与其他系统对接时,你很可能还会遇到一些坑。下面是我在实现和使用过程中总结的一些典型问题和技巧。
5.1 密文解密失败?先检查这五点
如果你的加密解密流程跑不通,别急着怀疑人生,按这个清单逐一排查:
- 字节序(Endianness) :这是 头号杀手 。你的实现和你要对接的系统(比如一个用C写的服务端)字节序一致吗?我们的实现用的是小端序(
<I)。如果对方是大端序(>I),那么_bytes_to_uint32_list和_uint32_list_to_bytes函数中的格式字符就要从<换成>。密文会完全对不上。 排查方法 :用一个双方公认的测试向量(比如全零数据和固定密钥)进行测试,比对中间每一步的32位整数结果。 - 密钥处理 :密钥长度是128位吗?我们代码里虽然做了填充和截断,但最好保证输入就是16字节。不同的库对非16字节密钥的处理方式可能不同(比如重复使用或哈希成128位)。
- 填充方案 :对方使用什么填充?PKCS#7是最常见的,但也有可能用零填充(
\x00)、ANSI X.923等。填充不对,解密后去除填充时会失败或得到错误数据。 注意 :如果数据长度恰好是块大小的整数倍,PKCS#7会额外填充一个完整的块(例如8个0x08),这是标准行为。 - 轮数和Delta常数 :标准XTEA是64轮,Delta是
0x9E3779B9。有些变种(如XXTEA)或出于性能考虑可能会修改轮数。确认双方算法完全一致。 - 32位溢出处理 :在
_crypt_block函数中,所有的加法和减法操作后,是否都进行了& 0xFFFFFFFF操作?在Python里漏掉这个,数值会无限增大,导致结果错误。
5.2 性能优化与生产环境须知
我们上面的实现侧重于清晰易懂,但在性能上还有优化空间。
- 使用
int.to_bytes()和int.from_bytes():对于单块操作,直接使用int.from_bytes(block, 'little')和result.to_bytes(8, 'little')可能比struct模块稍快,代码也更简洁。但在处理长字节数组时,struct的批量打包/解包效率更高。 - 循环展开 :XTEA的64轮循环是固定的。在极端追求性能的场景下,可以手动展开几层循环,减少循环计数开销。但Python的解释器开销很大,这种优化效果有限,不如考虑用C扩展或Cython重写核心循环。
- 关于ECB模式的安全警告(再次强调) :ECB模式是不安全的!它不能隐藏明文的数据模式。绝对不要用它加密图像、有固定格式的文档等。如果用于生产, 必须 使用更安全的工作模式,如CBC(密码块链接)模式。在CBC模式下,每个明文块在加密前会先与前一个密文块进行异或,第一个块使用一个初始化向量(IV)。这需要修改我们的
encrypt/decrypt函数,传递和保存IV。
5.3 从XTEA到现代加密的思考
通过实现XTEA,我们窥见了对称加密的基石。但XTEA在今天已不被推荐用于新的安全系统,主要原因在于其64位的分组大小和相对简单的轮函数,使其在面对现代计算能力(特别是GPU和专用硬件)时,抗攻击强度不如AES(128位分组)等算法。
那么,学完XTEA后,如何顺藤摸瓜?
- 理解AES :尝试去理解AES的S盒(Substitution Box)、行移位、列混合等操作。你会发现,AES的每一步都是为了更强的混淆和扩散,其数学基础更加严谨。
- 探索工作模式 :实现一下CBC、CTR等模式。理解IV(初始化向量)的作用,以及为什么它们比ECB安全得多。
- 了解认证加密 :现代应用不仅需要保密性,还需要完整性(数据未被篡改)和真实性(数据来源可信)。这引入了如GCM这样的认证加密模式。这是XTEA时代之后的重要发展。
最后,这个XTEA的实现项目,代码本身可能只有一两百行,但希望它带给你的不是仅仅能运行的代码,而是一把打开密码学大门的钥匙。下次当你再听到“Feistel结构”、“混淆扩散”、“工作模式”这些词时,你的脑海里应该能浮现出那几行简洁的 v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum_ + k[sum_ & 3]) ,以及它背后精妙的设计思想。这才是动手实现经典算法最大的收获。
更多推荐
所有评论(0)