8

我正在使用适用于 Android 的 SQLCipher,并试图确定测试用户提供的密码是否有效的正确方法。

我的第一个倾向是尝试使用给定密码打开数据库,使用 SQLCipher 实现SQLiteOpenHelper.getReadableDatabase(password),然后捕获SQLiteException弹出的内容。

这确实有效,但问题是因为 Android API 实际上包装了底层 C 调用,它为您做了很多工作 - 具体来说,当您使用 Android API 打开数据库时,它会打开数据库,运行本机C 级sqlite3_key方法(使用提供的密码),然后尝试在数据库上设置区域设置,无论提供的密码是否正确。

此时Android库尝试设置locale,底层数据库抛出“加密还是不是数据库” SQLiteException,被捕获并重新抛出;但在此之前,一个不相关的错误被写入日志,本质上是说无法设置区域设置并且数据库正在关闭(包含堆栈跟踪)。因为这是由Android库专门编写的,所以我无法抑制它,在日志中留下一个与我原来的问题无关的丑陋错误,这只是我输入了错误的密码。

因为 Android 库不公开 C 级调用,所以我不能只使用 SQLCipher API 文档中关于Testing the Key描述的方法,因为我无权直接打开数据库。

我倾向于使用SQLiteDatabaseHook,但据我所知,这排除了我使用SQLiteOpenHelper,它似乎没有提供设置挂钩的方法。

还有其他人知道测试输入密码是否通过 SQLCipher Android API 正确解密 SQLCipher 数据库的更好方法吗?我完全希望调用一个方法并检查是否引发了异常 - 我不希望该操作尝试在数据库上执行无关处理(如设置区域设置)并将一个完全无法抑制的错误写入我的日志。

4

3 回答 3

2

我没有更好的测试方法。我只是想另外提供一些代码,所以当其他人查找时,他们可能会发现一些有用的代码片段。至少当我发现这个问题时,我很想看到一些代码如何进行检查:)

我在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.
    }
于 2014-08-22T11:40:41.703 回答
1

SQLCipher for Android 不知道您提供的密码在sqlite3_key调用后是无效的,因为在对 后面的数据库发出 SQL 命令之前不会使用数据库密钥sqlite3_key,例如setLocale(...)您上面引用的方法。问题是,提供无效键可能只是在执行第一个 SQL 语句时可能出现问题的其他可能场景之一。损坏的数据文件、失败的 HMAC 检查或打开非数据库文件都可能导致同样的错误消息。有关这方面的详细说明,请查看此线程。最好在尝试打开数据库并在客户端应用程序中进行相应处理时捕获异常。

于 2013-05-15T15:32:33.623 回答
0

目前,验证密码的唯一方法是对数据库进行操作并检查它是否会抛出net.sqlcipher.database.SQLiteException. 所以对于那些使用带有 Room ORM 的 SQLCipher 的人来说,下面的代码应该可以完成这项工作。

使用提供的密码获取 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
        }
    }
于 2020-02-29T09:08:14.307 回答