Hi. I’m having issues applying SQLCipher to a previously existing Room database.
SQLCipher works fine to new users who builds the database for the first time,
but for previous users whom already have a built a database, I’m getting the following runtime error.
Android Runtime: FATAL EXCEPTION: arch_disk_io_1
...
Caused by: net.sqlcipher.database.SQLiteException: file is not a database: , while compiling: select count(*) from sqlite_master
Before applying SQLCipher, room database is created by using the following code:
SQLCipher does not distinguish between “unencrypted database” and “encrypted database with the wrong passphrase”. Ideally, you would track whether or not the database is encrypted. And, at the time you decide that you want to encrypt an unencrypted database, you will need code to encrypt it. This Java method will encrypt an existing unencrypted database.
The getDatabaseState() method on that utility class will attempt to determine if a database is encrypted or not, by trying to open the database with an empty passphrase.
Are you looking to encrypt an existing plaintext SQLite database, or are you creating a new SQLCipher database from scratch? If the former, please take a look at the sqlcipher_export convenience function; for the latter we have documentation for using SQLCipher for Android here.
If your goal is to encrypt a plaintext SQLite database, then yes you will need to use sqlcipher_export(...) to encrypt the database using SQLCipher.
From our Room integration steps in the README, you will use the existing Room.databaseBuilder, but provide the openHelperFactory(...) with a SupportFactory instance which allows for setting the passphrase.
final byte[] passphrase = SQLiteDatabase.getBytes(userEnteredPassphrase);
final SupportFactory factory = new SupportFactory(passphrase);
final SomeDatabase room = Room.databaseBuilder(activity, SomeDatabase.class, DB_NAME)
.openHelperFactory(factory)
.build();
Can you try pulling the database off the device after the cipher_migrate command is executed to further inspect it? You can use the nightly version of DB Browser for SQLite here to see if you are able to access it with either SQLCipher 3 or SQLCipher 4 settings in place.
Hi ,
i am also facing migration issue for existing room database. i have use SQLCipherUtils.encrypt for encrypting existing room database as mention in discussion. So expected behaviour should be database is encrypted and on query it should return old data. but look like database is getting encrypted but old is lost. on query i am not able fetch any data.
Adding code for reference
private fun create(context: Context, password: CharArray): MediDataBase {
val state = SQLCipherUtils.getDatabaseState(context, DB_NAME)
if (state == SQLCipherUtils.State.UNENCRYPTED){
SQLCipherUtils.encrypt(
context,
DB_NAME,
password
)
}
val supportFactory = SupportFactory(SQLiteDatabase.getBytes(password))
return Room.databaseBuilder(context, MediDataBase::class.java, DB_NAME)
.openHelperFactory(supportFactory)
.addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5, MIGRATION_5_6)
.fallbackToDestructiveMigration()
.build()
}