我正在考虑为Android开发一个鸟类目录。它将包含许多图片和音频文件。所有这些文件都来自拥有版权的第三方公司。
我的应用程序应尽可能确保不会访问,复制或操纵这些媒体文件。
我可以遵循哪些策略?在文件系统中加密文件并在显示或播放之前在内存中解密?将它们作为CLOB保存到SQL Lite中?这个SQL Lite是否可以从其他应用程序访问,还是隐藏在其他应用程序中?还有其他想法吗?我没有在网上找到关于这个“问题”的太多信息。
提前致谢,
CHEMI。
答案 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。
其余的很容易。