2015-06-17 53 views
1

我知道aes加密需要在16个块中,但我的印象是使用Cipher.getInstance("AES/ECB/PKCS5PADDING");填充字节数组来实现这一点。我的代码如下:当使用aes/ecb/pkcs5padding解密字节数组时,IllegalBlockSizeException

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构建。

+1

首先用硬编码输入单元测试你的方法:加密它并解密结果应该导致输出等于输入。完成之后,您会意识到加密和解密工作正常,并且问题出在您编写和读取文件的方式。 available()不会返回文件的长度。即使这样做,你的数组也包含一个额外的字节。所以这没有意义。 –

+2

请不要使用ECB模式。它在语义上不安全。您应该至少使用CBC模式和随机IV。充其量,你应该认证密文。这通常使用GCM等认证模式或通过HMAC运行密文(加密 - 然后MAC)来完成。 –

+0

...或运行* IV *和密文虽然HMAC ... –

回答

0

管理使用@ 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模式。

3

这就是问题所在:

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); 

现在,您不必担心关闭文件流,要么...(如果你已经设法将解密你可能不会能写,因为你仍然有打开的文件在当前的代码读取)

我还强烈建议重新访问您异常“处理”:

  • C atching Exception几乎总是一个坏主意
  • 调用e.printStackTrace(),然后继续若无其事几乎总是一个坏主意
+0

谢谢!我收到“错误:package java.nio.file不存在”,但我使用的是最新版本的Java。我使用的是Gradle 2.4,以及Android Tools插件1.2.0。对不起,我真的很陌生,大部分代码都不是我自己的 - 我的老板希望内部人员能够使用Java! –

+0

@DomHarris:你在使用Android?您从未在问题中提及任何地方 - 这绝对会影响可用的内容... *请*包括发布时的重要信息。 –

相关问题