Upgrading Sqlcipher for Android from 3 to 4

I upgraded Sqlcipher for Android from 3.5.7 to 4.1.3 in my app.

For the existing database, which has been created with Sqlcipher 3, I need a custom migration as it is based on custom parameters, as also the option 3 of this article explains.

I’m getting this exception when I try to open the database.

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)

This is my code:

        SQLiteDatabaseHook mHook = new SQLiteDatabaseHook() {
            public void preKey(SQLiteDatabase database) {
                database.rawExecSQL("PRAGMA kdf_iter=1000;");
                database.rawExecSQL("PRAGMA cipher_default_kdf_iter=1000;");
                database.rawExecSQL("PRAGMA cipher_page_size = 4096;");
            }

            public void postKey(SQLiteDatabase database) {
                database.rawExecSQL("PRAGMA cipher_compatibility=3;");
            }
        };

        // this line generate the exception
        SQLiteDatabase database = SQLiteDatabase.openDatabase(oldDatabaseFile.getAbsolutePath(), password, null, SQLiteDatabase.OPEN_READWRITE, mHook);
        ...
        // migration code with ATTACH, sqlcipher_export etc... 
        ...

The file exists and the password is correct: The same piece of code works if I downgrade the Sqlcipher library. What I am doing wrong?

Hi @Luigi_Capasso,

using PRAGMA cipher_compatability=3 will use the default SQLCipher 3 settings, as outlined in the API documentation here: SQLCipher API - Zetetic

Calling this PRAGMA and passing in 1, 2, or 3 will cause SQLCipher to operate with default settings consistent with that major version number for the current connection, e.g. the following will cause SQLCipher to treat the current database as a SQLCipher 3.x database

The default settings for a SQLCipher 3 database are referenced here: SQLCipher 4.0.0 Release - Zetetic under Compatability

PRAGMA cipher_page_size = 1024; 
PRAGMA kdf_iter = 64000; 
PRAGMA cipher_hmac_algorithm = HMAC_SHA1; 
PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1;

Because your database was using non-default SQLCipher 3 settings, PRAGMA cipher_compatability = 3; alone will not work for opening your database.

While you are setting your database specific settings in preKey these are being overwritten by the SQLCipher 3 defaults in postKey when you call PRAGMA cipher_compatability=3.

You should be able to move the PRAGMA cipher_compatability=3 call to the beginning of preKey the use your specific PRAGMA’s to overwrite the non-default settings you’re using.

public void preKey(SQLiteDatabase database) {
    database.rawExecSQL("PRAGMA cipher_compatibility=3;");
    database.rawExecSQL("PRAGMA kdf_iter=1000;");
    database.rawExecSQL("PRAGMA cipher_default_kdf_iter=1000;");
    database.rawExecSQL("PRAGMA cipher_page_size = 4096;");
}

Thank you, but it’s still not working. Same error.

@Luigi_Capasso

I apologize, could you actually put the PRAGMA’s in the postKey hook?

public void postKey(SQLiteDatabase database) {
    database.rawExecSQL("PRAGMA cipher_compatibility=3;");
    database.rawExecSQL("PRAGMA kdf_iter=1000;");
    database.rawExecSQL("PRAGMA cipher_default_kdf_iter=1000;");
    database.rawExecSQL("PRAGMA cipher_page_size = 4096;");
}

Let me know if that does the trick for you. Thanks!

Finally, I managed to do it. The problem was the cipher_page_size = 4096; which was probably ignored by sqlchipher 3 so using it with sqlchipher 4 was like using a wrong parameter: without specifying it or with cipher_page_size = 1024 (the default for version 3) it works!
Thank you

@Luigi_Capasso

Glad to hear you were able to get it working. It does sound like the cipher_page_size PRAMGA was never being applied previously. Where were you executing it?

A post was merged into an existing topic: PRAGMA cipher_migrate problem