使用 aes/ecb/pkcs5padding 解密字节数组时出现 IllegalBlockSizeException
IllegalBlockSizeException when using aes/ecb/pkcs5padding to decrypt a byte array
我知道 aes 加密需要以 16 为一组,但我的印象是使用 Cipher.getInstance("AES/ECB/PKCS5PADDING");
填充字节数组来实现这一点。我的代码如下:
CipherUtils.java
private static byte[] key = {
0x74, 0x68, 0x69, 0x73, 0x49, 0x73, 0x41, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4b, 0x65, 0x79
};//"thisIsASecretKey";
public static byte[] EncryptByteArray(byte[] array)
{
try
{
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return (cipher.doFinal(array));
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public static byte[] DecryptByteArray(byte[] array)
{
try
{
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
return cipher.doFinal(array);
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
主程序
fis = new FileInputStream(path);
toDecrypt = new byte[fis.available()+1];
int content;
int i = 0;
while ((content = fis.read()) != -1) {
// convert to byte and display it
toDecrypt[i] = (byte)content;
i += 1;
}
byte[] decryptedStr = CipherUtils.DecryptByteArray(toDecrypt);
FileOutputStream decryptedStream = new FileOutputStream(path);
decryptedStream.write (decryptedStr);
decryptedStream.close();
path
处的文件使用 cipherutils.java 中的函数加密,并使用 FileOutputStream.write
写入文件
更新 - 我正在使用 Gradle 为 Android 构建。
这是问题所在:
toDecrypt = new byte[fis.available()+1];
首先,您使用的是 available()
方法,绝不是 一个好主意。接下来,即使假设它 是 返回文件的长度,您也要向它加 1 - 为什么?当然,您只需要文件中的字节。
最简单的方法就是使用 Files.readAllBytes
:
byte[] toDecrypt = Files.readAllBytes(Paths.get(path));
// TODO: Change the method name to follow Java conventions
byte[] decrypted = CipherUtils.DecryptByteArray(toDecrypt);
Files.write(Paths.get(path), decrypted);
现在你也不需要担心关闭文件流了...(如果你设法解密,你可能无法写入,因为你仍然有文件打开以阅读您当前的代码。)
我还强烈建议重新访问您的异常 "handling":
- 抓住
Exception
几乎总是一个坏主意
- 调用
e.printStackTrace()
然后继续好像什么都没发生几乎总是一个坏主意
设法使用@JonSkeet 的回答解决问题(谢谢!):
File file = new File(path);
fis = new FileInputStream(file);
toDecrypt = new byte[(int)file.length()];
fis.read(toDecrypt);
byte[] decrypted = CipherUtils.DecryptByteArray(toDecrypt);
FileOutputStream decryptedStream = new FileOutputStream(bookPath);
decryptedStream.write (decrypted);
decryptedStream.close();
正如他所指出的,我不应该使用 available() 方法。还有一种比遍历每个字节更好更快的写入文件的方法!根据评论,我还使用随机 IV 将加密更改为 CBC 模式。
我知道 aes 加密需要以 16 为一组,但我的印象是使用 Cipher.getInstance("AES/ECB/PKCS5PADDING");
填充字节数组来实现这一点。我的代码如下:
CipherUtils.java
private static byte[] key = {
0x74, 0x68, 0x69, 0x73, 0x49, 0x73, 0x41, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4b, 0x65, 0x79
};//"thisIsASecretKey";
public static byte[] EncryptByteArray(byte[] array)
{
try
{
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return (cipher.doFinal(array));
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public static byte[] DecryptByteArray(byte[] array)
{
try
{
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
return cipher.doFinal(array);
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
主程序
fis = new FileInputStream(path);
toDecrypt = new byte[fis.available()+1];
int content;
int i = 0;
while ((content = fis.read()) != -1) {
// convert to byte and display it
toDecrypt[i] = (byte)content;
i += 1;
}
byte[] decryptedStr = CipherUtils.DecryptByteArray(toDecrypt);
FileOutputStream decryptedStream = new FileOutputStream(path);
decryptedStream.write (decryptedStr);
decryptedStream.close();
path
处的文件使用 cipherutils.java 中的函数加密,并使用 FileOutputStream.write
更新 - 我正在使用 Gradle 为 Android 构建。
这是问题所在:
toDecrypt = new byte[fis.available()+1];
首先,您使用的是 available()
方法,绝不是 一个好主意。接下来,即使假设它 是 返回文件的长度,您也要向它加 1 - 为什么?当然,您只需要文件中的字节。
最简单的方法就是使用 Files.readAllBytes
:
byte[] toDecrypt = Files.readAllBytes(Paths.get(path));
// TODO: Change the method name to follow Java conventions
byte[] decrypted = CipherUtils.DecryptByteArray(toDecrypt);
Files.write(Paths.get(path), decrypted);
现在你也不需要担心关闭文件流了...(如果你设法解密,你可能无法写入,因为你仍然有文件打开以阅读您当前的代码。)
我还强烈建议重新访问您的异常 "handling":
- 抓住
Exception
几乎总是一个坏主意 - 调用
e.printStackTrace()
然后继续好像什么都没发生几乎总是一个坏主意
设法使用@JonSkeet 的回答解决问题(谢谢!):
File file = new File(path);
fis = new FileInputStream(file);
toDecrypt = new byte[(int)file.length()];
fis.read(toDecrypt);
byte[] decrypted = CipherUtils.DecryptByteArray(toDecrypt);
FileOutputStream decryptedStream = new FileOutputStream(bookPath);
decryptedStream.write (decrypted);
decryptedStream.close();
正如他所指出的,我不应该使用 available() 方法。还有一种比遍历每个字节更好更快的写入文件的方法!根据评论,我还使用随机 IV 将加密更改为 CBC 模式。