AndroidRoom数据库加密详解


当前第2页 返回上一页

SQLCipher 与Room的结合方式同上面的情形是类似,也是通过代理的方式实现。由于Room需要的类跟SQLCipher 提供的类包名不一致,所以这里需要对SQLCipher 提供的类进行一下代理然后传递给Room架构使用就可以了。

fun init(context: Context) {
? val ?mDataBase1 = Room.databaseBuilder(
? ? ? ? context.applicationContext,
? ? ? ? TestDb::class.java,
? ? ? ? "user_login_info_db"
? ? ).openHelperFactory(SafeHelperFactory("".toByteArray()))
? ? ? .build()
}

这里主要需要自定义一个SupportSQLiteOpenHelper.Factory也就是SafeHelperFactory 这个SafeHelperFactory 完全是仿照Room架构默认的Factory 也就是FrameworkSQLiteOpenHelperFactory 实现。主要是用户创建一个用于打开数据库的SQLiteOpenHelper,主要的区别是自定义的Facttory 需要一个用于加密与解密的密码。
我们首先需要定义一个自己的OpenHelperFactory

public class SafeHelperFactory implements SupportSQLiteOpenHelper.Factory {
? public static final String POST_KEY_SQL_MIGRATE = "PRAGMA cipher_migrate;";
? public static final String POST_KEY_SQL_V3 = "PRAGMA cipher_compatibility = 3;";

? final private byte[] passphrase;
? final private Options options;

?
? public SafeHelperFactory(byte[] passphrase, Options options) {
? ? this.passphrase = passphrase;
? ? this.options = options;
? }

? /**
? ?* {@inheritDoc}
? ?*/
? @Override
? public SupportSQLiteOpenHelper create(
? ? SupportSQLiteOpenHelper.Configuration configuration) {
? ? return(create(configuration.context, configuration.name,
? ? ? configuration.callback));
? }

? public SupportSQLiteOpenHelper create(Context context, String name,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? SupportSQLiteOpenHelper.Callback callback) {
? ? ?//创建一个Helper
? ? return(new Helper(context, name, callback, passphrase, options));
? }

? private void clearPassphrase(char[] passphrase) {
? ? for (int i = 0; i < passphrase.length; i++) {
? ? ? passphrase[i] = (byte) 0;
? ? }
? }

SafeHelperFactory 的create创建了一个Helper,这个Helper实现了Room框架的SupportSQLiteOpenHelper ,实际这个Helper 是个代理类被代理的类为OpenHelper ,OpenHelper 用于操作SQLCipher 提供的数据库类。

class Helper implements SupportSQLiteOpenHelper {
? private final OpenHelper delegate;
? private final byte[] passphrase;
? private final boolean clearPassphrase;

? Helper(Context context, String name, Callback callback, byte[] passphrase,
? ? ? ? ?SafeHelperFactory.Options options) {
? ? SQLiteDatabase.loadLibs(context);
? ? clearPassphrase=options.clearPassphrase;
? ? delegate=createDelegate(context, name, callback, options);
? ? this.passphrase=passphrase;
? }

? private OpenHelper createDelegate(Context context, String name,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? final Callback callback, SafeHelperFactory.Options options) {
? ? final Database[] dbRef = new Database[1];

? ? return(new OpenHelper(context, name, dbRef, callback, options));
? }

? /**
? ?* {@inheritDoc}
? ?*/
? @Override
? synchronized public String getDatabaseName() {
? ? return delegate.getDatabaseName();
? }

? /**
? ?* {@inheritDoc}
? ?*/
? @Override
? @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
? synchronized public void setWriteAheadLoggingEnabled(boolean enabled) {
? ? delegate.setWriteAheadLoggingEnabled(enabled);
? }


? @Override
? synchronized public SupportSQLiteDatabase getWritableDatabase() {
? ? SupportSQLiteDatabase result;

? ? try {
? ? ? result = delegate.getWritableSupportDatabase(passphrase);
? ? }
? ? catch (SQLiteException e) {
? ? ? if (passphrase != null) {
? ? ? ? boolean isCleared = true;

? ? ? ? for (byte b : passphrase) {
? ? ? ? ? isCleared = isCleared && (b == (byte) 0);
? ? ? ? }

? ? ? ? if (isCleared) {
? ? ? ? ? throw new IllegalStateException("The passphrase appears to be cleared. This happens by" +
? ? ? ? ? ? ? "default the first time you use the factory to open a database, so we can remove the" +
? ? ? ? ? ? ? "cleartext passphrase from memory. If you close the database yourself, please use a" +
? ? ? ? ? ? ? "fresh SafeHelperFactory to reopen it. If something else (e.g., Room) closed the" +
? ? ? ? ? ? ? "database, and you cannot control that, use SafeHelperFactory.Options to opt out of" +
? ? ? ? ? ? ? "the automatic password clearing step. See the project README for more information.");
? ? ? ? }
? ? ? }

? ? ? throw e;
? ? }

? ? if (clearPassphrase && passphrase != null) {
? ? ? for (int i = 0; i < passphrase.length; i++) {
? ? ? ? passphrase[i] = (byte) 0;
? ? ? }
? ? }

? ? return(result);
? }

? /**
? ?* {@inheritDoc}
? ?*
? ?* NOTE: this implementation delegates to getWritableDatabase(), to ensure
? ?* that we only need the passphrase once
? ?*/
? @Override
? public SupportSQLiteDatabase getReadableDatabase() {
? ? return(getWritableDatabase());
? }

? /**
? ?* {@inheritDoc}
? ?*/
? @Override
? synchronized public void close() {
? ? delegate.close();
? }

? static class OpenHelper extends SQLiteOpenHelper {
? ? private final Database[] dbRef;
? ? private volatile Callback callback;
? ? private volatile boolean migrated;
}

真正操作数据库的类OpenHelper,OpenHelper 继承的SQLiteOpenHelper 是net.sqlcipher.database 包下的

static class OpenHelper extends SQLiteOpenHelper {
? ? private final Database[] dbRef;
? ? private volatile Callback callback;
? ? private volatile boolean migrated;
?OpenHelper(Context context, String name, final Database[] dbRef, final Callback callback,
? ? ? ? ? ? ? ?final SafeHelperFactory.Options options) {
? ? ? super(context, name, null, callback.version, new SQLiteDatabaseHook() {
? ? ? ? @Override
? ? ? ? public void preKey(SQLiteDatabase database) {
? ? ? ? ? if (options!=null && options.preKeySql!=null) {
? ? ? ? ? ? database.rawExecSQL(options.preKeySql);
? ? ? ? ? }
? ? ? ? }

? ? ? ? @Override
? ? ? ? public void postKey(SQLiteDatabase database) {
? ? ? ? ? if (options!=null && options.postKeySql!=null) {
? ? ? ? ? ? database.rawExecSQL(options.postKeySql);
? ? ? ? ? }
? ? ? ? }
? ? ? }, new DatabaseErrorHandler() {
? ? ? ? @Override
? ? ? ? public void onCorruption(SQLiteDatabase dbObj) {
? ? ? ? ? Database db = dbRef[0];

? ? ? ? ? if (db != null) {
? ? ? ? ? ? callback.onCorruption(db);
? ? ? ? ? }
? ? ? ? }
? ? ? });

? ? ? this.dbRef = dbRef;
? ? ? this.callback=callback;
? ? }

? ? synchronized SupportSQLiteDatabase getWritableSupportDatabase(byte[] passphrase) {
? ? ? migrated = false;

? ? ? SQLiteDatabase db=super.getWritableDatabase(passphrase);

? ? ? if (migrated) {
? ? ? ? close();
? ? ? ? return getWritableSupportDatabase(passphrase);
? ? ? }

? ? ? return getWrappedDb(db);
? ? }

? ? synchronized Database getWrappedDb(SQLiteDatabase db) {
? ? ? Database wrappedDb = dbRef[0];

? ? ? if (wrappedDb == null) {
? ? ? ? wrappedDb = new Database(db);
? ? ? ? dbRef[0] = wrappedDb;
? ? ? }

? ? ? return(dbRef[0]);
? ? }

? ? /**
? ? ?* {@inheritDoc}
? ? ?*/
? ? @Override
? ? public void onCreate(SQLiteDatabase sqLiteDatabase) {
? ? ? callback.onCreate(getWrappedDb(sqLiteDatabase));
? ? }

? ? /**
? ? ?* {@inheritDoc}
? ? ?*/
? ? @Override
? ? public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
? ? ? migrated = true;
? ? ? callback.onUpgrade(getWrappedDb(sqLiteDatabase), oldVersion, newVersion);
? ? }

? ? /**
? ? ?* {@inheritDoc}
? ? ?*/
? ? @Override
? ? public void onConfigure(SQLiteDatabase db) {
? ? ? callback.onConfigure(getWrappedDb(db));
? ? }

? ? /**
? ? ?* {@inheritDoc}
? ? ?*/
? ? @Override
? ? public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
? ? ? migrated = true;
? ? ? callback.onDowngrade(getWrappedDb(db), oldVersion, newVersion);
? ? }

? ? /**
? ? ?* {@inheritDoc}
? ? ?*/
? ? @Override
? ? public void onOpen(SQLiteDatabase db) {
? ? ? if (!migrated) {
? ? ? ? // from Google: "if we've migrated, we'll re-open the db so we ?should not call the callback."
? ? ? ? callback.onOpen(getWrappedDb(db));
? ? ? }
? ? }

? ? /**
? ? ?* {@inheritDoc}
? ? ?*/
? ? @Override
? ? public synchronized void close() {
? ? ? super.close();
? ? ? dbRef[0] = null;
? ? }
? }

这里的OpenHelper 完全是仿照Room 框架下的OpenHelper 实现的。


标签:SQLite

返回前面的内容

相关阅读 >>

django的创建和使用详解(默认数据库Sqlite3)

android中操作Sqlite数据库快速入门教程

android创建数据库(Sqlite)保存图片示例

sql数据库十四种案例介绍

Sqlite 常用函数 推荐

Sqlitestudio优雅调试android手机数据库Sqlite(推荐)

python sqlalchemy库的使用方法

c#操作Sqlite数据库方法小结

python 连接各类主流数据库的实例代码

python人工智能实战之对话机器人的实现

更多相关阅读请进入《Sqlite》频道 >>


数据库系统概念 第6版
书籍

数据库系统概念 第6版

机械工业出版社

本书主要讲述了数据模型、基于对象的数据库和XML、数据存储和查询、事务管理、体系结构等方面的内容。



打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...