我正在使用SQLCipher for Android,正在尝试确定测试用户提供的密码是否有效的正确方法。
我的第一个倾向是尝试使用给定的密码,使用SQLiteOpenHelper.getReadableDatabase(password)
的SQLCipher实现打开数据库,然后捕获弹出的SQLiteException
。
这确实有效,但是问题在于,因为Android API实际上包装了基础C调用,所以它为您完成了很多工作-特别是,当您使用Android API打开数据库时,它将打开数据库并运行本机C级sqlite3_key
方法(使用提供的密码),然后尝试在数据库上设置语言环境,无论提供的密码是否正确。
[此时,Android库尝试设置区域设置,并且基础数据库抛出被捕获并重新抛出的“加密或非数据库” SQLiteException
;但在此之前,一个不相关的错误被写入日志,这实际上是说无法设置语言环境并且正在关闭数据库(包括堆栈跟踪)。因为这是由Android库专门编写的,所以我无法抑制它,在日志中留下一个难看的错误,该错误实际上与我的原始问题无关,这仅仅是我输入了错误的密码。
由于Android库未公开C级调用,所以我不能仅使用SQLCipher API文档中有关Testing the Key的方法,因为我无权直接打开数据库。
[我倾向于使用SQLiteDatabaseHook
,但是据我所知,这排除了我对SQLiteOpenHelper
的使用,这似乎无法提供建立钩子的方法。
还有其他人知道更好的方法来测试输入密码短语是否通过SQLCipher Android API正确解密SQLCipher数据库吗?我完全希望调用一个方法并检查是否引发了异常-我不希望该操作尝试在数据库上执行无关的处理(如set locale),并向日志中写入完全无法抑制的错误。
用于Android的SQLCipher不知道您在sqlite3_key
调用后提供的密码无效,因为在sqlite3_key
之后针对数据库发出SQL命令之前,不会使用数据库密钥,例如[您在上面引用的setLocale(...)
方法。问题是,提供无效密钥可能只是其他可能出现的情况之一,在执行第一个SQL语句时可能是问题所在。数据文件损坏,HMAC检查失败或打开非数据库文件都可能导致此错误消息。有关此内容的详细说明,请查看此thread。尝试打开数据库并在客户端应用程序中进行相应处理时,最好捕获异常。
我没有更好的测试方法。我只想提供一些代码,所以当其他人查找时,他们可能会发现一些有用的代码片段。至少当我发现这个问题时,我很想看看一些代码如何进行检查:)
我在android中的操作方式是这样:
// 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.
}
当前,唯一验证密码短语的方法是对数据库进行操作,并检查其是否抛出net.sqlcipher.database.SQLiteException
。因此,对于那些将SQLCipher与Room ORM一起使用的人,下面的代码应该可以完成工作。
使用提供的密码获取Room数据库实例后,调用isPassphraseValid()
函数并将数据库实例传递给它。
/* Passphrase validation: */
private fun isPassphraseValid(db: MyRoomDatabase): Boolean {
return try {
db.openHelper.readableDatabase
Log.d("sql-log", "Pass phrase is valid.")
true
} catch (e: net.sqlcipher.database.SQLiteException) {
e.printStackTrace()
Log.d("sql-log", "Pass phrase is not valid.")
false
}
}