Migration from Android legacy to regular SQLCipher version

Migration from legacy version to regular one went smoothly, DB works as expected on the new app. Problem occurs when new version in being installed on top of the app with legacy SQLCipher.

Failed to open database ‘/data/user/0/com.xxx/databases/xxx.db’.
net.zetetic.database.sqlcipher.SQLiteDatabaseCorruptException: file is not a database (code 26): , while compiling: PRAGMA journal_mode

For some reason legacy version .db file is not recognized as a valid database.
Error occurs on calling SQLiteDatabase#getWritableDatabase().
Could you please let me know what can be a source of an issue? We’re using proguard though I’ve already checked this one.
Let me know if you need any more code snippets.

Hi @PiotrKlis,

We have many tests which verify opening existing SQLCipher database files (some can be found here). From the error, it appears the database file is corrupt. A few follow-up questions:

  • What version of SQLCipher was used to created the database file in question?
  • Can you share the code that is being called and where the exception is occurring?
  • Can you open the same database file in DB Browser for SQLite successfully?

Hello @developernotes Nick!

I have a similar problem, after trying to migrate a v3.x to a v4.x I have ended out of solutions after looking at the forum.

Then I tried to clone the Tests Suite GitHub - sqlcipher/sqlcipher-android-tests: A collection of tests that can be run on an emulator or device to verify SQLCipher for Android. but I’ve found the classes are not correctly referenced:

import net.sqlcipher.database.SQLiteDatabase;
should be

import net.zetetic.database.sqlcipher.SQLiteDatabase;

Am I wrong?

Hi @Chezlui,

There are two different version of SQLCipher for Android. The legacy edition: android-database-sqlcipher and the new edition: sqlcipher-android.

The legacy edition uses an external test suite available here, while the tests for the new sqlcipher-android library are bundled within the library here.

If you are migrating from a SQLCipher 3.x to 4.x library version, you should review the migration options detailed here:

1 Like

Hey, thanks for your reply.

I’ve managed to fix my issue with adding try/catch in relevant methods:

public class DatabaseHelper extends SQLiteOpenHelper { 
...
  public SQLiteDatabase getDatabase(int flag, String password) {
    return SQLiteDatabase.openDatabase(
        context.getDatabasePath(DatabaseHelper.getDatabaseFilename()).getAbsolutePath(),
        password, null, flag,
        null, null);
  }
...
}

  private SQLiteDatabase getWritableDatabase() {
    try {
      return databaseHelper.getWritableDatabase();
    } catch (Exception exception) {
      return databaseHelper.getDatabase(SQLiteDatabase.OPEN_READWRITE, password);
    }
  }

  private SQLiteDatabase getReadableDatabase() {
    try {
      return databaseHelper.getReadableDatabase();
    } catch (Exception exception) {
      return databaseHelper.getDatabase(SQLiteDatabase.OPEN_READONLY, password);
    }
  }

I’m not sure if that’s optimal solution though it works for my scenarios - migrating from legacy version to new one and fresh app install.

Hey @developernotes,

I’m coming from the same team as @PiotrKlis. Is there any migration guide for moving from legacy edition to the new one? We are trying to move from net.zetetic:android-database-sqlcipher:4.5.3 to net.zetetic:sqlcipher-android:4.5.3, but this doesn’t seem to fully work for us. As Piotr mentioned we are getting error:

Failed to open database ‘/data/user/0/com.xxx/databases/xxx.db’.
net.zetetic.database.sqlcipher.SQLiteDatabaseCorruptException: file is not a database (code 26): , while compiling: PRAGMA journal_mode

When opening database that was created with new version it is fine to call

databaseHelper.getWritableDatabase()

but when we try to open existing database with the new version of the sqlCipher we are getting the above error.
Calling

SQLiteDatabase.openDatabase(context.getDatabasePath(DatabaseHelper.getDatabaseFilename()).getAbsolutePath(), password, null, SQLiteDatabase.OPEN_READWRITE | SQLiteDatabase.CREATE_IF_NECESSARY, null, null)

seems to work, but on the other hand this call doesn’t work for freshly created database (thus the try-catch used by Piotr above).
Could you provide any tips for properly migrating the databse (if necessary) and how it should be opened, so it works in both scenarios (app update and fresh install)

Hello @aleknow,

Is it at all possible you are providing an invalid password when attempting to open the database connection using the newer sqlcipher-android library? We found a regression where the SQLiteDatabaseCorruptException exception would be thrown with an invalid password. This will be fixed in the next public release.

Hi,

I hate to admit it, but you were right with the incorrect password :man_facepalming: After moving to new version password is passed in the constructor of SQLiteOpenHelper instead of passing it in method that gets the database. We didn’t notice that at the time of helper object creation password was not yet available, thus it was empty. Sorry for the cofusion and thank you for all good sugestions.

Hi @aleknow,

Thank you for the update, we are happy to hear you were able to resolve the issue!

@developernotes Just in case it is useful.

My problem was the same. Or pretty similar.

In my old code I used to open the DDBB with getReadableDatabase(password).
When I installed the new library, these methods raised an error because they no longer admit a password.

I thought that using this method after the previous openDatabase, would work and since the method compiled, I went forward.

The method (getReadableDatabase) compiled because your class is an extension of SQLiteOpenHelper, but in the new library is not overrided, while it was in the old one.

So maybe it is worth mentioning in the migration guide that this method does no longer works with an encrypted ddbb.

Thanks for the help, I realized my error by looking at the tests.