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

Java AES加密:解决IllegalBlockSizeException及BadPaddingException问题

问题解决:AES加解密的IllegalBlockSizeException与BadPaddingException修复

核心问题分析

1. 二进制字节直接转UTF-8字符串的错误

原加密方法中,将包含IV、盐和密文的二进制数组直接通过new String(finalCiphertext, StandardCharsets.UTF_8)转为字符串,这会导致字节丢失或损坏:二进制字节并非都是合法的UTF-8编码,转换过程中会替换无效字节,解密时还原的字节数组和加密时的原始数组不一致,从而触发IllegalBlockSizeException。

2. Hex转字节数组的方法错误

你尝试的Hex转字节逻辑完全错误:将Hex字符转成二进制字符串(比如'A'转"1010"),再调用getBytes(),得到的是二进制字符串的ASCII编码('0'对应48,'1'对应49),而非原始的加密字节数组,自然会导致解密时密钥不匹配或数据损坏,触发BadPaddingException。

3. 密钥生成的逻辑错误

原代码中加密和解密时,使用password(要加密的密码)而非masterpassword(主密码)生成密钥,这完全违背了“用主密码加密普通密码”的需求,直接导致解密时密钥错误。


解决方案与修正代码

第一步:实现正确的Hex与字节数组互转工具

替换你错误的Hex转换逻辑,使用标准的Hex编码/解码方式:

public class HexUtils {
    // 字节数组转Hex字符串
    public static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02X", b));
        }
        return sb.toString();
    }

    // Hex字符串转字节数组
    public static byte[] hexToBytes(String hexStr) {
        if (hexStr.length() % 2 != 0) {
            throw new IllegalArgumentException("Hex字符串长度必须是偶数");
        }
        byte[] result = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length(); i += 2) {
            result[i / 2] = (byte) Integer.parseInt(hexStr.substring(i, i + 2), 16);
        }
        return result;
    }
}

第二步:修正加解密方法的核心逻辑

修复密钥生成的错误,替换字节-字符串的转换方式为Hex编码:

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;

public class AESEncryption implements EncryptionModuleInterface {
    private static final int ITERATION_COUNT = 1000000;
    private static final int KEY_LENGTH = 256;
    private static final String PBKDF_ALGORITHM = "PBKDF2WithHmacSHA1";
    private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding";
    private static final String ALGORITHM = "AES";

    @Override
    public String encryptPassword(String password, String masterpassword) {
        byte[] finalCiphertext;

        SecureRandom random = new SecureRandom();
        byte[] salt = new byte[16];
        random.nextBytes(salt);

        // 修复:用masterpassword生成密钥,而非要加密的password
        KeySpec spec = new PBEKeySpec(masterpassword.toCharArray(), salt, ITERATION_COUNT, KEY_LENGTH);

        try {
            SecretKeyFactory factory = SecretKeyFactory.getInstance(PBKDF_ALGORITHM);
            byte[] key = factory.generateSecret(spec).getEncoded();
            SecretKeySpec keySpec = new SecretKeySpec(key, ALGORITHM);

            byte[] ivBytes = new byte[16];
            random.nextBytes(ivBytes);
            IvParameterSpec iv = new IvParameterSpec(ivBytes);

            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);

            byte[] inputBytes = password.getBytes(StandardCharsets.UTF_8);
            byte[] encValue = cipher.doFinal(inputBytes);

            // 拼接IV、盐、密文
            finalCiphertext = new byte[ivBytes.length + salt.length + encValue.length];
            System.arraycopy(ivBytes, 0, finalCiphertext, 0, ivBytes.length);
            System.arraycopy(salt, 0, finalCiphertext, ivBytes.length, salt.length);
            System.arraycopy(encValue, 0, finalCiphertext, ivBytes.length + salt.length, encValue.length);

        } catch (NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException |
                 InvalidKeySpecException | NoSuchAlgorithmException | IllegalBlockSizeException | BadPaddingException e) {
            throw new RuntimeException(e);
        }

        // 替换:用Hex编码转字符串,而非直接转UTF-8
        return HexUtils.bytesToHex(finalCiphertext);
    }

    @Override
    public String decryptPassword(String encryptedHex, String masterpassword) {
        byte[] ivBytes = new byte[16];
        byte[] salt = new byte[16];
        byte[] encValue;

        // 替换:将Hex字符串转回字节数组
        byte[] readEncryptedBytesWithIvAndSaltPrefix = HexUtils.hexToBytes(encryptedHex);
        byte[] inputBytes = new byte[readEncryptedBytesWithIvAndSaltPrefix.length - 32];

        System.arraycopy(readEncryptedBytesWithIvAndSaltPrefix, 0, ivBytes, 0, 16);
        System.arraycopy(readEncryptedBytesWithIvAndSaltPrefix, 16, salt, 0, 16);
        System.arraycopy(readEncryptedBytesWithIvAndSaltPrefix, 32, inputBytes, 0, readEncryptedBytesWithIvAndSaltPrefix.length - 32);

        // 修复:用masterpassword生成密钥
        KeySpec spec = new PBEKeySpec(masterpassword.toCharArray(), salt, ITERATION_COUNT, KEY_LENGTH);

        try {
            SecretKeyFactory factory = SecretKeyFactory.getInstance(PBKDF_ALGORITHM);
            byte[] key = factory.generateSecret(spec).getEncoded();
            SecretKeySpec keySpec = new SecretKeySpec(key, ALGORITHM);

            IvParameterSpec iv = new IvParameterSpec(ivBytes);

            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);

            encValue = cipher.doFinal(inputBytes);

        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException |
                 BadPaddingException | InvalidKeySpecException | InvalidAlgorithmParameterException e) {
            throw new RuntimeException(e);
        }

        return new String(encValue, StandardCharsets.UTF_8);
    }
}

关键修复点总结

  • 替换字节-字符串转换方式:二进制密文必须用Hex或Base64编码为字符串,不能直接转UTF-8,避免字节损坏
  • 修正Hex转字节逻辑:直接将每两个Hex字符解析为一个字节,而非转成二进制字符串再编码
  • 修复密钥生成逻辑:始终使用masterpassword生成加密密钥,而非待加密的password,确保加解密密钥一致

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 20:55:56