Is " Option 2: Backwards Compatibility" would work nowadays for migrating from net.zetetic:android-database-sqlcipher:3.5.7 to net.zetetic:android-database-sqlcipher:4.5.4?
Hi @FrozenPyrozen,
Yes, you could use the compatibility PRAGMA to upgrade your library to 4.5.4 and access a SQLCipher 3.x database.
Iām not a native android dev so I wanted to check should I use it like this?
// DatabaseHelper.java
@Override
public void onOpen(SQLiteDatabase db) {
super.onOpen(db);
// Apply PRAGMAs to maintain SQLCipher 3 compatibility
db.execSQL("PRAGMA cipher_compatibility = 3;");
db.execSQL("PRAGMA cipher_page_size = 1024;");
db.execSQL("PRAGMA kdf_iter = 64000;");
db.execSQL("PRAGMA cipher_hmac_algorithm = HMAC_SHA1;");
db.execSQL("PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1;");
}
Hi @FrozenPyrozen,
No, if you are using the android-database-sqlcipher
library, you will want to use the SQLiteDatabaseHook
and set your compatibility via the postKey
event:
SQLiteDatabase hook = new SQLiteDatabaseHook() {
@Override
public void preKey(SQLiteDatabase database) {}
@Override
public void postKey(SQLiteDatabase database) {
database.execSQL("PRAGMA cipher_compatibility = 3;");
}
};
You can then provide the hook
parameter as an argument when opening the database connection. This will guarantee that the compatibility setting is in place before key derivation or any other SQL operation occurs.
Thanks, how to understand where to place a hook?
Hi @FrozenPyrozen,
The hook can be provided to the static openDatabase
/openOrCreateDatabase
methods found on the SQLiteDatabase
class, or if youāre using a subclass to the SQLiteOpenHelper
.
I was looking into MigrateDatabaseFrom3xFormatToCurrentFormatTest as an example, and Iāve seen some issues with SQLiteConnection
on my Android studio so Iāve created a helper method
public static SQLiteDatabaseHook migrateDbFromSupportHook() {
return new SQLiteDatabaseHook() {
@Override
public void preKey(SQLiteDatabase database) {}
@Override
public void postKey(SQLiteDatabase database) {
// Apply PRAGMAs to maintain SQLCipher 3 compatibility for net.zetetic:android-database-sqlcipher after 4x version
database.execSQL("PRAGMA cipher_compatibility = 3;");
database.execSQL("PRAGMA cipher_page_size = 1024;");
database.execSQL("PRAGMA kdf_iter = 64000;");
database.execSQL("PRAGMA cipher_hmac_algorithm = HMAC_SHA1;");
database.execSQL("PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1;");
}
};
}
and passing this hook into every openDatabase
method calling in project. Is this okay?
Hi @FrozenPyrozen,
Once you set the compatibility version you donāt need to set the other pragma items as they are set on your behalf. See the implementation for reference.
Iāve got dew questions:
- Everything above, but only with
database.execSQL("PRAGMA cipher_compatibility = 3;");
would be enough? - Iāve got
import net.sqlcipher.database.SQLiteException;
and error āCannot resolve symbol āSQLiteExceptionāā. DoesSQLiteException
moved somewhere in newer versions?
Correct.
In the SQLCipher for Android 4.5.4 release [1], Android Database SQLite Exception classes are now used for compatibility with Android Support and Room.
Where I could find an info what need to be changed there?
error: cannot access SupportSQLiteDatabase SQLiteDatabase.loadLibs(context);
SQLiteDatabase imported from import net.sqlcipher.database.SQLiteDatabase;
This error is not visible on Android studio, only on CI/CD when creating build
Hi @FrozenPyrozen,
That sounds like a project configuration issue, or possibly your environment. SupportSQLiteDatabase
is not part of SQLCipher for Android [1].
Itās expected after updating app from net.zetetic:android-database-sqlcipher:3.5.7
to app with net.zetetic:android-database-sqlcipher:4.5.4
we started to see that app making a logout and need user to login again? This behaviour could be, because of migration?
Hi @FrozenPyrozen,
That sounds like an application-specific issue, SQLCipher for Android would not directly cause your application to logout.
Got it, just to understand got few questions:
- If we storing user in
SQLiteDatabase
which imported fromimport net.sqlcipher.database.SQLiteDatabase;
and we updating thesqlcipher
to4.5.4
and installing newer build, by default dosqlcipher
library do some changes for example how db was encrypted/decrypted and old data becomes unavailable or it should work by default with prev version created, encrypted db without any changes/logouts? - What are the possible triggers/events that could lead to clearing user data from db etc?
- I currently added:
public static SQLiteDatabaseHook migrateDbFrom3xFormatToCurrentSupportHook() {
return new SQLiteDatabaseHook() {
@Override
public void preKey(SQLiteDatabase database) {}
@Override
public void postKey(SQLiteDatabase database) {
// Apply PRAGMA to maintain SQLCipher 3 compatibility for net.zetetic:android-database-sqlcipher after 4x version
database.execSQL("PRAGMA cipher_compatibility = 3;");
}
};
}
and passing this to each function which opens db connection, but also Iāve seen override of public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
from SQLiteOpenHelper
, maybe smth could be added there to support smooth migration from old to new version with backwards compatibility?
Hi @FrozenPyrozen,
You previously mentioned using SQLCipher for Android 3.5.7. If you are upgrading to SQLCipher for Android 4.5.4, you will need to review the upgrade recommendations as SQLCipher 4 will not open a SQLCipher 3 database by default, there are several approaches to address this.
SQLCipher for Android uses the DatabaseErrorHandler
(similar to android.database.sqlite.DatabaseErrorHandler) using the default implementation which will delete the file on corruption. This is consistent with the android.database.sqlite
package. You can override this behavior by providing your own implementation for a DatabaseErrorHandler
via constructor argument to a SQLiteOpenHelper
subclass, or the static openDatabase
or openOrCreateDatabase
on the SQLiteDatabase
class.
Iāve added PRAGMA cipher_compatibility = 3;
to SQLiteDatabaseHook
and passed it to openDatabase
As I remember we discussed that itās enough, I think that without it SQLCipher 3 database wouldnāt be opened.
In my case we store user login data in db and could update app from net.zetetic:android-database-sqlcipher:3.5.7
to app with net.zetetic:android-database-sqlcipher:4.5.4
impact on this data that we need to login again or login should be the same as we would close and open app?
Hi @FrozenPyrozen,
Since you are using the compatibility setting, you are not updating the database file format. Your application should continue to work when moving the library from 3.5.7 to 4.5.4.
Hi @developernotes, Iāve used a migration hook in all places where Iāve got SQLiteDatabase.openDatabase
do you now other methods where I could place this hook also? Because we have a pin screen and it look like it trying to connect to new db with old approach, In some cases Iāve get an error with message net.sqlcipher.database.SQLiteException: file is not a database: , while compiling: select count(*) from sqlite_master
looks like that I need to add migration hook somewhere else also
My case:
- Iāve open app with 3.5.7, do login (save data in db 3.5.7)
- Iām hiding app to background and install 4.5.4
- When open app again Iāve got error
net.sqlcipher.database.SQLiteException: file is not a database: , while compiling: select count(*) from sqlite_master
If I would kill app instead hiding on step 2, I would be logged out, so maybe there other places where I need to place migration hook to have backwards compatibility for supporting 3.5.7 db version
Hi @FrozenPyrozen,
You should only be linking your application with one version of SQLCipher. It sounds like you may need to evaluate your application source further to determine all call sites that interface with SQLCipher for Android. You can apply the hook to both the static methods available on the SQLiteDatabase
class for opening/creating a database, along with any derivatives associated with the SQLiteOpenHelper
.