【问题标题】:How to check if data in room database is encrypted?如何检查房间数据库中的数据是否加密?
【发布时间】:2021-10-28 14:56:45
【问题描述】:

我正在构建一个使用房间数据库的应用程序,并使用 SQLCipher 对其进行加密。我如何检查数据是否真的加密,因为这是我第一次使用加密,我不知道我是否正确。

【问题讨论】:

  • 您是否尝试过使用android studio中提供的数据库检查器工具?
  • 同意:如果您的目标是一次性检查数据库是否已加密,请尝试在不支持加密的 SQLite 客户端中打开数据库。如果您的目标是编写检测测试,请尝试在 Room 中打开数据库,而不使用您用于 SQLCipher 的 openHelperFactory() - 如果您可以在没有 SQLCipher 的情况下打开和读取数据库,则数据库未加密。

标签: android kotlin android-room sqlcipher sqlcipher-android


【解决方案1】:

假设您要检查数据库是否在应用程序中加密,那么您必须小心一点。

建议在不使用密钥的情况下通过房间打开数据库进行检查,如果数据库被加密,将导致数据丢失。

  • 这是因为当房间尝试打开加密时的数据库时,它将被视为损坏的数据库,因为整个文件都已加密,因此不是有效的数据库文件(标题字符串不是必需的标题字符串“SQLite格式 3\000")。 Room 然后会删除损坏的数据库,然后调用 onCreate 方法提供一个没有数据的有效新数据库。

  • What happens when room android db gets corrupted?

我建议您考虑打开文件,而不是作为数据库,而是作为文件并检查前 16 个字节是否为“SQLite 格式 3\000”。

如果是“SQLite format 3\000”那么数据库没有被加密,如果不是“SQLite format 3\000”那么数据库(如果文件实际上是一个/数据库文件)可能是加密。

也许可以考虑以下几点:-

    /**
     * Check to see if the database is encrypted
     *
     * NOTE assumes encrypted if the database header string is not the required SQLite header string
     * WARNING any invalid file would be considered encrypted
     */
    fun isEncryptedDatabase(context: Context, databaseName: String): Boolean {
        var rv = false

        // SQlite header String 16 bytes as SQLite format 3\000
        //  hex representation is  53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00
        val requiredSQLiteFileHeaderString: ByteArray
            = byteArrayOf(0x53,0x51,0x4c,0x69,0x74,0x65,0x20,0x66,0x6F,0x72,0x6D,0x72,0x61,0x74,0x20,0x33,0x0)
        var dbFileHeader = ByteArray(requiredSQLiteFileHeaderString.size)
        var i: InputStream
        try {
            i = FileInputStream(context.getDatabasePath(databaseName))
            i.read(dbFileHeader)
            if(!dbFileHeader.equals(requiredSQLiteFileHeaderString)) {
                rv = true
            }
            i.close()
        } catch (e: IOException) {
            rv = true;
        }
        return rv
    }
}

您可以在 Room 之外和 Room 打开数据库之前使用它。考虑到上面使用了 Context 的 getDatabasePath 方法,那么真正的结果(数据库被加密)很可能是由于数据库被加密而不是另一种类型的文件。

这是使用嵌入在@Database 类中的上述代码的示例(基于使用用于上述链接答案的代码)。活动代码是:-

class MainActivity : AppCompatActivity() {
    lateinit var db: TheDatabase
    lateinit var dao: AllDao
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        if (!TheDatabase.isEncryptedDatabase(this,TheDatabase.DATABASENAME)) {
            //.... handle un-encrypted database here
        }
        db = TheDatabase.getInstance(this)
        dao = db.getAllDao()
        .... 
    }
}
  • 为了方便和简洁,请注意以上使用主线程(即.allowMainThreadQueries() 已在 databaseBuilder 中编码)

【讨论】:

  • “在 Room 打开数据库之前”。我使用HILT进行依赖注入,如何在Room打开数据库之前打开它?
  • @Mox4 如果您查看isEncryptedDatabase,它所需要的只是上下文和数据库名称。所以这就是你需要调用它的所有内容。所以在你得到数据库之前的任何地方。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-04
  • 1970-01-01
  • 2018-08-18
  • 1970-01-01
  • 2020-07-03
  • 2021-09-12
  • 2021-03-09
相关资源
最近更新 更多