2015-12-18 34 views
-2

我嘗試加密和解密大型音頻二進制文件。使用CipherInputStream和CipherOutputStream。我知道,關於這樣的主題存在很多問題。但我不明白我的代碼有什麼問題。請明確描述出什麼錯誤。謝謝。Android加密大文件

public void encrypt() { 
    doCrypto(Cipher.ENCRYPT_MODE, KEY); 
} 

public void decrypt() { 
    doCrypto(Cipher.DECRYPT_MODE, KEY); 
} 

private void doCrypto(int cipherMode, String key) { 
    try { 
     Key secretKey = new SecretKeySpec(key.getBytes("UTF-8"), "AES"); 
     Cipher cipher = Cipher.getInstance("AES"); 
     cipher.init(cipherMode, secretKey); 

     FileInputStream inputStream = new FileInputStream(this); 
     FileOutputStream fileOutputStream = new FileOutputStream(this); 

     int read; 

     CipherInputStream cis = new CipherInputStream(inputStream, cipher); 
     CipherOutputStream cos = new CipherOutputStream(fileOutputStream, cipher); 

     while ((read = cis.read()) != -1) { 
      cos.write(read); 
      cos.flush(); 
     } 
     cos.close(); 
     cis.close(); 

     inputStream.close(); 
     fileOutputStream.close(); 

    } catch (NoSuchPaddingException | NoSuchAlgorithmException 
      | InvalidKeyException | IOException ex) { 
     throw new RuntimeException("Error encrypting/decrypting file", ex); 
    } 
} 

例外:

Caused by: java.lang.RuntimeException: Error encrypting/decrypting file at .hortext.HortextFile.doCrypto(HortextFile.java:81) 
    at .tools.hortext.HortextFile.decrypt(HortextFile.java:52) 
    at .tools.hortext.FilesStorage.getStringFromStorage(FilesStorage.java:104) 
    at com.msg.mobilinga.ui.ListenTextActivity.onCreate(ListenTextActivity.java:83) 
    at android.app.Activity.performCreate(Activity.java:5990) 
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106) 
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278) 
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)  
    at android.app.ActivityThread.access$800(ActivityThread.java:151)  
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)  
    at android.os.Handler.dispatchMessage(Handler.java:102)  
    at android.os.Looper.loop(Looper.java:135)  
    at android.app.ActivityThread.main(ActivityThread.java:5254)  
    at java.lang.reflect.Method.invoke(Native Method)  
    at java.lang.reflect.Method.invoke(Method.java:372)  
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)  
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)  
    Caused by: java.io.IOException: Error while finalizing cipher 
    at javax.crypto.CipherInputStream.fillBuffer(CipherInputStream.java:104) 
    at javax.crypto.CipherInputStream.read(CipherInputStream.java:130) 
    at com.msg.mobilinga.tools.hortext.HortextFile.doCrypto(HortextFile.java:69) 
    at com.msg.mobilinga.tools.hortext.HortextFile.decrypt(HortextFile.java:52)  
    at com.msg.mobilinga.tools.hortext.FilesStorage.getStringFromStorage(FilesStorage.java:104)  
    at com.msg.mobilinga.ui.ListenTextActivity.onCreate(ListenTextActivity.java:83)  
    at android.app.Activity.performCreate(Activity.java:5990)  
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)  
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278)  
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)  
    at android.app.ActivityThread.access$800(ActivityThread.java:151)  
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)  
    at android.os.Handler.dispatchMessage(Handler.java:102)  
    at android.os.Looper.loop(Looper.java:135)  
    at android.app.ActivityThread.main(ActivityThread.java:5254)  
    at java.lang.reflect.Method.invoke(Native Method)  
    at java.lang.reflect.Method.invoke(Method.java:372)  
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)  
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)  
    Caused by: javax.crypto.IllegalBlockSizeException: last block incomplete in decryption 
    at com.android.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(BaseBlockCipher.java:894) 
    at javax.crypto.Cipher.doFinal(Cipher.java:1314) 
    at javax.crypto.CipherInputStream.fillBuffer(CipherInputStream.java:102) 
    at javax.crypto.CipherInputStream.read(CipherInputStream.java:130)  
    at com.msg.mobilinga.tools.hortext.HortextFile.doCrypto(HortextFile.java:69)  
    at com.msg.mobilinga.tools.hortext.HortextFile.decrypt(HortextFile.java:52)  
    at com.msg.mobilinga.tools.hortext.FilesStorage.getStringFromStorage(FilesStorage.java:104)  
    at com.msg.mobilinga.ui.ListenTextActivity.onCreate(ListenTextActivity.java:83)  
    at android.app.Activity.performCreate(Activity.java:5990)  
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)  
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278)  
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)  
    at android.app.ActivityThread.access$800(ActivityThread.java:151)  
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)  
    at android.os.Handler.dispatchMessage(Handler.java:102)  
    at android.os.Looper.loop(Looper.java:135)  
    at android.app.ActivityThread.main(ActivityThread.java:5254)  
    at java.lang.reflect.Method.invoke(Native Method)  
    at java.lang.reflect.Method.invoke(Method.java:372)  
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)  
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)  
+0

