纯Python代码实现XXTEA解密核心算法
XXTEA为TEA第三代加密算法,1998年由剑桥学者提出,百行C代码实现完整加解密,轻量高效跨平台。基于纯Python实现其解密核心,支持小端序32位无符号整数处理。
XXTEA,全称是“eXtended eXtended Tiny Encryption Algorithm”,听名字就知道,它是TEA家族的第三代成员。它的诞生,说到底就是为了解决一件棘手的事:在资源极其受限的环境下,怎么才能实现一个既足够安全、代码量极小,运算速度又快的加密功能?
设计者剑桥大学的Da vid Wheeler和Roger Needham在1998年拿出了这个方案,可以看作是TEA和XTEA的“完全体”。它最大的魅力在于——用短短一百行左右的C代码,就能实现完整的加密和解密功能,而且这段代码几乎可以不加修改地移植到任何平台上。从8位单片机到最新的服务器CPU,都能流畅运行。这种“轻装上阵”的能力,在当时的加密算法中非常罕见。

纯 Python 实现的 XXTEA 解密核心算法
import os
import sys
import struct
# 配置游戏对应的密钥和签名
KEY = b"你的秘钥"
SIGN = b"4meJnPyl"
SIGN_LEN = len(SIGN)
def _long2str(v, w):
n = (len(v) - 1) << 2
if w:
m = v[-1]
if (m < n - 3) or (m > n): return None
n = m
s = struct.pack('<%dL' % len(v), *v)
return s[0:n] if w else s
def _str2long(s, w):
n = len(s)
m = (4 - (n & 3)) & 3
s += b'\x00' * m
v = list(struct.unpack('<%dL' % (len(s) >> 2), s))
if w: v.append(n)
return v
def xxtea_decrypt(data, key):
"""纯 Python 实现的 XXTEA 解密核心算法"""
if not data: return data
v = _str2long(data, False)
k = _str2long(key.ljust(16, b'\x00')[:16], False)
n = len(v) - 1
z = v[n]
y = v[0]
delta = 0x9E3779B9
q = 6 + 52 // (n + 1)
sum_val = (q * delta) & 0xFFFFFFFF
while sum_val != 0:
e = (sum_val >> 2) & 3
for p in range(n, 0, -1):
z = v[p - 1]
v[p] = (v[p] - (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum_val ^ y) + (k[p & 3 ^ e] ^ z)))) & 0xFFFFFFFF
y = v[p]
z = v[n]
v[0] = (v[0] - (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum_val ^ y) + (k[0 & 3 ^ e] ^ z)))) & 0xFFFFFFFF
y = v[0]
sum_val = (sum_val - delta) & 0xFFFFFFFF
return _long2str(v, True)
def decrypt_file(file_path):
if not os.path.exists(file_path):
print(f"[错误] 文件不存在: {file_path}")
return
print(f"[处理] 正在读取文件: {file_path}")
try:
with open(file_path, 'rb') as f:
encrypted_data = f.read()
# 检测并自动剔除文件头的签名
if encrypted_data.startswith(SIGN):
print(f"[检测] 发现文件头签名 '{SIGN.decode()}',已自动裁剪前 {SIGN_LEN} 字节。")
encrypted_data = encrypted_data[SIGN_LEN:]
else:
print("[提示] 未发现已知文件头签名,尝试直接整包解密。")
# 执行纯 Python 版 XXTEA 解密
decrypted_data = xxtea_decrypt(encrypted_data, KEY)
if not decrypted_data:
print("[失败] 解密结果为空(可能 Key 错误,或该文件并非 XXTEA 加密)。")
return
# 生成输出文件(保持原后缀方便直接预览)
dir_name, file_name = os.path.split(file_path)
base_name, ext = os.path.splitext(file_name)
output_name = f"{base_name}_decrypted{ext}" if ext else f"{base_name}_decrypted"
output_path = os.path.join(dir_name, output_name)
with open(output_path, 'wb') as f:
f.write(decrypted_data)
print(f"[成功] 解密完成!已生成文件: {output_path}")
except Exception as e:
print(f"[报错] 解密过程中间出现异常: {e}")
if __name__ == "__main__":
if len(sys.argv) > 1:
for path in sys.argv[1:]:
decrypt_file(path)
else:
print("提示: 你可以直接把文件拖到此工具上运行。")
path = input("或者请输入要解密的文件路径: ").strip('"')
if path:
decrypt_file(path)
input("处理完毕,按下回车键退出...")知识扩展
XXTEA 是 TEA 分组密码家族的一员,1998年由 Da vid Wheeler 和 Roger Needham 提出。它修正了 XTEA 的一些缺陷,最关键的改进是支持任意长度的数据块,不再局限于 64 位,同时保持了简单的 Feistel 结构。
算法核心特点
- 分组长度:不固定,可以是任意 32 位字(32-bit word)的整数倍,也就是 4 字节的倍数。
- 密钥长度:固定 128 位(16 字节),内部转换成 4 个 32 位整数来使用。
- 轮数:取决于数据长度,计算公式是
6 + 52 / n,这里的n是 32 位字的个数。数据越短,轮数越多,反过来也成立。 - 运算:只用到了加法、减法、异或、移位这些基本整数运算,因此非常适合嵌入式等资源受限的环境。
- 填充:原始数据长度不一定正好是 4 的倍数,这时需要进行填充,通常使用 PKCS#7。
下面提供两种纯 Python 的实现,它们都不依赖任何第三方库,开箱即用,适合直接集成到项目中。
方法一:精简实现
import struct
def _bytes_to_uint32(data: bytes) -> list:
"""将字节串转换为 32 位无符号整数列表(小端序)"""
n = len(data)
# 补齐到 4 的倍数
if n % 4 != 0:
data += b'\x00' * (4 - n % 4)
return list(struct.unpack('<{}I'.format(len(data)//4), data))
def _uint32_to_bytes(arr: list) -> bytes:
"""将 32 位无符号整数列表转换为字节串(小端序)"""
return struct.pack('<{}I'.format(len(arr)), *arr)
def _mx(z, y, sum_val, p, e, k):
"""XXTEA 轮函数中的辅助计算"""
return (((z >> 5) ^ (y << 2)) + ((y >> 3) ^ (z << 4))) ^ ((sum_val ^ y) + (k[(p & 3) ^ e] ^ z))
def xxtea_decrypt(data: bytes, key: bytes) -> bytes:
"""
XXTEA 解密核心算法
:param data: 密文字节串(长度应为 4 的倍数)
:param key: 密钥字节串(长度任意,内部将扩展/截断为 16 字节)
:return: 解密后的明文字节串(自动去除填充)
"""
if len(data) < 8:
raise ValueError("密文长度过短(至少需要 8 字节)")
# 将密钥转换为 4 个 32 位整数(小端序)
key_bytes = key.ljust(16, b'\x00')[:16] # 补齐或截断到 16 字节
k = _bytes_to_uint32(key_bytes) # k[0..3]
# 将密文转换为 32 位整数数组
v = _bytes_to_uint32(data)
n = len(v)
if n < 2:
raise ValueError("密文至少需要 2 个 32 位字")
# 解密常数
DELTA = 0x9E3779B9
rounds = 6 + 52 // n # 轮数(标准实现)
sum_val = (rounds * DELTA) & 0xFFFFFFFF
y = v[0]
# 主解密循环
while rounds > 0:
e = (sum_val >> 2) & 3
for p in range(n-1, -1, -1):
z = v[p-1] if p > 0 else v[-1]
mx_val = _mx(z, y, sum_val, p, e, k)
v[p] = (v[p] - mx_val) & 0xFFFFFFFF
y = v[p]
sum_val = (sum_val - DELTA) & 0xFFFFFFFF
rounds -= 1
# 将整数数组转换回字节
plain_bytes = _uint32_to_bytes(v)
# 去除 PKCS#7 风格填充(解密后末尾的填充字节)
pad_len = plain_bytes[-1]
if pad_len <= len(plain_bytes):
return plain_bytes[:-pad_len]
else:
# 填充格式不正确时返回原始解密结果
return plain_bytes方法二:完整实现(含加密函数)
import struct
def _bytes_to_uint32(data: bytes) -> list:
"""字节串 -> 小端序 32 位无符号整数列表,长度自动补齐到 4 的倍数"""
n = len(data)
if n % 4 != 0:
data += b'\x00' * (4 - n % 4)
return list(struct.unpack(f'<{len(data)//4}I', data))
def _uint32_to_bytes(arr: list) -> bytes:
"""小端序 32 位整数列表 -> 字节串"""
return struct.pack(f'<{len(arr)}I', *arr)
def xxtea_encrypt(plain: bytes, key: bytes) -> bytes:
"""
加密任意字节串,返回密文字节串(自动添加 PKCS#7 填充)
key: 任意长度的密钥,内部将截断或补零至 16 字节
"""
if len(plain) == 0:
return b''
# PKCS#7 填充:补足到 4 字节整数倍
pad_len = 4 - (len(plain) % 4)
if pad_len == 4:
pad_len = 0
if pad_len:
plain += bytes([pad_len]) * pad_len
key_bytes = key.ljust(16, b'\x00')[:16]
k = _bytes_to_uint32(key_bytes)
v = _bytes_to_uint32(plain)
n = len(v)
if n < 2:
v += [0] * (2 - n)
n = 2
DELTA = 0x9E3779B9
rounds = 6 + 52 // n
sum_val = 0
y = v[0]
for _ in range(rounds):
e = (sum_val >> 2) & 3
for p in range(n):
z = v[p-1] if p > 0 else v[-1]
mx = (((z >> 5) ^ (y << 2)) + ((y >> 3) ^ (z << 4))) ^ ((sum_val ^ y) + (k[(p & 3) ^ e] ^ z))
v[p] = (v[p] + mx) & 0xFFFFFFFF
y = v[p]
sum_val = (sum_val + DELTA) & 0xFFFFFFFF
return _uint32_to_bytes(v)
def xxtea_decrypt(cipher: bytes, key: bytes) -> bytes:
if len(cipher) == 0:
return b''
if len(cipher) % 4 != 0:
raise ValueError("密文长度必须是 4 的倍数")
key_bytes = key.ljust(16, b'\x00')[:16]
k = _bytes_to_uint32(key_bytes)
v = _bytes_to_uint32(cipher)
n = len(v)
if n < 2:
raise ValueError("密文至少需要 8 字节")
DELTA = 0x9E3779B9
rounds = 6 + 52 // n
sum_val = (rounds * DELTA) & 0xFFFFFFFF
y = v[0]
for _ in range(rounds):
e = (sum_val >> 2) & 3
for p in range(n-1, -1, -1):
z = v[p-1] if p > 0 else v[-1]
mx = (((z >> 5) ^ (y << 2)) + ((y >> 3) ^ (z << 4))) ^ ((sum_val ^ y) + (k[(p & 3) ^ e] ^ z))
v[p] = (v[p] - mx) & 0xFFFFFFFF
y = v[p]
sum_val = (sum_val - DELTA) & 0xFFFFFFFF
plain_bytes = _uint32_to_bytes(v)
pad_len = plain_bytes[-1]
if pad_len <= len(plain_bytes):
return plain_bytes[:-pad_len]
else:
return plain_bytes核心要点说明
- 数据格式:XXTEA 的最小操作单元是 32 位无符号整数(4 字节)。两套实现都采用了小端序进行字节与整数之间的转换。
- 密钥处理:密钥统一转为 4 个 32 位整数,不足 16 字节补 0x00,超出则截断。
- 轮数计算:
rounds = 6 + 52 / n,n是整数数组的长度。数据块越大,轮数越少,这算是一个很巧妙的设计。 - 解密过程:先初始化
sum_val = rounds * DELTA,然后逆向循环逐轮减少DELTA,内部从n-1到0的顺序更新每个整数,使用_mx辅助函数算出差值并减去。 - 填充处理:解密结果末尾的字节表示填充长度,按 PKCS#7 风格直接去除即可。
使用注意事项
- 密钥长度:建议使用 16 字节(128 位),安全性最高。
- 数据长度:算法本身不限制数据长度,但加密前要求数据长度是 4 的倍数,靠填充来解决。
- 端序:上面的代码都采用小端序,这与大多数已知的 XXTEA 实现是一致的(例如 QQ、微信等常见应用都用的这小端序版本)。如果你需要跟某个特定的系统对接,记得先确认对方的端序。
- 安全性:2010 年后学术界确实提出了一些针对 XXTEA 的理论攻击。对于非极敏感数据,它仍然够用。不过,如果是核心业务或金融级场景,现代应用更推荐使用 AES。
Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。
极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。
















