You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java AES加密后Python解密长文本报错问题排查

AES跨语言解密问题排查

问题背景

使用Java代码加密的文本,短内容(如cV6aNGlm3u2sDW+z74y0uA==)可通过Python代码正常解密,但长加密数据解密时抛出UnicodeDecodeError,即使仅解密前16字节也会触发相同错误。

Java加密代码分析

Java端加密核心代码:

public static String encrypt(String value) {
    Key key = generateKey();
    byte[] encValue = new byte[0];
    Cipher c;
    try {
        c = Cipher.getInstance("AES");
        System.out.println(c.getBlockSize());
        c.init(Cipher.ENCRYPT_MODE, key);
        encValue = c.doFinal(value.getBytes());
    } catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException e) {
        log.error("Can't encrypt", e);
    }
    return Base64.getEncoder().encodeToString(encValue);
}

关键细节:

  • Cipher.getInstance("AES")在Java中默认采用AES/ECB/PKCS5Padding模式(未指定模式和填充时的标准默认实现)
  • value.getBytes()未指定编码,默认使用JVM所在平台的字符编码(如Windows下为GBK,Linux/macOS下为UTF-8)
  • ECB模式不需要初始化向量(IV)

Python解密代码的问题定位

Python端解密核心代码:

def decrypt_aes(self, encrypted_str):
    _iv = "\x00" * AES.block_size
    generator = AES.new(str.encode(self.key), AES.MODE_CBC, self._iv.encode())
    encrypted_str_bytes = base64.b64decode(encrypted_str)
    recovery = generator.decrypt(encrypted_str_bytes)
    return unpad(recovery, block_size=AES.block_size).decode()

问题根源:

  1. 加密模式不匹配:Java用ECB模式,Python却用CBC模式——这是解密乱码的核心原因。ECB和CBC是完全不同的分组加密模式,即使IV设为全0,也无法正确解密ECB加密的数据。
  2. 编码潜在不兼容:Java端value.getBytes()的默认编码可能与Python端decode()(默认UTF-8)不一致,短文本(如纯英文)因编码兼容无报错,长文本包含多字节字符时就会触发解码错误。
  3. 填充逻辑隐性冲突:Java默认PKCS5Padding,若Python的unpad函数不是标准PKCS5实现,会导致解密后内容损坏。

修复方案

修改Python解密代码,完全对齐Java端的加密逻辑:

from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import base64

def decrypt_aes(self, encrypted_str):
    # 切换为ECB模式,无需IV
    generator = AES.new(str.encode(self.key), AES.MODE_ECB)
    encrypted_str_bytes = base64.b64decode(encrypted_str)
    recovery = generator.decrypt(encrypted_str_bytes)
    # 使用标准PKCS5填充的unpad实现
    decrypted_bytes = unpad(recovery, block_size=AES.block_size)
    # 对齐Java端的默认编码:若Java用GBK则改为'gbk',否则用'utf-8'
    return decrypted_bytes.decode('utf-8')

额外注意:

  • 确认Java端generateKey()生成的密钥长度与Python端一致(AES密钥长度为16/24/32字节,对应AES-128/192/256)
  • 若Java端明确指定了编码(如value.getBytes(StandardCharsets.UTF_8)),Python端解码时需保持完全一致

内容的提问来源于stack exchange,提问作者Nikita

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 07:07:39