如何用Python解密Android端基于Bouncy Castle的AES加密Zip文件?
如何用Python解密Android端基于Bouncy Castle的AES加密Zip文件?
我仔细看了你的Kotlin加密代码和Python解密代码,问题主要出在几个细节上,我帮你梳理清楚并给出修正方案:
先说说Kotlin代码里的潜在问题
你的readFile方法有冗余且容易出错的逻辑:file.readBytes()已经完整读取了整个文件的字节内容,后面再用BufferedInputStream重复读取完全是多余的,甚至可能因为流操作覆盖正确的数据。可以直接简化成:
fun readFile(filePath: String): ByteArray { return File(filePath).readBytes() }
另外,你在创建Cipher时只写了"AES",没有明确指定加密模式和填充方式。在Bouncy Castle中,默认的AES转换规则是AES/ECB/PKCS5Padding,但你又传入了IV参数(IvParameterSpec),这在ECB模式下是不合法的——能运行说明你的Android环境可能默认用了CBC模式,但为了避免歧义,建议明确指定模式和填充,把Cipher初始化改成:
val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "BC")
这样能和Python的实现完全对齐,减少兼容性问题。
再修正你的Python代码
你的Python逻辑大体方向是对的,但手动处理填充容易出错,而且可以优化一些细节,下面是修正后的代码:
from Crypto.Cipher import AES from Crypto.Util.Padding import unpad import base64 def get_secret_key(): # 替换为你从Android端拿到的Base64编码密钥(注意是NO_WRAP格式,无换行) secret_key_encoded = "这里替换为你的AES密钥Base64字符串" decoded_key = base64.b64decode(secret_key_encoded) # 256位AES密钥必须是32字节,加个断言确保正确性 assert len(decoded_key) == 32, "AES密钥必须是256位(32字节)" return decoded_key def decrypt_file(input_file_path, output_file_path=None): try: # 自动处理输出路径 if output_file_path is None: if input_file_path.endswith('.encrypted'): output_file_path = input_file_path[:-len('.encrypted')] else: # 拆分文件名和后缀,添加_decrypted标识 name_parts = input_file_path.rsplit('.', 1) if len(name_parts) == 2: output_file_path = f"{name_parts[0]}_decrypted.{name_parts[1]}" else: output_file_path = f"{input_file_path}_decrypted" # 读取加密文件的全部内容 with open(input_file_path, 'rb') as f: encrypted_data = f.read() # 获取密钥和初始化IV(和Kotlin一致,用全0的16字节数组) key = get_secret_key() iv = bytes(16) # 初始化CBC模式的AES解密器 cipher = AES.new(key, AES.MODE_CBC, iv=iv) # 用pycryptodome自带的工具解PKCS7填充(和PKCS5对AES是等价的) decrypted_data = unpad(cipher.decrypt(encrypted_data), AES.block_size) # 保存解密后的文件 with open(output_file_path, 'wb') as f: f.write(decrypted_data) print(f"文件解密成功,已保存到: {output_file_path}") return True except Exception as e: print(f"解密出错了: {str(e)}") return False # 示例调用 if __name__ == "__main__": encrypted_zip_path = "com.android.settings_1736318346774.zip" decrypt_file(encrypted_zip_path)
几个需要确认的关键点
- 确保你从Android端拿到的Base64密钥是无换行的(Kotlin用了
Base64.NO_WRAP,所以Python解码时不用处理换行符); - 检查你的pycryptodome库是不是最新版本,旧版本可能有兼容性问题:
pip install --upgrade pycryptodome - 如果解密后的文件还是无法解压,建议对比原Zip文件和解密后的文件的字节差异,或者检查Kotlin端的加密流程是否真的用了全0IV和CBC模式。
备注:内容来源于stack exchange,提问作者Rahim T.S
相关产品推荐
相关产品推荐

