使用facebook隐藏解密文件时出现OutOfMemoryException

OutOfMemoryException while decrypting file using facebook conceal

我正在开发 android 应用程序,我需要将视频保存在 SD 卡中,它不能转移,这就是为什么我在需要时使用 Facebook Conceal 进行加密和解密的原因如果视频尺寸更小就完美了。

每当我尝试对 GenyMotion running 2.3.7 中不超过 10MB 的大型视频文件进行加密和解密时,它会崩溃并显示 OutOfMemoryException,这意味着我 运行 出局了分配给我的应用程序的堆内存无法处理但必须阻止。

尝试过:

Facebook Conceal : 解密时说

 You must read the entire stream to completion.
 The verification is done at the end of the stream.
 Thus not reading till the end of the stream will cause
 a security bug. For safety, you should not
 use any of the data until it's been fully read or throw
 away the data if an exception occurs.

我用Facebook Conceal调用加密解密的代码:

加密 :

public void startEncryption() {
    // Creates a new Crypto object with default implementations of
    // a key chain as well as native library.
    // Check for whether the crypto functionality is available
    // This might fail if android does not load libaries correctly.
    if (!crypto.isAvailable()) {
        return;
    }
    OutputStream fileStream;
    try {
        File mEncryptedFile = new File(mPlainFile.getPath().substring(0,
                mPlainFile.getPath().length() - 4)
                + "_encrypted"
                + mPlainFile.getPath().substring(
                        mPlainFile.getPath().length() - 4,
                        mPlainFile.getPath().length()));

        fileStream = new BufferedOutputStream(new FileOutputStream(
                mEncryptedFile));

        // Creates an output stream which encrypts the data as
        // it is written to it and writes it out to the file.
        OutputStream outputStream;
        outputStream = crypto.getCipherOutputStream(fileStream, entity);
        outputStream.write(FileUtils.readFileToByteArray(mPlainFile));
        // fileStream.flush();
        // fileStream.close();
        // outputStream.flush();
        // outputStream.close();
        // outputStream.flush();
        File mRenameTo = new File(mPlainFile.getPath());
        mPlainFile.delete();
        mEncryptedFile.renameTo(mRenameTo);
    } catch (FileNotFoundException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (CryptoInitializationException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (KeyChainException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

解密:

public String startDecryption() {
    // Get the file to which ciphertext has been written.
    try {
        FileInputStream fileStream = new FileInputStream(mPlainFile);

        // Creates an input stream which decrypts the data as
        // it is read from it.
        InputStream inputStream;
        inputStream = crypto.getCipherInputStream(fileStream, entity);

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        // org.apache.commons.io.output.ByteArrayOutputStream out = new
        // org.apache.commons.io.output.ByteArrayOutputStream(1024);
        // Read into a byte array.
        // int read;
        // byte[] buffer = new byte[1024];
        // // You must read the entire stream to completion.
        // // The verification is done at the end of the stream.
        // // Thus not reading till the end of the stream will cause
        // // a security bug.
        // int i = 0;
        // while ((read = inputStream.read(buffer)) != -1) {
        // out.write(buffer, 0, read);
        // Log.i(TAG, "bytearrayoutputstream "+i++ + " "+read + " " +
        // buffer.length + " "+out.size());
        // }

        mDecryptedFile = new File(mPlainFile.getPath().substring(0,
                mPlainFile.getPath().length() - 4)
                + "_decrypted"
                + (mPlainFile.getPath().substring(mPlainFile.getPath()
                        .length() - 4, mPlainFile.getPath().length())));

        OutputStream outputStream = new FileOutputStream(mDecryptedFile);
        // IOUtils.copy(inputStream, outputStream);

        try {
            final byte[] buffer = new byte[1024];
            int read;

            while ((read = inputStream.read(buffer)) != -1)
                outputStream.write(buffer, 0, read);

            outputStream.flush();
        } catch (Exception e) {

        } finally {
            outputStream.close();
        }

        // out.writeTo(outputStream);
        // out.flush();
        // out.close();

        // fileStream.close();
        inputStream.close();
        // outputStream.flush();
        outputStream.close();
        return mDecryptedFile.getPath();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (CryptoInitializationException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (KeyChainException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return null;
}

是否有任何解决方案可以变通并加密和解密大型视频文件?

您似乎正在将整个文件读入一个字节数组。您应该做的是创建一个输入流并将其提供给加密引擎。

所以这个:

 outputStream.write(FileUtils.readFileToByteArray(mPlainFile));

应该看起来像你的解密循环。

BufferedInputStream  bis = new BufferedInputStream(mPlainFile);
InputStream inputStream = crypto.getCipherInputStream(
                             bis,
                             entity);
while ((read = inputStream.read(buffer)) != -1) {
   outputStream.write(buffer, 0, read);
}

不确定这是否是您最终得到的结果。我从文档中提取了加密解码。我认为这证实了他们的意图是说必须读取流直到结束。

正如 Bruce 在 Encryption 上强调的瓶颈导致 OutOfMemoryExceptionDecryption 时。所以这是我在加密和解密时正在执行的代码,不再导致 OutOfMemoryException.

加密:

fileStream = new BufferedOutputStream(new FileOutputStream(mEncryptedFile));
OutputStream outputStream;
outputStream = crypto.getCipherOutputStream(fileStream, entity);
int read;
byte[] buffer = new byte[1024];
BufferedInputStream  bis = new BufferedInputStream(newFileInputStream(mPlainFile));
while ((read = bis.read(buffer)) != -1) {
       outputStream.write(buffer, 0, read);
    }
outputStream.close();
bis.close();

解密:

InputStream inputStream;
inputStream = crypto.getCipherInputStream(fileStream, entity);
ByteArrayOutputStream out = new ByteArrayOutputStream();
OutputStream outputStream = new FileOutputStream(mDecryptedFile);
BufferedInputStream bis = new BufferedInputStream(inputStream);
int mRead;
byte[] mBuffer = new byte[1024];
while ((mRead = bis.read(mBuffer)) != -1) {
   outputStream.write(mBuffer, 0, mRead);
    }
bis.close();
out.writeTo(outputStream);
inputStream.close();
outputStream.close();
out.close();