Sqlcipher加密框架版本升级3.x to 4.x

Sqlcipher数据库加密框架是一个比较流行的Sqlite数据库加密框架,微信的WCDB数据库也是使用的此框架。由于历史原因,项目使用的Sqlcipher框架是3.0.x的版本,具体哪个版本都无从查找,因为是使用的源码。最近由于业务需要,项目要加入androidx的支持,发现Sqlcipher的3.0版本只能支持23以下目标版本的编译支持,于是升级Sqlcipher版本至4.0以上。于是……问题来了,升级后发现原有的数据库无法打开,无法打开。于是开始重新梳理Sqlcipher数据库框架。

一、查看Sqlcipher的GitHub上关于版本兼容性的说  https://github.com/sqlcipher/sqlcipher

Compatibility

SQLCipher maintains database format compatibility within the same major version number so an application on any platform can open databases created by any other application provided the major version of SQLCipher is the same between them. However, major version updates (e.g. from 3.x to 4.x) often include changes to default settings. This means that newer major versions of SQLCipher will not open databases created by older versions without using special settings. For example, SQLCipher 4 introduces many new performance and security enhancements. The new default algorithms, increased KDF iterations, and larger page size mean that SQLCipher 4 will not open databases created by SQLCipher 1.x, 2.x, or 3.x by default. Instead, an application would either need to migrate the older databases to use the new format or enable a special backwards-compatibility mode. The available options are described in SQLCipher's upgrade documentation.

SQLCipher is also compatible with standard SQLite databases. When a key is not provided, SQLCipher will behave just like the standard SQLite library. It is also possible to convert from a plaintext database (standard SQLite) to an encrypted SQLCipher database using ATTACH and the sqlcipher_export() convenience function.

原文如上,大致意思是SQLCipher 的版本升级,主要是大版本升级,1到2,2到3,3到4,都是伴随着安全技术、核心技术的升级,无法实现直接无缝的兼容。

However, major version updates (e.g. from 3.x to 4.x) often include changes to default settings. This means that newer major versions of SQLCipher will not open databases created by older versions without using special settings.

翻译一下:

但是,主要版本更新(例如从3.x到4.x)通常包括对默认设置的更改。这意味着,如果不使用特殊设置,较新的SQLCipher主版本将不会打开由较旧版本创建的数据库。

好了,原因找到了,版本不兼容,作者也给出了解决的方案,来吧,试试看。

二、解决方案的选择

Sqlcipher仓库的地址:https://mvnrepository.com/artifact/net.zetetic/android-database-sqlcipher

Sqlcipher的升级4文档地址:https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283

Option 1: Database File Migration

SQLCipher provides a very convenient way to perform an “in place” migration of a SQLCipher database using PRAGMA cipher_migrate. This does all the work of updating the database file format with a single SQL statement. After migration the database will use all of the latest default settings so an application can immediately benefit from improved performance and security.

PRAGMA cipher_migrate be run a single time immediately after the key is provided (i.e. via sqlite3_key() or PRAGMA key in order to upgrade the database. This would normally occur on the first run after the application is upgraded to perform a one-time conversation.

After the migration is complete the application will no longer need to call the command again on subsequent opens.

PRAGMA key = '';
PRAGMA cipher_migrate;
我选择了第一个方案,其他方案可以去上面的网址找。选择的原因很简单,代码执行简单。就这一个原因就够了,项目时间太紧了,没工夫挨个测试啊。
Sqlcipher的版本使用了4.1.0,不敢追求太新,有需要的可以使用更高的版本,目前最新是4.2.0版本(需要androidx)。


三、代码实现

1、在数据库第一个调用之前,执行这个升级数据库的操作,核心是SqlcipherUpdateHook类
SQLiteDatabase.openOrCreateDatabase(Constants.DB_PATH_EN, Constants.DB_KEY, null, new SqlcipherUpdateHook());
2、最好是在Application 中执行,可以结合APP版本执行这个语句,最好不要多次执行(多次执行虽然没有发现问题,但是也不要多次执行)
3、也可以进行异常捕获,当打开数据库失败时,升级数据库,但是这个有风险,打不开数据库可能是其他原因,需要小心使用
try {
    DatabaseHelper.getHelper().getWritableDatabase(Constants.DB_KEY);     
  }catch (Exception e){
    SQLiteDatabase.openOrCreateDatabase(Constants.DB_PATH_EN, Constants.DB_KEY, null, new SqlcipherUpdateHook());
  }
4、APP升级加密框架Sqlcipher到4.0后,新安装APP是不需要升级的,只有从旧版本升级才需要升级数据库加密框架版本,这个要处理好  
import android.content.Context;

import net.sqlcipher.database.SQLiteDatabase;
import net.sqlcipher.database.SQLiteDatabaseHook;

 /**
      * 开发者:hongzhen
      * 创建时间: 2019/11/8 11:33
      * 类名:SqlcipherUpdateHook.java
      * 描述:升级Sqlcipher版本,3-4,解决数据库无法打开问题   
      */
public class SqlcipherUpdateHook implements SQLiteDatabaseHook {
    private Context context;
    private String dbname;

    public SqlcipherUpdateHook() {
        this.context = context;
        this.dbname = dbname;
    }

    @Override
    public void preKey(SQLiteDatabase database) {

    }

    @Override
    public void postKey(SQLiteDatabase database) {
        //核心代码,执行升级的语句
        database.rawExecSQL("PRAGMA cipher_migrate;");
    }
}


 

你可能感兴趣的:(Android,Sqlcipher)