@ArtjomB。我的例外是編輯器不可見的。我被編輯後。請拿出你的減號。謝謝。 – smail2133

+0

除了逐字節讀寫外,使用ECB模式和使用文本編碼密鑰,您的代碼看起來很好。 Scratch that ...爲什麼你同時使用'CipherInputStream' *和*'CipherOutputStream'? –

+0

@ArtjomB。嗯,你能告訴我我該怎麼做?謝謝。 – smail2133

回答

3

的問題是很可能:

CipherInputStream cis = new CipherInputStream(inputStream, cipher); 
CipherOutputStream cos = new CipherOutputStream(fileOutputStream, cipher); 

您應該只使用其中的一個。 A Cipher包含一些狀態,但由於您將cipher傳遞給兩個流,它們都將使用相同的狀態,並且會發生不可預知的情況(技術術語:))。

FileInputStream inputStream = new FileInputStream(inputFile); 
FileOutputStream fileOutputStream = new FileOutputStream(outputFile); 

int read; 
byte[] buffer = new byte[4096]; 

CipherInputStream cis = new CipherInputStream(inputStream, cipher); 

while ((read = cis.read(buffer)) != -1) { 
    fileOutputStream.write(buffer, 0, read); 
} 
fileOutputStream.close(); 
cis.close(); 

請記住,你不能給你寫信目前正在讀取文件:

FileInputStream inputStream = new FileInputStream(inputFile); 
FileOutputStream fileOutputStream = new FileOutputStream(outputFile); 

int read; 

CipherInputStream cis = new CipherInputStream(inputStream, cipher); 

while ((read = cis.read()) != -1) { 
    fileOutputStream.write(read); 
} 
fileOutputStream.close(); 
cis.close(); 

當然,如果你使用一個緩衝區這將是更高性能的。你必須使用兩個文件。


安全考慮:

  • 始終使用一個完全合格的密碼字符串。 Cipher.getInstance("AES");將根據默認值選擇一些密碼,最可能是Cipher.getInstance("AES/ECB/PKCS5Padding");。默認值可能會改變哪些會破壞你的代碼。
  • 切勿使用ECB模式,因爲它不是semantically secure
  • CBC模式提供語義安全性,但僅限於不可預知的(隨機讀取)IV。 IV不必是保密的,所以你可以將它放在密文上並在解密之前切掉。
  • 驗證您的密文可防止許多攻擊。您可以使用GCM或EAX等認證模式,也可以使用強大的MAC功能(如HMAC-SHA256)應用encrypt-then-MAC方案。
+0

你回答真的很美。這個星球必須有更多像你這樣的人。但是我有不同的問題,結果文件是空的。 – smail2133

+0

我不知道你的代碼中有什麼'this',但我懷疑你爲'File'創建了一個子類。在這種情況下,您無法寫入您正在閱讀的文件。 –

+0

是的,你正確的文件的子類。你的意思是我的代碼只能讀取,而不是寫入文件? – smail2133

0

Here是爲什麼你不應該使用ECB模式。

(用於圖像的回答)

enter image description here

(圖像linked from Wikipedia,見abovr URL)

+0

什麼需要用來做安全的二進制文件? – smail2133

+0

您需要使用CBC模式。 – zaph