@developernotes how to get current db cipher_page_size
, kdf_iter
, cipher_hmac_algorithm
, cipher_kdf_algorithm
to verify that is actual (to get/verify non-default SQLCipher 3 settings) and check that database.rawExecSQL("PRAGMA cipher_compatibility = 3;");
applied successfully?
You can use PRAGMA cipher_settings;
[1] once you have keyed the database to report the current library configuration:
$ ./sqlcipher ~/Desktop/foo.db
SQLite version 3.46.1 2024-08-13 09:16:08 (SQLCipher 4.6.1 community)
Enter ".help" for usage hints.
sqlite> pragma key = 'foo';
ok
sqlite> pragma cipher_settings;
PRAGMA kdf_iter = 256000;
PRAGMA cipher_page_size = 4096;
PRAGMA cipher_use_hmac = 1;
PRAGMA cipher_plaintext_header_size = 0;
PRAGMA cipher_hmac_algorithm = HMAC_SHA512;
PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA512;
sqlite> pragma cipher_compatibility = 3;
sqlite> pragma cipher_settings;
PRAGMA kdf_iter = 64000;
PRAGMA cipher_page_size = 1024;
PRAGMA cipher_use_hmac = 1;
PRAGMA cipher_plaintext_header_size = 0;
PRAGMA cipher_hmac_algorithm = HMAC_SHA1;
PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1;
It’s possible to connect to existing db from Android java code and check all of these?
@developernotes also I’ve noticed that in my case error file is encrypted or is not a database: , while compiling: select count(*) from sqlite_master; E Database: net.sqlcipher.database.SQLiteException: file is encrypted or is not a database: , while compiling: select count(*) from sqlite_master;
coming after calling getWritableDatabase
. It’s possible to place migration hook before calling getWritableDatabase
or make sure that kdf_iter
and other cipher...
configs are right from Android java code?
Hi @FrozenPyrozen,
You can provide a SQLiteDatabaseHook
instance to a SQLiteOpenHelper
derivative.
Hi, @developernotes I’m not sure how to run ./sqlcipher ~/Desktop/foo.db
in my case im working with Android device from Java code, maybe you know how to check these cipher config from Java code?
Enter ".help" for usage hints. sqlite> pragma key = 'foo'; ok sqlite> pragma cipher_settings; PRAGMA kdf_iter = 256000; PRAGMA cipher_page_size = 4096; PRAGMA cipher_use_hmac = 1; PRAGMA cipher_plaintext_header_size = 0; PRAGMA cipher_hmac_algorithm = HMAC_SHA512; PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA512; sqlite> pragma cipher_compatibility = 3; sqlite> pragma cipher_settings; PRAGMA kdf_iter = 64000; PRAGMA cipher_page_size = 1024; PRAGMA cipher_use_hmac = 1; PRAGMA cipher_plaintext_header_size = 0; PRAGMA cipher_hmac_algorithm = HMAC_SHA1; PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1;
Hi @FrozenPyrozen,
I was just showing your the PRAGMA
commands that you can issue. If you are operating on the Android platform you would generally need to exercise the SQLCipher for Android API to invoke those commands.
@developernotes are there are some methods to get all cipher settings from current db? For example I could call stmh similar to db.getCipherEncryptionSettings()
from pre lib update 3.5.7
sql cipher build and then get the db.getCipherEncryptionSettings()
from build with cipher 4.5.4
?
@developernotes in my case I’ve got a class DatabaseHelper
which extends from SQLiteOpenHelper
so I need to put SQLiteDatabaseHook
into constructor or where?
No, you will need to execute the PRAGMA commands and iterate over the results. This is an example using the older android-database-sqlcipher
API, this is an example using the sqlcipher-android
library. You will note the API is quite similar for this scenario.
Hi @FrozenPyrozen,
The older android-database-sqlcipher
exposes several constructors to the SQLiteOpenHelper
which accept a SQLiteDatabaseHook
. Additionally, you will find several constructor options with the SQLiteOpenHelper
in the newer sqlcipher-android
library that does the same.
Hi, @developernotes it really helps me out I’ve added, but do you have examples how to get other pragma cipher settings like kdf_iter
, cipher_plaintext_header_size
, cipher_hmac_algorithm
, cipher_kdf_algorithm
, kdf_iter
, cipher_page_size
, cipher_use_hmac
, cipher_plaintext_header_size
, cipher_hmac_algorithm
, cipher_kdf_algorithm
like this for older android-database-sqlcipher
API?
Hi @FrozenPyrozen,
Sorry, the PRAGMA cipher_settings
command wasn’t added until SQLCipher core 4.1.0 release [1]. That said, if you are using the newer library, you can execute that command against a database that was created with SQLCipher 3.x.
Hello @FrozenPyrozen,
Just to clarify, the PRAGMA cipher_settings
command will only return the runtime configured options from the library. It will not report what a given database file was configured with as that is not stored within the database file itself.
@developernotes Is it possible to get kdf_iter, cipher_plaintext_header_size, cipher_hmac_algorithm, cipher_kdf_algorithm, kdf_iter, cipher_page_size, cipher_use_hmac, cipher_plaintext_header_size, cipher_hmac_algorithm, cipher_kdf_algorithm
that were used to create/configure db initially?
Hi, @developernotes
Curently I’ve added checkCipherSettings
to check before database.execSQL("PRAGMA cipher_compatibility = 3;");
configs and compare with after it
Code:
private void checkCipherSettings(SQLiteDatabase database) {
String[] pragmas = {
"PRAGMA cipher_compatibility;",
"PRAGMA kdf_iter;",
"PRAGMA cipher_plaintext_header_size;",
"PRAGMA cipher_hmac_algorithm;",
"PRAGMA cipher_kdf_algorithm;",
"PRAGMA cipher_page_size;",
"PRAGMA cipher_use_hmac;",
"PRAGMA cipher_settings;"
};
try {
for (String pragma : pragmas) {
Cursor cursor = database.rawQuery(pragma, null);
if (cursor != null && cursor.moveToFirst()) {
String result = cursor.getString(0);
Log.i("CipherSettings", "[KLOG]: " + pragma + " " + result);
cursor.close();
} else {
Log.i("CipherSettings", "[KLOG] Failed to retrieve value for " + pragma);
}
}
} catch (Exception e) {
Log.e("CipherSettings", "[KLOG] Error while fetching cipher settings: " + e.getMessage(), e);
}
}
@Override
public void postKey(SQLiteDatabase database) {
Log.i("DatabaseHelper", "[KLOG] postKey triggered for db: " + database);
Log.i("DatabaseHelper", "[KLOG] _________ before this.checkCipherSettings for existing db __________: ");
this.checkCipherSettings(database);
Log.i("DatabaseHelper", "[KLOG] _________ after this.checkCipherSettings for existing db __________: ");
Log.i("DatabaseHelper", "[KLOG] postKey before database cipher_compatibility to 3");
// Apply PRAGMA to maintain SQLCipher 3 compatibility for net.zetetic:android-database-sqlcipher after 4x version
database.execSQL("PRAGMA cipher_compatibility = 3;");
Log.i("DatabaseHelper", "[KLOG] postKey after database cipher_compatibility to 3");
Log.i("DatabaseHelper", "[KLOG] _________ before this.checkCipherSettings for cipher_compatibility = 3 db __________: ");
this.checkCipherSettings(database);
Log.i("DatabaseHelper", "[KLOG] _________ after this.checkCipherSettings for cipher_compatibility = 3 db __________: ");
}
And I’ve got some differences:
After this I’ve changed postKey
to set exact same kdf_iter
, cipher_hmac_algorithm
, cipher_kdf_algorithm
, cipher_page_size
settings as it was before database.execSQL("PRAGMA cipher_compatibility = 3;");
public void postKey(SQLiteDatabase database) {
Log.i("DatabaseHelper", "[KLOG] postKey triggered for db: " + database);
Log.i("DatabaseHelper", "[KLOG] _________ before this.checkCipherSettings for existing db __________: ");
this.checkCipherSettings(database);
Log.i("DatabaseHelper", "[KLOG] _________ after this.checkCipherSettings for existing db __________: ");
Log.i("DatabaseHelper", "[KLOG] postKey before database cipher_compatibility to 3");
// Apply PRAGMA to maintain SQLCipher 3 compatibility for net.zetetic:android-database-sqlcipher after 4x version
database.execSQL("PRAGMA cipher_compatibility = 3;");
database.execSQL("PRAGMA kdf_iter = 256000;");
database.execSQL("PRAGMA cipher_hmac_algorithm = HMAC_SHA512;");
database.execSQL("PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA512;");
database.execSQL("PRAGMA cipher_page_size = 4096;");
Log.i("DatabaseHelper", "[KLOG] postKey after database cipher_compatibility to 3");
Log.i("DatabaseHelper", "[KLOG] _________ before this.checkCipherSettings for cipher_compatibility = 3 db __________: ");
this.checkCipherSettings(database);
Log.i("DatabaseHelper", "[KLOG] _________ after this.checkCipherSettings for cipher_compatibility = 3 db __________: ");
}
Now they are equal, but I still have an error android.database.sqlite.SQLiteException: file is not a database: , while compiling: select count(*) from sqlite_master;
after this:
Maybe I could check existing db setup with sql cipher old library v3? Or maybe I missed some pragma that needs for opening db file
Hi @FrozenPyrozen,
No, that is not stored in the database file. Unless the database was created with non-default configuration options with regard to those settings, you could cycle through the values supported by PRAGMA cipher_compatibility
[1] and attempt to open the database to identify the SQLCipher version needed for that specific database. The cipher_compatibility
pragma will set the appropriate values on your behalf. Please review the documentation for usage.
@developernotes could I get somehow these values and other creation config from place where I created a db with old v3 library?
Hi @FrozenPyrozen,
Can you share what you’re trying to accomplish? This thread is getting rather long and I don’t think we understand exactly what your situation is in detail. Could you provide those details? Thanks!
Hi, @developernotes I’m trying to update net.zetetic:android-database-sqlcipher:3.5.7
to net.zetetic:android-database-sqlcipher:4.5.4
. So basically I’ve got prev app build with net.zetetic:android-database-sqlcipher:3.5.7
and I’ve created new app build with net.zetetic:android-database-sqlcipher:4.5.4
. I’ve decided to go with backwards compatibility step with database.execSQL("PRAGMA cipher_compatibility = 3;");
. When I’m installing new app on prev with already created db I’ve got an error on this.getWritableDatabase
of based on SQLiteOpenHelper
class`:
file is encrypted or is not a database: , while compiling: select count(*) from sqlite_master; 11-14 15:15:27.619 18529 18529 E Database: net.sqlcipher.database.SQLiteException: file is encrypted or is not a database: , while compiling: select count(*) from sqlite_master;
So I’m passing compatibility hook to based on SQLiteOpenHelper
class constructor super(context, NetworkConstant.DATABASE_NAME, null, NetworkConstant.DATABASE_VERSION, DatabaseHelper.migrateDbFrom3xFormatToCurrentSupportHook());
but it didn’t help and I trying to understand why
Currently I’m trying to get all possible db info to understand what is the db settings for prev app and what’s changed in new app with net.zetetic:android-database-sqlcipher:4.5.4
Here I’ve tried to compare cipher settings for prev and new build, but maybe I missed to check smth else, because after setting the same pragmas when I’ve got before launching database.execSQL("PRAGMA cipher_compatibility = 3;");
didn’t work