Java AES解密异常:简单测试用例失败问题求助
AES加解密异常问题分析与解决
问题描述
我编写的Java AES加解密代码,对复杂文本(如"11-24'?*&11[]")能正常完成加解密,但对简单文本"hello"执行解密时,抛出javax.crypto.BadPaddingException及NullPointerException异常,无法正常解密。
完整代码
import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; public class Test { class Encryption { File file; SecretKeySpec secretKeySpec; public void setFile(String filePathResource) throws Exception { URL url = Encryption.class.getResource(filePathResource); System.out.println(url.toString()); this.file = new File(url.toURI()); if (!file.isFile()) { System.out.println("File is not valid"); throw new Exception("The file you choosed is not valid"); } } public void setKey(String keyword) { try { MessageDigest sha = MessageDigest.getInstance("SHA-256"); sha.update(keyword.getBytes()); byte[] key = sha.digest(); secretKeySpec = new SecretKeySpec(key, "AES"); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } } public String encryptText(String text) { byte[] encryptedBytes = null; try { byte[] bytesText = text.getBytes(); Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); encryptedBytes = cipher.doFinal(bytesText); } catch (Exception e) { e.printStackTrace(); } return new String(encryptedBytes); } public String decryptText(String encryptedText) { byte[] decryptedBytes = null; try { ByteArrayOutputStream out = new ByteArrayOutputStream(); Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, secretKeySpec); byte[] encryptedTextBytes = encryptedText.getBytes(); decryptedBytes = cipher.doFinal(encryptedTextBytes); } catch (Exception e) { e.printStackTrace(); } return new String(decryptedBytes); } } public static void main(String[] args) throws IOException, URISyntaxException { Test t = new Test(); Encryption cipher = t.new Encryption(); cipher.setKey("password"); // String encryptedText=cipher.encryptText("2024-05-04T05:48:19.702630400Z[UTC]"); // String encryptedText=cipher.encryptText("11-24'?*&11[]"); String encryptedText = cipher.encryptText("hello"); System.out.println(encryptedText); System.out.println(cipher.decryptText(encryptedText)); } }
测试情况
正常测试情况
文本"11-24'?*&11[]"加密后输出:|Ä{™úk©¢[ÁÌ¿µ,解密后可还原原文本。
异常测试情况
文本"hello"加密后输出:iî]´¾-Ò?%??H,解密时报错:
iî]´¾-Ò?%??H javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption. at java.base/com.sun.crypto.provider.CipherCore.unpad(CipherCore.java:859) at java.base/com.sun.crypto.provider.CipherCore.fillOutputBuffer(CipherCore.java:939) at java.base/com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:735) at java.base/com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:436) at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2205) at Test$Encryption.decryptText(Test.java:56) at Test.main(Test.java:83) Exception in thread "main" java.lang.NullPointerException: Cannot read the array length because "bytes" is null at java.base/java.lang.String.<init>(String.java:1432) at Test$Encryption.decryptText(Test.java:61) at Test.main(Test.java:83)
原因分析
核心问题是加密后的二进制字节流直接转换为字符串会丢失关键信息:
- AES加密输出的是二进制字节数组,其中包含大量无法被默认字符集正确映射的无效字节。直接用
new String(encryptedBytes)转换时,JVM会将无法识别的字节替换为替代字符(如�),导致原始加密字节不可逆损坏。 - 复杂文本加密后,巧合下字节刚好能被字符集完整映射,所以解密正常;而"hello"这类简单文本加密后的字节包含更多无效字符,转字符串时丢失了关键字节,解密时输入的字节已不是原始加密字节,触发填充校验失败(
BadPaddingException),后续decryptedBytes为null,又引发NullPointerException。
解决方法
必须使用Base64编码将加密后的二进制字节转换为可安全存储/传输的字符串,解密时再解码回字节数组。
修改后的关键代码
加密方法
import java.nio.charset.StandardCharsets; import java.util.Base64; public String encryptText(String text) { byte[] encryptedBytes = null; try { byte[] bytesText = text.getBytes(StandardCharsets.UTF_8); Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); encryptedBytes = cipher.doFinal(bytesText); } catch (Exception e) { e.printStackTrace(); } return Base64.getEncoder().encodeToString(encryptedBytes); }
解密方法
import java.nio.charset.StandardCharsets; import java.util.Base64; public String decryptText(String encryptedText) { byte[] decryptedBytes = null; try { Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, secretKeySpec); byte[] encryptedTextBytes = Base64.getDecoder().decode(encryptedText); decryptedBytes = cipher.doFinal(encryptedTextBytes); } catch (Exception e) { e.printStackTrace(); } return decryptedBytes != null ? new String(decryptedBytes, StandardCharsets.UTF_8) : ""; }
额外注意事项
- 明确指定字符集为
StandardCharsets.UTF_8,避免不同环境默认字符集不一致导致的问题。 - 解密时判断
decryptedBytes是否为null,避免空指针异常。 - ECB模式安全性较低,不建议用于生产环境,推荐使用CBC/GCM等带初始向量(IV)的加密模式。
内容的提问来源于stack exchange,提问作者mmofood
相关产品推荐
相关产品推荐

