"""ImageResolver 在 V2 加密格式下的端到端解密测试。 覆盖: - v2_decrypt_file 能正确还原 AES-ECB + XOR 混合加密的合成数据 - decrypt_dat_file 按 magic 自动分发 V2 / V1 / 老 XOR 三条路径 - ImageResolver 通过 __init__ 注入 aes_key/xor_key 后,能端到端解密 V2 .dat - 没传 aes_key 时遇到 V2 文件返回结构化错误,而不是 crash 或返回错误数据 - 默认参数下老 XOR 路径不受影响,保持向后兼容 """ import hashlib import os import sqlite3 import struct import tempfile import unittest from Crypto.Cipher import AES from Crypto.Util import Padding from decode_image import ( V1_MAGIC_FULL, V2_MAGIC_FULL, ImageResolver, decrypt_dat_file, v2_decrypt_file, ) # 测试用 16 字节 AES key (任意值,仅用于合成测试数据) TEST_AES_KEY = b'1234567890abcdef' TEST_XOR_KEY = 0x37 # 最小可识别的 PNG payload (含 IHDR 和 IEND chunk),长度 88 字节 TEST_PNG_PAYLOAD = ( b'\x89PNG\r\n\x1a\n' + b'\x00\x00\x00\rIHDR' + b'\x00' * 64 + b'IEND\xaeB`\x82' ) def _build_v2_dat(plaintext, aes_size, xor_size, aes_key=TEST_AES_KEY, xor_key=TEST_XOR_KEY, magic=V2_MAGIC_FULL): """构造合成的 V2 / V1 .dat 字节串。 布局: [6B magic][4B aes_size LE][4B xor_size LE][1B pad][AES-ECB][raw][XOR] aes_size / xor_size 是明文字段长度,AES 段做 PKCS7 padding 后向上对齐到 16 倍数。 """ if aes_size + xor_size > len(plaintext): raise ValueError("aes_size + xor_size 超过 plaintext 长度") aes_plain = plaintext[:aes_size] raw_plain = plaintext[aes_size:len(plaintext) - xor_size] xor_plain = plaintext[len(plaintext) - xor_size:] cipher = AES.new(aes_key[:16], AES.MODE_ECB) aes_cipher = cipher.encrypt(Padding.pad(aes_plain, AES.block_size)) xor_cipher = bytes(b ^ xor_key for b in xor_plain) header = magic + struct.pack('