是否有正确的方法来测试用户提供的SQLCipher密码在Android上是否有效?

时间:2013-05-14 21:28:49

标签: android sqlcipher

我正在使用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)并在我的日志中写入一个完全不可抑制的错误。

3 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

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

我在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.
    }

答案 2 :(得分:0)

当前,验证密码短语的唯一方法是对数据库进行操作并检查其是否抛出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
        }
    }