从现有 Room 数据库迁移到 Sqlcipher

Muh*_*eem 5 android sqlcipher-android android-room

我的应用程序目前正在使用房间数据库。我想迁移到使用 Sqlcipher 数据库。我已经fallbackToDestructiveMigration()启用但仍然抛出以下错误

java.lang.RuntimeException: Exception while computing database live data.
    at androidx.room.RoomTrackingLiveData$1.run(RoomTrackingLiveData.java:92)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
    at java.lang.Thread.run(Thread.java:764)
 Caused by: net.sqlcipher.database.SQLiteException: file 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:91)
    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:2016)
    at net.sqlcipher.database.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1902)
    at net.sqlcipher.database.SQLiteDatabase.keyDatabase(SQLiteDatabase.java:2673)
    at net.sqlcipher.database.SQLiteDatabase.openDatabaseInternal(SQLiteDatabase.java:2603)
    at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:1247)
    at net.sqlcipher.database.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:1322)
    at net.sqlcipher.database.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:166)
    at net.sqlcipher.database.SupportHelper.getWritableDatabase(SupportHelper.java:83)
    at androidx.room.RoomDatabase.inTransaction(RoomDatabase.java:476)
    at androidx.room.RoomDatabase.assertNotSuspendingTransaction(RoomDatabase.java:281)
    at androidx.room.RoomDatabase.query(RoomDatabase.java:324)
    at androidx.room.util.DBUtil.query(DBUtil.java:83)
    at com.screenlocker.secure.room.MyDao_Impl$29.call(MyDao_Impl.java:1249)
    at com.screenlocker.secure.room.MyDao_Impl$29.call(MyDao_Impl.java:1246)
    at androidx.room.RoomTrackingLiveData$1.run(RoomTrackingLiveData.java:90)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) 
    at java.lang.Thread.run(Thread.java:764) 
Run Code Online (Sandbox Code Playgroud)

有没有办法销毁我所有的数据库并转移到 Sqlcipher?我也尝试过database.delete("table_name",null,null)手动删除表和迁移的命令,但它仍然无法正常工作。我的数据库创建代码如下。

DatabaseSecretProvider provider = new DatabaseSecretProvider(context);
        byte[] passphrase = provider.getOrCreateDatabaseSecret().asBytes();
        SupportFactory factory = new SupportFactory(passphrase);
        instance = Room.databaseBuilder(context, MyAppDatabase.class, AppConstants.DATABASE_NAME)
                .openHelperFactory(factory)
                .fallbackToDestructiveMigration()
                .build();
Run Code Online (Sandbox Code Playgroud)

我正在使用以下版本的 Sqlcipher

implementation 'net.zetetic:android-database-sqlcipher:4.3.0'
    implementation "androidx.sqlite:sqlite:2.1.0"
Run Code Online (Sandbox Code Playgroud)

小智 6

您可以使用 sqlcipher 的便捷方法加密未加密的数据库sqlcipher_export因此,您不必使用fallbackToDestructiveMigration或花时间编写自定义迁移工具。

\n

来自开发者的网站:

\n
\n

要使用 sqlcipher_export() 加密现有数据库,首先打开标准 SQLite 数据库,但不要\xe2\x80\x99t 提供密钥。接下来,附加一个新的加密数据库,然后在 SELECT 语句中调用 sqlcipher_export() 函数,传入要写入主数据库架构和数据的附加数据库的名称。

\n
\n
$ ./sqlcipher plaintext.db\nsqlite> ATTACH DATABASE \'encrypted.db\' AS encrypted KEY \'newkey\';\nsqlite> SELECT sqlcipher_export(\'encrypted\');\nsqlite> DETACH DATABASE encrypted;\n
Run Code Online (Sandbox Code Playgroud)\n
\n

最后,安全地删除现有的明文数据库,然后像往常一样使用 sqlite3_key 或 PRAGMA 密钥打开新的加密数据库。

\n
\n

资料来源:https ://discuss.zetetic.net/t/how-to-encrypt-a-plaintext-sqlite-database-to-use-sqlcipher-and-avoid-file-is-encrypted-or-is-not- a-数据库错误/868

\n

@commonsguy还有一个如何在 Android 中执行此操作的示例:

\n
$ ./sqlcipher plaintext.db\nsqlite> ATTACH DATABASE \'encrypted.db\' AS encrypted KEY \'newkey\';\nsqlite> SELECT sqlcipher_export(\'encrypted\');\nsqlite> DETACH DATABASE encrypted;\n
Run Code Online (Sandbox Code Playgroud)\n

来源: https: //github.com/commonsguy/cwac-saferoom/blob/v1.2.1/saferoom/src/main/java/com/commonsware/cwac/saferoom/SQLCipherUtils.java#L175-L224

\n

您可以context.getDatabasePath(DATABASE_NAME)作为originalFile参数传递。

\n

另外,请参阅commonsguy 的评论,它解释了如何将其与getDatabaseState函数结合使用,将数据从现有的纯文本数据库迁移到 sqlcipher 加密数据库。

\n


Hai*_*lik 0

这对我有用,但我觉得这不是最好的答案:

    val factory: SupportFactory = SupportFactory(masterKeyAlias.toByteArray())

    private fun buildDatabase(context: Context) =
        Room.databaseBuilder(
            context.applicationContext,
            AppDatabase::class.java,
            "MyDatabaseNew.db"  // <<--- change the name of this database file
        ).openHelperFactory(factory)
            .build()
Run Code Online (Sandbox Code Playgroud)

这是一个全新的数据库,数据需要全新填充。也许有一种方法可以在迁移中迁移它。