Upgrading from android-database-sqlcipher to sqlcipher-android

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.

1 Like

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.

1 Like

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.

1 Like

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:

  1. Everything above, but only with database.execSQL("PRAGMA cipher_compatibility = 3;"); would be enough?
  2. Iā€™ve got import net.sqlcipher.database.SQLiteException; and error ā€œCannot resolve symbol ā€˜SQLiteExceptionā€™ā€. Does SQLiteException 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.


  1. SQLCipher 4.5.4 Release | Zetetic ā†©ļøŽ

1 Like

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].


  1. SupportSQLiteDatabase  |  Android Developers ā†©ļøŽ

1 Like

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.

1 Like

Got it, just to understand got few questions:

  1. If we storing user in SQLiteDatabase which imported from import net.sqlcipher.database.SQLiteDatabase; and we updating the sqlcipher to 4.5.4 and installing newer build, by default do sqlcipher 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?
  2. What are the possible triggers/events that could lead to clearing user data from db etc?
  3. 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:

  1. Iā€™ve open app with 3.5.7, do login (save data in db 3.5.7)
  2. Iā€™m hiding app to background and install 4.5.4
  3. 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.