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

Jos*_*dax 5 android

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

我的应用程序应该(尽可能地)确保不能访问,复制或操纵这些媒体文件.

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

提前致谢,

CHEMI.

Shl*_*blu 7

我建议将这些文件保存到SD卡,而不是活动的私人文件,因为图像/音频文件通常很大(我在本次讨论中看到你计划处理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);
    }
}
Run Code Online (Sandbox Code Playgroud)

}

您还需要此Exception类:

public class EncrypterException extends Exception {
    public EncrypterException (           ) { super(   ); }
    public EncrypterException (String str ) { super(str); }
    public EncrypterException (Throwable e) { super(e);   }
}
Run Code Online (Sandbox Code Playgroud)

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

encryptToBinaryFile("password", bytesToSaveEncrypted, encryptedFileToSaveTo);
Run Code Online (Sandbox Code Playgroud)

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

byte [] clearData = decryptFromBinaryFiles("password", encryptedFileToReadFrom);
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

有一种简单的方法来规避这个问题.它详细说明这里在Android开发者博客.对于那个很抱歉.