Can't open android database that has a non-default cipher

We have successfully converted a database to use gcm cipher (PRAGMA encrypted.cipher = ‘aes-256-gcm’) but cannot open it afterward. (We get an error “file is encrypted or not a database”. I believe that this is because we can not specify a cipher in the open command:
SQLiteDatabase openDatabase(String path, char[] password, SQLiteDatabase.CursorFactory factory, int flags, SQLiteDatabaseHook databaseHook)

Is there any way around this?

BTW, I realize that the PRAGMA to set the cipher is deprecated but we have not choice, we need to use aes-256-gcm.

Hi @scott_coleman

Have you tried executing the cipher change in a postKey event of the SQLiteDatabaseHook? You can pass the hook to the openDatabase method. An example:

SQLiteDatabaseHook hook = new SQLiteDatabaseHook() {
  public void preKey(SQLiteDatabase database) {}
  public void postKey(SQLiteDatabase database) {
    database.rawExecSQL("PRAGMA cipher = 'aes-256-gcm';");
  }
};

Hi @developernotes

I am working @scott_coleman on this issue. Yeah I’ve tried utilizing the SQLiteDatabaseHook to switch cipher mode to aes-256-gcm in postKey.

The exact exception we get is…

I/Database: sqlite returned: error code = 26, msg = file is encrypted or is not a database
E/Database: CREATE TABLE android_metadata failed
E/Database: Failed to setLocate() when constructing, closing the database
net.sqlcipher.database.SQLiteException: file is encrypted or is not a database

From what I can tell the setLocate function is called after postKey so our statement “PRAGMA cipher=‘aes-256-gcm’;” in postKey should be executed. We previously had our database encrypted using the sqlcipher default of cbc using the fine example you guys provided. In order to satisfy our current requirement of gcm encryption we are following the “Changing Cipher Settings” example. Like as stated in Scott’s original post, our function based off the example to switch the cipher settings succeeds or at least doesn’t fail. The issue occurs when we attempt to open the database afterwards.

Is there another place we can change the cipher mode during the opening of our database? Perhaps we are missing a crucial step that isn’t included in the “Changing Cipher Settings” example we are following that may be causing issues on Android.

Examples I was referring to: https://www.zetetic.net/sqlcipher/sqlcipher-api/#sqlcipher_export (I’m sure you know what I was talking about but figured I would be complete). We are only changing the cipher mode, we have tried changing the cipher_page_size and kdf_iter but we still get the same error.

-Brad

Just tried this. Tried both preKey and postKey. I’ve confirmed that the hook is getting called but still get the same error.

Just to check I changed the PRAGMA cipher to cbc when both when I create the database and when I try to open it and it opens fine. Just doesn’t work setting it to gcm

A bit more info:
I found this on in the docs:
PRAGMA cipher must be called after PRAGMA key and before the first actual database operation or it will have no effect. - Tried this to no avail.

Here are the specific errors we are getting:
I/Database: sqlite returned: error code = 26, msg = file is encrypted or is not a database
E/Database: CREATE TABLE android_metadata failed

Hi @scott_coleman

I’ve just pushed up a test to show creating, closing and reopening with that cipher in SQLCipher for Android. Could you take a look at it here and compare it to yours?

In your code I don’t think that the database is being switched to gcm mode at all. I believe that the postKey method of setting the cipher doesn’t work.

I confirmed this by removing the hook from the second open, this means it should be looking for cbc, It opens fine which means the database just created was NOT gcm… Am I missing anything?

@developernotes If we have an existing database using the default cipher, do we need to use the sqlcipher_export process to switch the cipher to gcm? From the example test you posted, it seems like all we need to do is switch the ciphers in the postKey event and it should work even if the database was originally using the default cbc cipher.

Hi @scott_coleman

What version of SQLCipher for Android are you using? Was your database created using a cipher set to aes-256-gcm?

Hi @bcatlett

You cannot change the cipher on the fly. If you have an existing database that uses an alternative cipher, such as the default you would need to utilize the sqlcipher_export convenience function to change the cipher.

Ok that is what we have been trying.

Yeah our existing database was encrypted using the default cipher. Currently we are attempting to change the cipher used on our existing database using sqlcipher_export as shown in the “Change Cipher Settings” example. Afterwards we are attempting to open the database with the hook setup to run "PRAGMA cipher = ‘aes-256-gcm’ in postKey which results in the error described above.

So it appears that the settings are indeed being switched on the database, we just can’t open it afterwards.

I’m unsure about what version of SQLCipher for Android we are using. I’m sure @scott_coleman will be able to answer that.

Hi @scott_coleman

I’ve modified the test case I referenced above to show that the cipher is changing. As a follow up to my previous questions, what version of OpenSSL are you using?

Is this what you’re looking for?

#define SQLITE_VERSION “3.8.4.3”

Hi @scott_coleman

We are looking for the version of SQLCipher for Android, SQLCipher core, and OpenSSL you are using. Are you using the community build of SQLCipher for Android? If so, a Java client version number is available via SQLiteDatabase.SQLCIPHER_ANDROID_VERSION;. The version of SQLCipher core the library is using is available by executing PRAGMA cipher_version; from the library. SQLCipher core will report what crypto library you are using along with its version when executing PRAGMA cipher_provider_version; once you have key’ed the database. Would you please provide this additional information.

We are using the community version.

in my Java code SQLiteDatabase.SQLCIPHER_ANDROID_VERSION is undefined.
I greped for SQLCIPHER_ANDROID_VERSION nothing found

In code I tried unencryptedDatabase.rawExecSQL(“PRAGMA cipher_version;”). Is is supposed to print the version in the logcat?
ini crypto.h : #define CIPHER_VERSION “3.1.0”

Hello @scott_coleman

Are you using the community edition distribution of SQLCipher for Android, or are you building from source? If you are building from source, what version of OpenSSL are you using?

Yes, community edition.

Open ssl versions:
1.0.1 f
ecp-2.0.2

Hello @scott_coleman

Could you try running the test suite and let us know your results? What are you results if you just use the prebuilt community binaries within your application?

I just noticed the update warning about Android N. Instead of fighting this with an older version I think we’re going to just upgrade to your latest version.