XXTEA解密故障:Python实现无法解密12字节数据包求助
Python XXTEA解密失效的排查方案
XXTEA跨语言实现最容易栽在字节序、数据填充、密钥处理这几个细节上,结合你的场景(12字节数据包、解密后格式000\12345678),按以下步骤排查:
1. 字节序必须和Java对齐
Java默认使用**大端(Big-Endian)**处理32位整数,而很多Python XXTEA库或自定义实现默认用小端(Little-Endian),这是头号坑:
- 检查Python代码中字节与32位整数互转的逻辑:用
struct.unpack('!I', ...)和struct.pack('!I', ...)指定大端,对应Java的ByteBuffer默认行为。 - 比如Java中
ByteBuffer.wrap(cipherBytes).getInt()是大端读取,Python要完全匹配这个逻辑。
2. 数据块与填充规则匹配
你的数据包是12字节(3个32位整数块),解密后有效内容是000\12345678(长度10字节左右):
- 确认Java加密时是否对原始明文做了填充(比如补
\x00到12字节),Python解密后需要手动移除填充字节,比如用plain_bytes.rstrip(b'\x00')截断到有效长度。 - 如果Java用了自定义填充(比如补特定字符),Python必须执行完全相同的反向操作。
3. 密钥处理完全一致
XXTEA标准密钥是16字节(4个32位整数),两边处理逻辑要丝毫不差:
- 检查Java是否将密钥字符串按UTF-8转字节数组,再转成4个大端32位整数;Python要做同样的编码转换,不足16字节的话补
\x00对齐。 - 比如Java代码:
byte[] keyBytes = "your-key".getBytes(StandardCharsets.UTF_8);,Python对应key_bytes = b"your-key".ljust(16, b'\x00')。
4. 核心算法逻辑对比
把Java和Python的XXTEA核心循环逐行对比,重点看:
- 轮数是否为32轮,delta值是否为
0x9E3779B9; - 解密时的循环顺序是否和Java反向(加密是正向轮,解密是逆向轮);
- 异或、加法的操作顺序是否一致,避免出现运算优先级或变量顺序错误。
快速验证方法
用同一明文(比如b"000\\12345678")和密钥,先跑Java加密得到密文,再用Python解密这个密文:
- 如果能解密成功,说明你的Python代码处理现有数据包时可能存在数据读取问题(比如12字节数据包截取错误);
- 如果解密失败,直接对比两边的中间值(比如密文转成的整数数组、每轮解密后的数组),定位差异点。
对齐Java的Python XXTEA解密示例
import struct DELTA = 0x9E3779B9 def xxtea_decrypt(cipher_bytes, key_bytes): # 密钥处理:转4个大端32位整数,不足16字节补0 key = struct.unpack('!4I', key_bytes.ljust(16, b'\x00')) # 12字节密文转3个大端32位整数 if len(cipher_bytes) != 12: raise ValueError("Invalid packet length (must be 12 bytes)") cipher = list(struct.unpack('!3I', cipher_bytes)) n = len(cipher) sum_val = DELTA * n y = cipher[0] z = cipher[-1] q = 6 + 52 // n while q > 0: sum_val -= DELTA y_idx = (n - 1) & (0xFF & (z >> 2)) y = cipher[y_idx] ^ (sum_val + z) z_idx = (n - 1) & (0xFF & (y >> 2)) z = cipher[z_idx] ^ (sum_val + y) q -= 1 # 转大端字节串,移除填充 plain_bytes = struct.pack('!3I', *cipher) # 按已知格式截断到有效长度(假设明文是10字节) return plain_bytes[:10].decode('utf-8')
内容的提问来源于stack exchange,提问作者Christophe Marteil
相关产品推荐
相关产品推荐

