sqlcipher加密已有数据库及其时机

  最近我们做的移动im打算将数据库加密,我们的数据库是对数据库的简单封装 ,调研了一些开源数据库加密工具,觉得sqlcipher用户会多一点,而且开源。所以打算就用它了

  sqlcipher的使用可以参考下这两篇文章:

  http://www.jianshu.com/p/3baf311f8c8c

  https://www.zetetic.net/sqlcipher/sqlcipher-api/#cipher_default_kdf_iter

 

  因为之前我们发的版本是没有加密的,所以面临的问题是怎么读取之前未加密的数据库或者读取之前怎么加密。

  我们选择了后者,为了将用户数据最大程度的保留(im 一些本地消息的状态)

 加密的方法用的是sqlcipher_export(),具体在android中的用法如下

 

 public static void encrypt(Context context, String dbName,
                               String passphrase) throws IOException {
        File originalFile = context.getDatabasePath(dbName);
        
        if (originalFile.exists()) {

            File newFile =
                    File.createTempFile("sqlcipherutils", "tmp",
                            context.getCacheDir());
            SQLiteDatabase db =
                    SQLiteDatabase.openDatabase(originalFile.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 =
                    SQLiteDatabase.openDatabase(newFile.getAbsolutePath(),
                            passphrase, null,
                            SQLiteDatabase.OPEN_READWRITE);
            db.setVersion(version);
            db.close();

            originalFile.delete();
            newFile.renameTo(originalFile);
        }
    }
     但是加密的时机,并没有太多的资料,本来考虑的是通过数据库onupdate的时候进行加密,但是验证后发现,根本在读取sqlite_master(备注)表的时候就已经报错,说明在检查升级前就已经在读取数据库数据了

      报错如下

      

file is encrypted or is not a database: , while compiling: select count(*) from sqlite_master;
                                                         net.sqlcipher.database.SQLiteException: file is encrypted or is not a database: , while compiling: select count(*) from sqlite_master;
                                                             at net.sqlcipher.database.SQLiteCompiledSql.native_compile(Native Method)
                                                             at net.sqlcipher.database.SQLiteCompiledSql.compile(SQLiteCompiledSql.java:91)
                                                             at net.sqlcipher.database.SQLiteCompiledSql.<init>(SQLiteCompiledSql.java:64)
                                                             at net.sqlcipher.database.SQLiteProgram.<init>(SQLiteProgram.java:89)
                                                             at net.sqlcipher.database.SQLiteQuery.<init>(SQLiteQuery.java:48)
                                                             at net.sqlcipher.database.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:60)
                                                             at net.sqlcipher.database.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1867)
                                                             at net.sqlcipher.database.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1785)
                                                             at net.sqlcipher.database.SQLiteDatabase.keyDatabase(SQLiteDatabase.java:2486)
                                                             at net.sqlcipher.database.SQLiteDatabase.openDatabaseInternal(SQLiteDatabase.java:2415)
                                                             at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:1149)
                                                             at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:1041)
                                                             at net.sqlcipher.database.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:249)
                                                             at net.sqlcipher.database.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:214)
      所以我采用的方案是在getreadabledatabase(“passphase”)||getwriteabledatabase("passphase")的时候进行加密

 try {
            return this.tempDB != null ? this.tempDB : (readable ? this.getReadableDatabase("test12") : this.getWritableDatabase("test12"));
        } catch (SQLiteException e) {
            String message = e.getMessage();
            if (message.contains("encrypt") && message.contains("sqlite_master")) {
                try {
                    encrypt(context , dbName , "test12");
                    return (readable ? this.getReadableDatabase("test12") : this.getWritableDatabase("test12"));
                } catch (IOException e1) {
                    e1.printStackTrace();
                    return  null;
                }
            }
            return null;



      备注:

      关于sqlitemaster:是一张B+树用于查询

   




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值