I ran into a few issues while working with an in-memory database and trying to attach a on-disk database. The project I’m working on is using the Android Library, version 3.5.9.
Here is what the app is doing:
Create an on-disk database with a password. The ‘cipher_page_size’ is set to 4096.
Create an in-memory database without changing any settings.
Attach the on-disk database to the in-memory one.
I get an exception saying file is not a database.
I found out that, if I do not use a password to create the on-disk database, it works.
I also found out that, if I change the cipher page size to 1024 for the on-disk database, it works.
Questions I have:
Is the exception thrown because the two databases have different page sizes?
As a follow-up, does that imply the in-memory database have default page size of 1024?
My understanding is that the in-memory database is not encrypted. Does that mean it does not even have cipher_page_size setting?
The project I’m working on is using the Android Library, version 3.5.9.
SQLCipher for Android uses SQLCipher core 3.4.2. The default cipher_page_size in 3.4.2 was 1024. You would need to specify the non-standard (relative to SQLCipher core 3.4.2) cipher_page_size in order to interface with that attached database. So they would both have different cipher_page_size values. An example is below:
$ ./sqlcipher :memory:sqlite
sqlite> ATTACH DATABASE 'otherdb.db' AS other KEY 'otherkey';
sqlite> PRAGMA other.cipher_page_size = 4096;
sqlite> SELECT COUNT(*) FROM other.sqlite_master;
I found out that, if I do not use a password to create the on-disk database, it works.
This is because SQLite moved to 4096 as a default page size with the release of SQLite 3.12.0, before SQLCipher migrated to using a value of 4096. If you do not key the database, the SQLCipher codec is not attached and defaults to the SQLite behavior.
If I may ask a follow-up question, is there a workaround for the case where we want to attach an existing encrypted database with a non-default page size?
And could you clarify a bit about the differences between page_size and cipher_page_size.
With SQLCipher for Android you will want to utilize a SQLiteDatabaseHook when constructing your connection, specifying your non-default cipher_page_size value in the postKey event. An example can be found here. If you need to maintain a different page size between the attached database and the originating database, please see the comments below about using cipher_default_page_size instead.
SQLite uses PRAGMA page_size to determine the size of the database page written to disk, whereas SQLCipher utilizes the variable cipher_page_size for adjusting SQLCipher-encrypted database files. The documentation for the latter is available here. Additionally, SQLCipher also supports cipher_default_page_size (documented here) which allows for differing the page size for future connections that differ from the configurations set on the current connection.