
本文详解如何在 Python 中正确实现与 Java 版 XXTEA 完全兼容的解密逻辑,重点修复字节序、块长度、轮数计算和 MX 函数等关键差异,确保 12 字节数据包可稳定还原为 000S45678 类格式明文。
本文详解如何在 python 中正确实现与 java 版 xxtea 完全兼容的解密逻辑,重点修复字节序、块长度、轮数计算和 mx 函数等关键差异,确保 12 字节数据包可稳定还原为 `000S45678` 类格式明文。
XXTEA(Corrected Block TEA)是一种轻量级分组密码算法,常用于嵌入式或资源受限场景。但其 Python 实现极易因字节序(endianness)、整数截断、轮数计算或 MX 运算细节与 Java 不一致而失败——尤其当输入为固定 12 字节数据包时,常见错误包括解密后乱码、高位字节丢失或解密结果全零。
✅ 核心问题诊断(基于您提供的 Java 代码)
您的原始 Python 实现存在以下关键偏差:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 字节序不匹配:Java 使用 ByteOrder.LITTLE_ENDIAN 转换 data,但 key 使用 BIG_ENDIAN;而您的代码对 data 和 key 均用 little 或 big,导致密钥扩展错误;
- 轮数(rounds)计算错误:Java 中 rounds = 1 + 52 / n(n 为 block 长度,单位:int,即 len(data)//4),而您的代码硬编码为 6 轮,不适用于 n=3(12 字节 → 3 个 int);
- MX 函数符号与括号逻辑错误:Java 的 mx() 返回 (z>>>5^y>>3^z>> → >> + & 0xFFFFFFFF)及运算优先级;
- 未处理不足 4 字节填充:XXTEA 要求输入长度为 4 字节整数倍;12 字节恰好满足,但若后续扩展需注意补零(PKCS#7 等非必需,但 Java 示例未填充,Python 也应保持原长)。
✅ 推荐解决方案:兼容 Java 的 Python XXTEA 解密器
以下为严格对标 Java btea() 和 toIntArray/toByteArray 行为的修复版实现(无需 Jython,纯 Python):
import struct
def to_int_array(data: bytes, byteorder: str = 'little') -> list:
"""Convert bytes to int array, padding with zeros if length not multiple of 4."""
n = len(data)
padded_len = ((n + 3) // 4) * 4
data_padded = data.ljust(padded_len, b' ')
fmt = ''
fmt += 'I' * (len(data_padded) // 4)
return list(struct.unpack(fmt, data_padded))
def to_byte_array(ints: list, byteorder: str = 'little') -> bytes:
"""Convert int array to bytes."""
fmt = ''
fmt += 'I' * len(ints)
return struct.pack(fmt, *ints)
def btea(v: list, n: int, k: list) -> list:
"""
XXTEA core algorithm (compatible with Java version).
v: int array (data), n: length in ints (positive for encrypt, negative for decrypt), k: 4-int key
"""
DELTA = 0x9e3779b9
MASK = 0xFFFFFFFF
if n > 1: # Encrypt
rounds = 1 + 52 // n
sum_val = 0
z = v[n - 1]
for _ in range(rounds):
sum_val = (sum_val + DELTA) & MASK
e = (sum_val >> 2) & 3
for p in range(n - 1):
y = v[p + 1]
mx_val = (((z >> 5) ^ (y > 3) ^ (z > 5) ^ (y > 3) ^ (z > 2) & 3
for p in range(n - 1, 0, -1):
z = v[p - 1]
mx_val = (((z >> 5) ^ (y > 3) ^ (z > 5) ^ (y > 3) ^ (z bytes:
"""Decrypt data using XXTEA with given key (16-byte hex key)."""
assert len(key) == 16, "Key must be exactly 16 bytes (32 hex chars)"
# Convert data & key to int arrays per Java convention
v = to_int_array(data, 'little') # data: little-endian
k = to_int_array(key, 'big') # key: big-endian
# Ensure v length >= 1; XXTEA requires at least one int
if len(v) == 0:
return b''
# Call btea with negative n for decryption
decrypted_v = btea(v[:], -len(v), k)
# Convert back to bytes (little-endian), truncate to original length
result = to_byte_array(decrypted_v, 'little')
return result[:len(data)]
# 使用示例(适配您的 12 字节分组场景)
if __name__ == "__main__":
key_hex = "91bd7a0aa75440a9bbd49d6ce0dcc0e3"
key_bytes = bytes.fromhex(key_hex)
# 假设这是您从文件读取的一个 12 字节加密段(示例密文,需替换为真实数据)
encrypted_segment = bytes.fromhex("a1b2c3d4e5f6789012345678") # ← 替换为实际密文
try:
decrypted = xxtea_decrypt(encrypted_segment, key_bytes)
print(f"Decrypted (raw): {decrypted}")
print(f"Decrypted (UTF-8): {decrypted.decode('utf-8', errors='replace')}")
# 预期输出类似: b'000\12345678' 或可打印 ASCII
except Exception as e:
print(f"Decryption failed: {e}")
⚠️ 注意事项与调试建议
- 密钥长度必须为 16 字节:XXTEA 固定使用 4×int 密钥(16 字节),key_hex 必须是 32 位十六进制字符串;
- 输入长度必须为 4 字节整数倍:12 字节(3 int)完全合法,无需填充;若遇到非 4 倍长度,请先补零至 4 倍再解密(并记录原始长度以截断);
- 验证解密结果:预期明文 000\12345678 中的 \ 是单个反斜杠(ASCII 0x5C),非转义符,解密后应直接出现 b'000\12345678';
- 性能优化:对于大批量分组,可将 xxtea_decrypt 向量化或使用 multiprocessing 并行处理(如您原代码所示),但务必确保每个分组独立解密;
- 替代方案:若仍不稳定,可考虑调用已验证的第三方库(如 [xxtea](https://www.php.cn/link/b182dcf1b0a650c56d1c286730126945 Java 一致——多数默认与 OpenSSL 兼容,而非此 Java 实现。
通过以上修正,您的 Python 解密器将严格遵循 Java XXTEACipher.btea() 的行为,可靠还原每一段 12 字节密文,真正实现跨语言 XXTEA 互通。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










