2017-01-19 68 views
0

我最近在做文件加密/解密。android AES解密文件:BadPaddingException:EVP_CipherFinal_ex

BadPaddingException:EVP_CipherFinal_ex:當我嘗試使用相同的密鑰解密文件時,總是發生。

代碼片段將在下面發佈。

我做錯了什麼?

謝謝你的幫助。

加密

public static void encryptFile() { 
    File file = new File(Environment.getExternalStorageDirectory().getPath() + "/" + TARGET_FILE); 

    FileInputStream fileInputStream; 
    FileOutputStream fileOutputStream; 

    byte[] buffer = new byte[1024 * 8]; 

    IvParameterSpec ivParameterSpec = new IvParameterSpec("123456789".getBytes()); 

    byte[] key = "only for testing".getBytes(); 
    MessageDigest sha; 
    try { 
     sha = MessageDigest.getInstance("SHA-1"); 
     key = sha.digest(key); 
    } catch (NoSuchAlgorithmException e) { 
     e.printStackTrace(); 
    } 
    key = Arrays.copyOf(key, 16); // use only first 128 bit 

    SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES"); 

    try { 
     fileInputStream = new FileInputStream(file); 
     fileOutputStream = new FileOutputStream(Environment.getExternalStorageDirectory().getPath() + "/" + ENCRYPT_FILE); 

     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec); 

     //CipherOutputStream cipherOutputStream = new CipherOutputStream(fileOutputStream, cipher); 

     int read; 

     while ((read = fileInputStream.read(buffer)) > 0) { 
      Log.i(TAG, "encrypt read= " + read); 

      byte[] encryptedData = cipher.doFinal(buffer); 
      if (encryptedData != null) { 
       Log.i(TAG, "encrypted size= " + encryptedData.length); 
       fileOutputStream.write(encryptedData, 0, read); 
      } 

      //cipherOutputStream.write(buffer, 0, buffer.length); 
     } 
     //cipherOutputStream.flush(); 
     //cipherOutputStream.close(); 
     fileInputStream.close(); 
     fileOutputStream.close(); 

    } catch (IOException | NoSuchAlgorithmException | NoSuchPaddingException 
      | IllegalBlockSizeException | BadPaddingException 
      | InvalidAlgorithmParameterException | InvalidKeyException e) { 
     e.printStackTrace(); 
    } 
} 

解密

public static void decryptFile() { 
    File file = new File(Environment.getExternalStorageDirectory().getPath() + "/" + ENCRYPT_FILE); 

    FileInputStream fileInputStream; 
    FileOutputStream fileOutputStream; 

    byte[] buffer = new byte[1024 * 8]; 

    IvParameterSpec ivParameterSpec = new IvParameterSpec("123456789".getBytes()); 

    byte[] key = "only for testing".getBytes(); 
    MessageDigest sha; 
    try { 
     sha = MessageDigest.getInstance("SHA-1"); 
     key = sha.digest(key); 
    } catch (NoSuchAlgorithmException e) { 
     e.printStackTrace(); 
    } 
    key = Arrays.copyOf(key, 16); // use only first 128 bit 

    SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES"); 

    try { 
     fileInputStream = new FileInputStream(file); 
     fileOutputStream = new FileOutputStream(Environment.getExternalStorageDirectory().getPath() + "/" + DECRYPT_FILE); 

     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec); 

     //CipherInputStream cipherInputStream = new CipherInputStream(fileInputStream, cipher); 

     int read; 

     while ((read = fileInputStream.read(buffer)) > 0) { 
      Log.i(TAG, "decrypt read= " + read); 

      byte[] decryptedData = cipher.doFinal(buffer); 
      if (decryptedData != null) { 
       Log.i(TAG, "decrypted size= " + decryptedData.length); 
       fileOutputStream.write(decryptedData, 0, read); 
      } 

      //fileOutputStream.write(buffer, 0, buffer.length); 
     } 
     fileOutputStream.flush(); 
     fileOutputStream.close(); 
     //cipherInputStream.close(); 
     fileInputStream.close(); 

    } catch (IOException | NoSuchAlgorithmException | NoSuchPaddingException 
      | IllegalBlockSizeException | BadPaddingException 
      | InvalidAlgorithmParameterException | InvalidKeyException e) { 
     e.printStackTrace(); 
    } 
} 

BTW:這將正常工作,當我使用CipherInputStream/CipherOutStream。我想知道是否可以只使用FileInputStream/FileOutputStream?謝謝。

編輯: 加密函數將放大約16個字節的字節數組,我試圖增加解密的緩衝區大小,仍然無法得到它的工作。

byte[] buffer = new byte[1024 * 8 + 16]; 

日誌:

I /#_:解密讀取= 8208

javax.crypto.BadPaddingException:EVP_CipherFinal_ex

在com.android.org.conscrypt.NativeCrypto.EVP_CipherFinal_ex(本地方法)

at com.android.org.conscrypt.OpenSSLCipher.doFinalInternal(OpenSSLCipher.java:430)

在com.android.org.conscrypt.OpenSSLCipher.engineDoFinal(OpenSSLCipher.java:466)

在javax.crypto.Cipher.doFinal(Cipher.java:1340)

在CryptoHelper.decryptFile( CryptoHelper.java:128)

編輯這裏更新代碼基於#羅伯特的答案任何人都遇到了像我一樣的問題。

加密:

int read; 

     while ((read = fileInputStream.read(buffer)) > 0) { 
      Log.i(TAG, "encrypt read= " + read); 
      byte[] encryptedData = cipher.update(buffer, 0, read); 
      //byte[] encryptedData = cipher.doFinal(buffer); 
      if (encryptedData != null) { 
       Log.i(TAG, "encrypted size= " + encryptedData.length); 
       fileOutputStream.write(encryptedData, 0, encryptedData.length); 
      } 

      //cipherOutputStream.write(buffer, 0, buffer.length); 
     } 
     byte[] finals = cipher.doFinal(); 
     Log.i(TAG, "encrypted finals = " + finals.length); 
     fileOutputStream.write(finals, 0, finals.length); 

解密:再次羅伯特的幫助

int read; 

     while ((read = fileInputStream.read(buffer)) > 0) { 
      Log.i(TAG, "decrypt read= " + read); 

      //byte[] decryptedData = cipher.doFinal(buffer); 
      byte[] decryptedData = cipher.update(buffer, 0, read); 
      if (decryptedData != null) { 
       Log.i(TAG, "decrypted size= " + decryptedData.length); 
       fileOutputStream.write(decryptedData, 0, decryptedData.length); 
      } 

      //fileOutputStream.write(buffer, 0, buffer.length); 
     } 
     byte[] finals = cipher.doFinal(); 
     Log.i(TAG, "decrypted finals = " + finals.length); 
     fileOutputStream.write(finals, 0, finals.length); 

感謝。

回答

3

你的問題是你總是調用cipher.doFinal()爲每個數據塊是錯誤的,因爲每個塊將被填充。

如果您正在使用cipher.update(...)進行數據解密/解密,並且在處理完最後一個塊之後,只調用cipher.doFinal()一次。

更簡單的方法是使用CipherInputStream/CipherOutputStream - 它的確如我所描述的那樣(關閉流時調用doFinal)。

+0

我遵循你的回答並編輯了代碼。它現在有效。非常感謝您的幫助。你拯救了我的一天。 – Youxian