版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
Android 数据库加密 SQLCipher使用方法
最近在做数据库加密,遇到了些问题,特此记录
greendao 支持数据库加密
网址http://greenrobot.org/greendao/documentation/database-encryption/SQLCipher 网址:https://www.zetetic.net/sqlcipher/
SQLCipher 如何依赖在Android
网址:https://www.zetetic.net/sqlcipher/sqlcipher-for-android/AS依赖 compile ‘net.zetetic:android-database-sqlcipher:3.5.9@aar’
每次在操作数据库前,初始化SQLCipher 所以我放在了Application下
SQLiteDatabase.loadLibs(APPApplication.this);
- 在操作数据库时与SQLiteDatabase 基本一样,唯一的区别就是打开数据库,需要密码
- 首先打开一个加密的数据库
sqlcipher 打开加密数据库
net.sqlcipher.database.SQLiteDatabase sqLiteDatabase = net.sqlcipher.database.SQLiteDatabase.openDatabase(file.getAbsolutePath(), password, null,
SQLiteDatabase.OPEN_READWRITE
| SQLiteDatabase.CREATE_IF_NECESSARY
| SQLiteDatabase.NO_LOCALIZED_COLLATORS, new SQLiteDatabaseHook() {
@Override
public void preKey(net.sqlcipher.database.SQLiteDatabase sqLiteDatabase) {
}
@Override
public void postKey(net.sqlcipher.database.SQLiteDatabase sqLiteDatabase) {
//操作数据与 Android SQLiteDatabase 用法一致
}
});
//greendao 操作数据库时 用这个方法 打开加密的库
openHelper.getEncryptedWritableDb(Contents.DB_KEY);
openHelper.getEncryptedReadableDb(Contents.DB_KEY);
greendao 中结合 sqlcipher 用法:
/**
* 获取可读数据库
*/
private Database getReadableDatabase() {
if (Contents.DB_RELEASE) {
DBencrypt.getInstences().encrypt(UIUtil.getContext(), Contents.DB_KEY);
return openHelper.getEncryptedReadableDb(Contents.DB_KEY);
} else {
return openHelper.getReadableDb();
}
}
/**
* 获取可写数据库
*/
private Database getWritableDatabase() {
if (Contents.DB_RELEASE) {
DBencrypt.getInstences().encrypt(UIUtil.getContext(), Contents.DB_KEY);
return openHelper.getEncryptedWritableDb(Contents.DB_KEY);
} else {
return openHelper.getReadableDb();
}
}
做完后遇到一个尴尬的问题,第一次进去时确实能显示,没毛病,当把进程杀死后在进去,都报错。。。
net.sqlcipher.database.SQLiteException: file is not a database: , while compiling: select count(*) from sqlite_master;
查询多次后发现 是加密 解密时出问题,当数据库原来未加密时用此方法打开,会报错。所以在查询数据之前,先把未加密的数据库加密,再去查询
代码附上:
/**
* 加密数据库
* Created by Han on 2018/4/10
* Email:[email protected]
* CSDN:http://blog.csdn.net/yin13753884368/article
* Github:https://github.com/yin13753884368
*/
public class DBencrypt {
public static DBencrypt dBencrypt;
private Boolean isOpen = true;
public static DBencrypt getInstences() {
if (dBencrypt == null) {
synchronized (DBencrypt.class) {
if (dBencrypt == null) {
dBencrypt = new DBencrypt();
}
}
}
return dBencrypt;
}
/**
* 如果有旧表 先加密数据库
*
* @param context
* @param passphrase
*/
public void encrypt(Context context, String passphrase) {
File file = new File("/data/data/" + context.getPackageName() + "/databases/db_name");
if (file.exists()) {
if (isOpen) {
try {
File newFile = File.createTempFile("sqlcipherutils", "tmp", context.getCacheDir());
net.sqlcipher.database.SQLiteDatabase db = net.sqlcipher.database.SQLiteDatabase.openDatabase(
file.getAbsolutePath(), "", null, SQLiteDatabase.OPEN_READWRITE);
db.rawExecSQL(String.format("ATTACH DATABASE '%s' AS encrypted KEY '%s';",
newFile.getAbsolutePath(), passphrase));
db.rawExecSQL("SELECT sqlcipher_export('encrypted')");
db.rawExecSQL("DETACH DATABASE encrypted;");
int version = db.getVersion();
db.close();
db = net.sqlcipher.database.SQLiteDatabase.openDatabase(newFile.getAbsolutePath(),
passphrase, null,
SQLiteDatabase.OPEN_READWRITE);
db.setVersion(version);
db.close();
file.delete();
newFile.renameTo(file);
isOpen = false;
} catch (Exception e) {
isOpen = false;
}
}
}
}
}
官网文档地址:https://www.zetetic.net/sqlcipher/sqlcipher-api/#attach