纯Python代码实现XXTEA解密核心算法
简介
XXTEA,全称是“eXtended eXtended Tiny Encryption Algorithm”,顾名思义,它是TEA (微型加密算法)家族的第三代成员。它的诞生就是为了解决一个核心矛盾:在资源极其受限的环境下,如何实现一个足够安全、代码量极小、运算速度又快的加密功能。它的设计者,剑桥大学的David 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'\0' * 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'\0')[: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("\n处理完毕,按下回车键退出...")知识扩展
XXTEA(eXtended eXtended TEA)是 TEA 分组密码家族的一个成员,由 David Wheeler 和 Roger Needham 于 1998 年提出。它修正了之前 XTEA 算法的缺陷,支持任意长度的数据块(不限于 64 位),并保持了简单的 Feistel 结构。
算法核心特点
- 分组长度:不固定,可以是任意 32 位字(32-bit word)的整数倍(即 4 字节的倍数)。
- 密钥长度:128 位(16 字节),固定转换为 4 个 32 位整数。
- 轮数:取决于数据长度,计算公式为
6 + 52 / n,其中n是 32 位字的个数。 - 运算:仅使用加法、减法、异或、移位等基本整数运算,非常适合嵌入式环境。
- 填充:当原始数据不是 4 字节倍数时,需要进行填充(通常使用 PKCS#7)。
方法一:
以下是纯 Python 实现的 XXTEA 解密核心算法,包含必要的辅助函数,不依赖任何第三方库。
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
# ========== 使用示例 ==========
if __name__ == "__main__":
# 测试数据(可以用已知的加密结果验证)
key = b'my_secret_key_16' # 密钥(16字节,不足会自动补零)
plaintext = b"Hello, XXTEA!"
print("原始明文:", plaintext)
# 这里假设你已经有了加密函数,或者使用一个已知的密文进行解密测试
# 为演示,我们手动构造一个简单的加密后再解密的例子(需先实现加密)
# 实际使用中,你只需要调用 xxtea_decrypt 即可。
# 为了完整性,提供一个简单的加密函数(纯Python,便于测试)
def xxtea_encrypt(plain: bytes, key: bytes) -> bytes:
if len(plain) == 0:
return b''
# PKCS#7 填充
pad_len = 4 - (len(plain) % 4)
if pad_len == 4:
pad_len = 0
if pad_len:
plain += bytes([pad_len]) * pad_len
v = _bytes_to_uint32(plain)
n = len(v)
k = _bytes_to_uint32(key.ljust(16, b'\x00')[:16])
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_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
return _uint32_to_bytes(v)
# 加密 -> 解密测试
cipher = xxtea_encrypt(plaintext, key)
print("加密后密文:", cipher)
decrypted = xxtea_decrypt(cipher, key)
print("解密后明文:", decrypted)
assert decrypted == plaintext, "加解密不匹配"核心要点说明
数据格式:XXTEA 操作的基本单元是 32 位无符号整数(4 字节)。本实现使用小端序字节与整数之间的转换。
密钥处理:密钥被转换为 4 个 32 位整数,不足 16 字节时补 0x00,超过则截断。
轮数计算:轮数 rounds = 6 + 52 / n,其中 n 是整数数组的长度(即 32 位字的个数)。
解密过程:
- 初始化
sum_val = rounds * DELTA。 - 逆向循环,每次减少
DELTA,内部按n-1到0的顺序更新每个整数。 - 使用
_mx辅助函数计算差值并减去。
填充处理:解密后末尾的字节表示填充长度(PKCS#7 风格),据此去除填充字节。
该实现完全自包含,可独立运行,适用于任何支持 Python 3 的环境。
方法二:
下面的实现完全基于纯 Python,不依赖任何第三方库,包含:
- 字节与 32 位整数数组的相互转换(小端序)
- 加密函数(带 PKCS#7 填充)
- 解密函数(自动去填充)
- 核心轮函数
_mx
import struct
# ---------- 辅助函数:字节 ↔ 32位整数数组 ----------
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)
# ---------- XXTEA 加密 ----------
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
# 将密钥转换为 4 个 32 位整数
key_bytes = key.ljust(16, b'\x00')[:16]
k = _bytes_to_uint32(key_bytes)
# 将明文转换为 32 位整数数组
v = _bytes_to_uint32(plain)
n = len(v)
if n < 2:
# 长度至少为 2 个字(8 字节)
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)
# ---------- XXTEA 解密 ----------
def xxtea_decrypt(cipher: bytes, key: bytes) -> bytes:
"""
解密密文字节串,自动去除 PKCS#7 填充
"""
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)
# 将密文转换为 32 位整数数组
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
# 转换回字节并去除 PKCS#7 填充
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
# ---------- 测试示例 ----------
if __name__ == "__main__":
key = b'my_secret_key_16' # 16 字节密钥
plain = b"Hello, XXTEA! This is a test."
print("原 文:", plain)
cipher = xxtea_encrypt(plain, key)
print("密 文:", cipher)
decrypted = xxtea_decrypt(cipher, key)
print("解密后:", decrypted)
assert decrypted == plain, "加解密不一致"使用注意事项
- 密钥长度:建议使用 16 字节(128 位),安全性最高。
- 数据长度:XXTEA 算法本身可以处理任意长度的数据,但内部要求加密前数据长度为 4 的倍数(通过填充实现)。
- 端序:上述实现采用小端序,与大多数 XXTEA 标准实现一致(如 QQ、微信等常用的小端序版本)。如果需要与特定系统对接,请确认端序是否匹配。
- 安全性:XXTEA 在 2010 年后被认为存在一些理论的攻击,但对于非极敏感数据仍然足够。现代应用更推荐使用 AES。
到此这篇关于纯Python代码实现XXTEA解密核心算法的文章就介绍到这了,更多相关Python XXTEA解密算法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
Python3.5 win10环境下导入kera/tensorflow报错的解决方法
这篇文章主要介绍了Python3.5 win10环境下导入keras/tensorflow报错的解决方法,较为详细的分析了Python3.5在win10环境下导入keras/tensorflow提示错误的原因与相关解决方法,需要的朋友可以参考下2019-12-12
解决win10 vscode 无法激活python 虚拟环境的问题
这篇文章主要介绍了win10 vscode 无法激活python 虚拟环境的解决办法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下2021-10-10


最新评论