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
相关产品推荐
相关产品推荐

