Android 4.10.0 Upgrade cipher_migrate crash

I am seeing the following error when I do a pragma cipher_migrate;
Error: android.database.sqlite.SQLiteOutOfMemoryException: out of memory (code 7): , while compiling: SELECT COUNT(*) FROM sqlite_schema

It appears to be something changed in the migration somewhere between the 4.51 to 4.10.0

I have the exact same “encypted.sqlite” test file that I tested everywhere since I’m doing tests only. I can provide it since it is just a test file, but apparently discourse won’t let me upload it yet because I’m a new user… I’ll attach it tomorrow if possible.

  1. iOS 4.10.0 - no problems, cipher_migrate works perfectly fine with the file.
  2. Android 4.10.0 - migrate totally fails, with the above error.
  3. Android 4.5.1 - migrate works fine.
  4. Command line program on Linux - 4.5.1 cipher_migrate works fine and migrates it perfectly.
  5. Command line 4.10.0 throws a bunch of errors when I do a cipher_migrate:
    2025-08-11 22:50:09.739: ERROR CORE sqlcipher_page_cipher: hmac check failed for pgno=1
    2025-08-11 22:50:09.739: ERROR CORE sqlite3Codec: error decrypting page 1 data: 1
    2025-08-11 22:50:09.739: ERROR CORE sqlcipher_codec_ctx_set_error 1
    0

However interestingly enough the file does seem to be converted correctly [although doing a binary diff the 4.10.0 has some binary differences from the 4.5.1 migrated file???].

Notes:

  • If I don’t run the pragma cipher_migrate, the file is not seen as a valid db file.
  • I did try using the cipher_compatibility 1-4 and it made no difference
  • Both 4.5.1 & 4.10.0 could open each others sqlite converted files w/o any issues
  • cipher_integrity_check didn’t find anything wrong with EITHER versions converted table.

encrypted.zip (2.2 KB)

Inside this zip file is the encrypted.sqlite file [since I can’t upload it directly], the password is simply “testing” :wink:

I should also mention it is a simple table of “names” – so after you open it “select * from names” should show you 5 or 6 names…

Hello @NathanaelA - There really aren’t any meaningful differences in the implementation of PRAGMA cipher_migrate in the core library on Android vs the other platforms. Can you share the code that you are using to perform the PRAGMA cipher_migrate on Android? Are you executing it in the context of a SQLiteDatabaseHook.postKey?

Yes, It is setup as a postKey setup.
→ Code:

conn.executeForLong("PRAGMA cipher_migrate;", null, null);

This returns the value of “1”.

I’ve also tried adding a executeRaw(‘pragma key = ‘testing’;’) before this statement in the postkey, and the result is identical. There is no prekey stuff nor is their any other calls in the postKey function.

The connection is created as

file = ”/path/to/encrypted.sqlite”
passwordString = “testing”
flags = 0.

openDatabase(file, passwordString, null, flags | 0x10000000, null, hook) , and then I see the error:

Error: android.database.sqlite.SQLiteOutOfMemoryException: out of memory (code 7): , while compiling: SELECT COUNT(*) FROM sqlite_schema

I’m not running that select statement, the library is I assume to populate internal data…

If I don’t pass in the hooks or the hook doesn’t call the pragma cipher_migrate, then I get the standard this is not a database error. :wink:

I should also mention, if I pre-convert the above attached db using either version of the command line tools, then everything works fine on the android application, even with the hook still calling an (now) un-needed “pragma cipher_migrate;”

Obviously their is something different as the older tools shows no errors and works, and you can see the 4.10 command line tooling spits out 3 different errors and I suspect these errors leaves the Android version in a bad state, where the command line version recovers (maybe because it has access to massive amounts of memory?)…

Make sure you are opening the connection with both the OPEN_READWRITE and CREATE_IF_NECESSARY flags.

The command line tool behavior is expected. Those aren’t errors in the sense that they are permant problems. Rather, they are log messages indicating that an incorrect key was provided to open the database. Since cipher_migrate does attempt to open the database with various settings (including version 4), those messages get logged. On the command line the default log target is stderr, so you see them there.

FYI on Android:

OPEN_READWRITE = 0
CREATE_IF_NECESSARY = 0x10000000

Which is why I OR the 0x10000000 with it as I might in the future send additional flags to the open routine, but currently I send only the READ WRITE value of (0). :wink:

Just for testing purposes trying to narrow down what was broken – I also tried pointing it to a file that didn’t exist, and it created it and opened it fine and even ran the cipher_migrate on it fine, so obviously the flags value is being passed in and used correctly on android. :wink:


So if those are just logged, then how come in 4.5.1 those weren’t logged? Or did they get added in a later version?

@NathanaelA - as a next step, I would like you to setup trace logging Prior to calling cipher_migrate, execute:

PRAGMA cipher_log = '/path/to/writable/log.txt';
PRAGMA cipher_log_level = TRACE;

Then capture the log and post it. This may help trace out exactly what is failing inside cipher_migrate.

Also, it’s worth checking whether there is free space on the device you are testing with. How large is the database you are attempting to migrate, and how much free space is available?

The reason the log messages weren’t visible in 4.5.1 is that the default log level was set to warn in SQLCipher 4.6.0.

I’ll do the logging – as for space, not only is their plenty – the db is like only 2048 BYTES in size. :wink:

Well I must apologize, I can not duplicate it again.

The only thing I can think of is somehow I got an actual corrupted db onto the device. I’ve double checked everything and de/re-install the app a dozen times now… Every time pragma cipher_migrate works without an issue now.

Sorry for wasting your time! If I see it again, I’ll reopen this thread with the logging.