I'm using SQLCipher for Android and am trying to determine the correct way to test whether a user-provided password is valid.
My first inclination was to just try and open the database with the given password, using the SQLCipher implementation of SQLiteOpenHelper.getReadableDatabase(password)
, and then catch the SQLiteException
that pops out.
This does work, but the problem is that because the Android API actually wraps the underlying C calls, it does a lot of the work for you - specifically, when you open a database using the Android API, it opens the database, runs the native C-level sqlite3_key
method (with the provided password), then tries to set the locale on the database, whether or not the provided password was correct.
At this point, the Android library tries to set the locale, and the underlying database throws the "encrypted or not a database" SQLiteException
, which is caught and rethrown; but before it is, an unrelated error is written to the logs, essentially saying the locale cannot be set and the database is being closed (with an included stack trace). Because this is specifically written by the Android library, I cannot suppress it, leaving an ugly error in the logs that is actually unrelated to my original problem, which was simply that I passed in the wrong password.
Because the Android library does not expose the C-level calls, I can't just use the method described in the SQLCipher API documentation regarding Testing the Key, because I don't have access to directly open the database.
I lean towards using the SQLiteDatabaseHook
, but as best I can tell, that precludes my use of SQLiteOpenHelper
, which does not appear to provide a way to set up a hook.
Does anyone else know any better way to test whether an input passphrase properly decrypts a SQLCipher database through the SQLCipher Android API? I would completely expect to call a method and check for an exception being thrown - what I don't want is for the operation to try and perform extraneous processing (like set locale) on the database and write a completely insuppressible error to my logs.
I don't have a better way of testing it. I just want to provide some code in addition, so when other people look this up, they may find some useful code snippets. At least when I found this question, I would have loved to see some code how do to the check-up :)
The way I do it in android is this:
// Simply get an instance of SQLiteOpenHelper.
dbHelperObj = myDatabase.getInstance(this, str_username, version);
// Now we try to open the database with the password from the user.
try {
dbObj = dbHelperObj.getReadableDatabase(str_password);
// The only possible error now must be a wrong password.
} catch (Exception e) {
dbHelperObj.close();
// Do stuff to tell the user he provided a wrong password.
}
SQLCipher for Android does not know that the password you have provided is invalid following a sqlite3_key
call, as the database key isn't used until a SQL command is issued against the database following the sqlite3_key
, such as the setLocale(...)
method you reference above. The problem is, providing an invalid key may be only one of possible other scenarios that could be the problem at the point the first SQL statement is executed. A corrupt data file, a failed HMAC check, or opening a non database file could result in this same error message. For a detailed description of this please review this thread. It would be best to catch the exception when attempting to open the database and handle accordingly within the client application.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With