Android 加密大文件

sma*_*133 -2 encryption android

我尝试加密和解密大型音频二进制文件。使用 CipherInputStream 和 CipherOutputStream。我知道,关于像这样的主题存在许多问题。但我不明白我的代码有什么问题。请描述清楚是什么错误。谢谢。

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

例外:

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) 
Run Code Online (Sandbox Code Playgroud)

Art*_* B. 5

问题很可能是:

CipherInputStream cis = new CipherInputStream(inputStream, cipher);
CipherOutputStream cos = new CipherOutputStream(fileOutputStream, cipher);
Run Code Online (Sandbox Code Playgroud)

您应该只使用其中之一。ACipher持有一些状态,但是由于您将 传递cipher给两个流,因此它们都将使用相同的状态并且会发生不可预测的事情(技术术语:))。

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();
Run Code Online (Sandbox Code Playgroud)

当然,如果使用缓冲区,性能会更高:

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();
Run Code Online (Sandbox Code Playgroud)

请记住,您无法写入当前正在读取的文件。您必须使用两个文件。


安全考虑:

  • 始终使用完全限定的密码字符串。Cipher.getInstance("AES");将根据默认值选择一些密码,这很可能是Cipher.getInstance("AES/ECB/PKCS5Padding");. 默认值可能会更改,这会破坏您的代码。
  • 永远不要使用 ECB 模式,因为它在语义上不安全
  • CBC 模式提供语义安全性,但仅具有不可预测的(随机读取)IV。IV 不必是秘密的,因此您可以将其添加到密文中并在解密之前切掉。
  • 验证您的密文可以防止许多攻击。您可以使用 GCM 或 EAX 等身份验证模式,也可以应用具有强大 MAC 功能的encrypt-then-MAC方案,例如 HMAC-SHA256。