图片解密时抛出IllegalArgumentException异常求助
问题分析与解决方案
问题根源
你遇到的IllegalArgumentException: Input byte array has incorrect ending byte错误,本质是二进制文件(图片)被当作字符串处理导致数据损坏:
- 图片属于二进制数据,并非所有字节都对应合法的UTF-8字符。你用
getFileContent读取图片为String,再通过text.getBytes(UTF_8)转回字节数组时,部分原始字节会被替换为UTF-8的替换字符(�),导致数据永久损坏。 - 损坏后的字节再经过AES加密、Base64编码,最终写入文件的内容已经和真正的加密结果不符,解密时Base64解码器自然无法识别错误的字节序列。
解决方案
核心是全程用字节数组处理二进制数据,避免在二进制和String之间来回转换。具体需要修改以下几点:
- 加密/解密方法改为直接接收和返回
byte[],不再用String作为中间载体。 - 读取文件时用字节流读取原始二进制数据,写入文件时直接写入字节数组。
- 加密后依然用Base64编码(方便存储为文本格式),但要确保Base64的编码和解密流程基于完整的字节数据。
修改后的代码示例
1. 修正后的加密方法
import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import java.util.Base64; public static byte[] cat_encrypt(byte[] data, String pass) { try { MessageDigest messageDigest = MessageDigest.getInstance("MD5"); SecretKey key = new SecretKeySpec(messageDigest.digest(pass.getBytes(StandardCharsets.UTF_8)), "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, key); byte[] encrypted = cipher.doFinal(data); return Base64.getEncoder().encode(encrypted); } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) { throw new RuntimeException("Cannot encrypt", e); } }
2. 修正后的解密方法
public static byte[] cat_decrypt(byte[] encryptedData, String pass) { try { MessageDigest messageDigest = MessageDigest.getInstance("MD5"); SecretKey key = new SecretKeySpec(messageDigest.digest(pass.getBytes(StandardCharsets.UTF_8)), "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.DECRYPT_MODE, key); byte[] decoded = Base64.getDecoder().decode(encryptedData); return cipher.doFinal(decoded); } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) { try { sendError(e.getClass().getSimpleName()); } catch (Exception sE) { e.printStackTrace(); } throw new RuntimeException("Cannot decrypt", e); } }
3. 加密图片的调用代码
import java.nio.file.Files; import java.nio.file.Path; // 读取原始图片字节 byte[] fileBytes = Files.readAllBytes(jf.getSelectedFile().toPath()); // 加密并得到Base64编码的字节数组 byte[] encryptedBytes = encrypt.cat_encrypt(fileBytes, pass); // 写入文件(直接写Base64字节) Files.write(jf.getSelectedFile().toPath(), encryptedBytes);
4. 解密图片的调用代码
// 读取加密后的Base64字节 byte[] encryptedBytes = Files.readAllBytes(jf.getSelectedFile().toPath()); // 解密得到原始图片字节 byte[] decryptedBytes = encrypt.cat_decrypt(encryptedBytes, pass); // 写入解密后的图片文件 Files.write(Path.of("解密后的图片路径.jpg"), decryptedBytes);
额外优化建议
- AES默认的ECB模式安全性较低,建议改为CBC或GCM模式,并添加随机初始化向量(IV),避免相同明文加密后得到相同密文的问题。
- MD5生成的16字节密钥对应AES-128,若需要更强加密,可改用SHA-256生成32字节密钥对应AES-256(Java 8u161+默认支持)。
内容的提问来源于stack exchange,提问作者AlexM
相关产品推荐
相关产品推荐

