2017-06-19 79 views
0

我试图在java中解密一个文件。解密文件的前16个字节是IV(初始化向量)。请帮助解决上述例外情况。javax.crypto.BadPaddingException:给定的最终块在解密时未正确填充

我想在AESFileEncryption()的输出文件中加入IV,然后在解密时读取它。

谢谢。

public class AESFileEncryption { 
public static void encrypt(String path,String pwd) throws Exception { 

    FileOutputStream outFile; 

    try ( 
      FileInputStream inFile = new FileInputStream(path)) { 

     String fileName=path; 

     System.out.println(path); 

     outFile = new FileOutputStream(fileName+".aes"); 
     // password to encrypt the file 
     String password = pwd; 
     byte[] salt = { 
     (byte)0xc7, (byte)0x73, (byte)0x21, (byte)0x8c, 
     (byte)0x7e, (byte)0xc8, (byte)0xee, (byte)0x99 
     }; 

     SecretKeyFactory factory = SecretKeyFactory 
       .getInstance("PBKDF2WithHmacSHA1"); 
     KeySpec keySpec = new PBEKeySpec(password.toCharArray(),salt,65536,128);// user-chosen password that can be used with password-based encryption (PBE). 
     SecretKey secretKey = factory.generateSecret(keySpec); 
     SecretKey secret = new SecretKeySpec(secretKey.getEncoded(), "AES");//Secret KeySpec is a class and implements inteface SecretKey 

     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     SecureRandom random = new SecureRandom(); 
     byte bytes[] = new byte[16]; 
     random.nextBytes(bytes); 
    IvParameterSpec ivspec = new IvParameterSpec(bytes); 
     cipher.init(Cipher.ENCRYPT_MODE, secret,ivspec);//opmode,key 
     outFile.write(bytes); 
     byte[] input = new byte[64]; 
     int bytesRead; 
     while ((bytesRead = inFile.read(input)) != -1) { 
      byte[] output = cipher.update(input, 0, bytesRead); 
      if (output != null) 
       Files.write(Paths.get(fileName+".aes"), output, StandardOpenOption.APPEND); 

     } byte[] output = cipher.doFinal(); 
     if (output != null) 
      Files.write(Paths.get(fileName+".aes"), output, StandardOpenOption.APPEND); 
    } 
    outFile.flush(); 
    outFile.close(); 
    File f=new File(path); 
    boolean x=f.delete(); 
    if(x){ 
     System.out.println("File deleted"); 
    } 
    JOptionPane.showMessageDialog(null,"File Encrypted."); 

} 
} 

解密代码

public class AESFileDecryption { 
public static void decrypt(String path,String pwd) throws Exception { 

    String password = pwd; 
    String fileName=path; 
    File file=new File(path); 
     //System.out.println(inFile.toString()); 
     String fileNameWithOutExt = path.replaceFirst("[.][^.]+$", ""); 
     System.out.println(fileName); 
     System.out.println(fileNameWithOutExt); 
     byte[] salt = { 
     (byte)0xc7, (byte)0x73, (byte)0x21, (byte)0x8c, 
     (byte)0x7e, (byte)0xc8, (byte)0xee, (byte)0x99 
    }; 
    System.out.println("1"); 
    FileInputStream fis = new FileInputStream(path); 
    SecretKeyFactory factory = SecretKeyFactory 
      .getInstance("PBKDF2WithHmacSHA1"); 
    KeySpec keySpec = new PBEKeySpec(password.toCharArray(),salt,65536,128); 
    SecretKey tmp = factory.generateSecret(keySpec); 
    SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES"); 
    System.out.println("2"); 
    // file decryption 
    Cipher cipher=null; 
    byte bytes[]=new byte[16]; 
    fis.read(bytes, 0, 16); 
    IvParameterSpec ivspec = new IvParameterSpec(bytes); 

    cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
    cipher.init(Cipher.DECRYPT_MODE, secret, ivspec); 
    System.out.println("3"); 
    FileOutputStream fos = new FileOutputStream(fileNameWithOutExt); 
    System.out.println("4"); 
    byte[] in = new byte[64]; 
    int read; 
    while ((read = fis.read(in,16,(int)file.length()-16)) != -1) { 
     byte[] output = cipher.update(in, 0, read); 
     if (output != null) 
      fos.write(output); 
    } 
    try{ 
    byte[] output = cipher.doFinal(); 
    if (output != null) 
     fos.write(output); 
    fis.close(); 
    fos.flush(); 
    fos.close(); 
    System.out.println("File Decrypted."); 
} 
catch(IOException | BadPaddingException | IllegalBlockSizeException e) 
{ 
    System.out.println(e+""); 
} 
} 
} 

回答

5

有几个问题与小例子,但一个是最直接的问题是线

while ((read = fis.read(in,16,(int)file.length()-16)) != -1) { 

你似乎混淆关于read()offset参数的含义。它不是文件的偏移量,而是第一个参数中指定的数组的偏移量(in)。

的,我看其他问题的非详尽列表包括:

  • 写入使用两个独立的机制(FileOutputStream.write()Files.write())的文件。当我运行你的程序时,这实际上工作正常,但它似乎是在寻求麻烦。这里没有理由使用Files.write()
  • fis.read(bytes, 0, 16);不检查返回值。

看来你正在努力寻找一些你习惯的IO习语。或者也许只是试验。冒着给你更多选择的风险,你可能会考虑调查谷歌的开源Guava库。许多人发现它正是他们所需要的。

+1

如果我没有记错,文件句柄被锁定到当前线程。所以我并不感到惊讶,它(使用两种不同的方法编写文件)确实有效,但它**仍然在寻求麻烦:) –

+0

我明白了。谢谢。你可以建议我一种方法来读取IV的前16个字节的文件,然后读取其余的字节进行解密? –

相关问题