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

AES解密报javax.crypto.BadPaddingException错误求助

问题分析与解决方案

问题根源

你遇到的javax.crypto.BadPaddingException,核心原因是代码中使用了静态的Cipher实例,而Cipher类本身并非线程安全。

加密程序是单线程调用加密+解密验证,不会触发线程安全问题;但如果解密程序是多线程环境(比如Web应用、多线程任务),多个线程共用同一个静态Cipher实例时,会导致init()和doFinal()操作交叉执行,破坏Cipher的内部状态,最终解密出错误的字节数据,引发填充验证失败。

修复方案

方案1:每次加密/解密创建新的Cipher实例

去掉静态的aes变量,在加密和解密方法内直接创建Cipher实例,确保每个操作都使用独立的实例,从根本上避免线程安全问题:

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.Base64;

public class EncryptionUtility {

    private static byte[] key_data = { (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08,
            (byte) 0x09, (byte) 0x0a, (byte) 0x0b, (byte) 0x0c, (byte) 0x0d, (byte) 0x0e, (byte) 0x0f, (byte) 0x10 };

    private static byte[] iv_data = { (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08,
            (byte) 0x09, (byte) 0x0a, (byte) 0x0b, (byte) 0x0c, (byte) 0x0d, (byte) 0x0e, (byte) 0x0f, (byte) 0x10 };

    private EncryptionUtility() {
    }

    public static String encrypt(String target) throws GeneralSecurityException {
        Cipher aes = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKey key = new SecretKeySpec(key_data, "AES");
        IvParameterSpec iv = new IvParameterSpec(iv_data);
        aes.init(Cipher.ENCRYPT_MODE, key, iv);
        return base64Encode(aes.doFinal(target.getBytes(StandardCharsets.UTF_8)));
    }

    private static String base64Encode(byte[] encrypted) {
        return Base64.getEncoder().encodeToString(encrypted);
    }

    public static String decrypt(String encrypted) throws GeneralSecurityException, IOException {
        Cipher aes = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKey key = new SecretKeySpec(key_data, "AES");
        IvParameterSpec iv = new IvParameterSpec(iv_data);
        aes.init(Cipher.DECRYPT_MODE, key, iv);
        return new String(aes.doFinal(base64Decode(encrypted)), StandardCharsets.UTF_8);
    }

    private static byte[] base64Decode(String property) throws IOException {
        return Base64.getDecoder().decode(property);
    }
}

方案2:使用ThreadLocal存储线程专属的Cipher实例

如果担心频繁创建Cipher实例的性能开销,可以用ThreadLocal为每个线程分配独立的Cipher实例,既保证线程安全,又减少实例创建次数:

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.Base64;

public class EncryptionUtility {

    private static byte[] key_data = { (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08,
            (byte) 0x09, (byte) 0x0a, (byte) 0x0b, (byte) 0x0c, (byte) 0x0d, (byte) 0x0e, (byte) 0x0f, (byte) 0x10 };

    private static byte[] iv_data = { (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08,
            (byte) 0x09, (byte) 0x0a, (byte) 0x0b, (byte) 0x0c, (byte) 0x0d, (byte) 0x0e, (byte) 0x0f, (byte) 0x10 };

    private static final ThreadLocal<Cipher> AES_CIPHER = ThreadLocal.withInitial(() -> {
        try {
            return Cipher.getInstance("AES/CBC/PKCS5Padding");
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            throw new RuntimeException("Failed to initialize AES cipher", e);
        }
    });

    private EncryptionUtility() {
    }

    public static String encrypt(String target) throws GeneralSecurityException {
        Cipher aes = AES_CIPHER.get();
        SecretKey key = new SecretKeySpec(key_data, "AES");
        IvParameterSpec iv = new IvParameterSpec(iv_data);
        aes.init(Cipher.ENCRYPT_MODE, key, iv);
        return base64Encode(aes.doFinal(target.getBytes(StandardCharsets.UTF_8)));
    }

    private static String base64Encode(byte[] encrypted) {
        return Base64.getEncoder().encodeToString(encrypted);
    }

    public static String decrypt(String encrypted) throws GeneralSecurityException, IOException {
        Cipher aes = AES_CIPHER.get();
        SecretKey key = new SecretKeySpec(key_data, "AES");
        IvParameterSpec iv = new IvParameterSpec(iv_data);
        aes.init(Cipher.DECRYPT_MODE, key, iv);
        return new String(aes.doFinal(base64Decode(encrypted)), StandardCharsets.UTF_8);
    }

    private static byte[] base64Decode(String property) throws IOException {
        return Base64.getDecoder().decode(property);
    }
}

额外排查点

  1. 确保待解密字符串无隐藏字符:比如前后空格、换行符,可先调用encrypted.trim()再尝试解密(注意Base64字符串本身不应包含这些字符)。
  2. 统一算法名称大小写:将SecretKeySpec构造函数中的"aes"改为"AES",避免部分JCE提供者对大小写敏感的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 06:22:03