保护移动设备中的媒体文件

时间:2011-07-13 09:05:45

标签: android

我正在考虑为Android开发一个鸟类目录。它将包含许多图片和音频文件。所有这些文件都来自拥有版权的第三方公司。

我的应用程序应尽可能确保不会访问,复制或操纵这些媒体文件。

我可以遵循哪些策略?在文件系统中加密文件并在显示或播放之前在内存中解密?将它们作为CLOB保存到SQL Lite中?这个SQL Lite是否可以从其他应用程序访问,还是隐藏在其他应用程序中?还有其他想法吗?我没有在网上找到关于这个“问题”的太多信息。

提前致谢,

CHEMI。

2 个答案:

答案 0 :(得分:7)

我建议将这些文件保存到SD卡,而不是保存到Activity的私人文件,因为图像/音频文件通常很大(我已经看到in this discussion你计划处理400 MB,是这个相同的应用程序?)。所以加密应该没问题,比SQLite更直接。

下面的类允许将字节加密为二进制文件:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;


public class AESEncrypter {
    public static void encryptToBinaryFile(String password, byte[] bytes, File file) throws EncrypterException {
        try {
            final byte[] rawKey = getRawKey(password.getBytes());
            final FileOutputStream ostream = new FileOutputStream(file, false);

            ostream.write(encrypt(rawKey, bytes));
            ostream.flush();
            ostream.close();

        } catch (IOException e) {
            throw new EncrypterException(e);
        }
    }

public static byte[] decryptFromBinaryFile(String password, File file) throws EncrypterException {
    try {
        final byte[] rawKey = getRawKey(password.getBytes());
        final FileInputStream istream = new FileInputStream(file);
        final byte[] buffer = new byte[(int)file.length()];

        istream.read(buffer);

        return decrypt(rawKey, buffer);

    } catch (IOException e) {
        throw new EncrypterException(e);
    }
}

private static byte[] getRawKey(byte[] seed) throws EncrypterException {
    try {
        final KeyGenerator kgen = KeyGenerator.getInstance("AES");
        final SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");

        sr.setSeed(seed);
        kgen.init(128, sr); // 192 and 256 bits may not be available

        final SecretKey skey = kgen.generateKey();

        return skey.getEncoded();

    } catch (Exception e) {
        throw new EncrypterException(e);
    }
}

private static byte[] encrypt(byte[] raw, byte[] clear) throws EncrypterException {
    try {
        final SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        final Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);

        return cipher.doFinal(clear);

    } catch (Exception e) {
        throw new EncrypterException(e);
    }
}

private static byte[] decrypt(byte[] raw, byte[] encrypted) throws EncrypterException {
    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
    try {
        final Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.DECRYPT_MODE, skeySpec);

        return cipher.doFinal(encrypted);

    } catch (Exception e) {
        throw new EncrypterException(e);
    }
}

}

您还需要此Exception类:

public class EncrypterException extends Exception {
    public EncrypterException (           ) { super(   ); }
    public EncrypterException (String str ) { super(str); }
    public EncrypterException (Throwable e) { super(e);   }
}

然后,您只需使用以下内容生成加密文件:

encryptToBinaryFile("password", bytesToSaveEncrypted, encryptedFileToSaveTo);

在您的应用中,您可以通过以下方式阅读:

byte [] clearData = decryptFromBinaryFiles("password", encryptedFileToReadFrom);

使用硬编码密码可以通过挖掘混淆代码并查找字符串来进行攻击。我不知道你的情况下这是否足够安全?

如果没有,您可以将密码存储在Activity的私人首选项中,或者使用诸如this.class.getDeclaredMethods()[n] .getName()之类的技巧作为密码。这很难找到。

关于表演,你必须知道加密/解密可能需要很长时间。这需要一些测试。

[编辑:04-25-2014] 我的回答有一个很大的错误。这个实现是种子SecureRandom,这是坏的(有些人会说'邪恶')。

有一种简单的方法来规避这个问题。 Android开发人员博客中详细解释了here。对不起。

答案 1 :(得分:1)

类似的问题我已经使用SQLite BLOB解决了。您可以尝试application in AndroidMarket

实际上我正在将媒体文件保存到一系列BLOB中。 SQLite支持BLOB大小up to 2 gigs,但由于Android限制,我被迫将文件块化为4兆位BLOB。

其余的很容易。