android sqlcipher使用方法
最近在做数据库加密,遇到了些问题,特此记录
greendao 支持数据库加密
网址https://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:yin13753884368@163.com
* csdn:https://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;
}
}
}
}
}