本文章將介紹如何在 Android 中使用 Room 和 SQLCipher 來加密資料庫。
Table of Contents
SQLCipher
SQLCipher 是一個可以用密碼加密 SQLite 資料庫的套件。
與 Room 一起使用
SQLCipher 與 Room 的整合相當地好。我們可以很輕易地將它整合到我們的 Android 專案中。如果你不熟悉 Room 的話,請先參照以下文章。
首先,我們要引入 SQLCipher 的 dependency。
dependencies { def sqlcipher_version = "4.5.0" implementation "net.zetetic:android-database-sqlcipher:$sqlcipher_version" }
修改 EmpolyeeDatabase.getInstance()
,讓它可以多接收一個密碼參數。由於 SupportFactory 只接收 ByteArray,所以我們要先將參數 password
轉換成 CharArray。然後再用 SQLiteDatabase.getBytes()
來將 CharArray 轉換成合適的 ByteArray。
import net.sqlcipher.database.SQLiteDatabase import net.sqlcipher.database.SupportFactory @Database(entities = [Employee::class], version = 1) @TypeConverters(Converters::class) abstract class EmployeeDatabase : RoomDatabase() { abstract fun dao(): EmployeeDao companion object { @Volatile private var INSTANCE: EmployeeDatabase? = null fun getInstance(context: Context, path: String, password: String): EmployeeDatabase { return INSTANCE ?: synchronized(this) { val supportFactory = SupportFactory(SQLiteDatabase.getBytes(password.toCharArray())) val instance = Room.databaseBuilder( context.applicationContext, EmployeeDatabase::class.java, path, ) .openHelperFactory(supportFactory) .build() INSTANCE = instance instance } } } }
最後在 EmployeeListViewModel 裡,我們設定密碼為 1234。這樣就完成了!
class EmployeeListViewModel : ViewModel() { private lateinit var database: EmployeeDatabase fun initDatabase(context: Context) { val path = context.getDatabasePath("employee") database = EmployeeDatabase.getInstance(context, path.absolutePath, "1234") } }
在命令列上存取加密的資料庫
因為除錯的需求,有時候我們可能會想要查看加密的資料庫裡面有哪些資料。SQLCipher 也有提供 command line 的方式來存取資料庫。所以,首先我們要先安裝 SQLCipher 的指令。你可以從這裡下載原始碼,然後編譯並且安裝。如果你的系統是 MacOS 的話,我們可以利用 Homebrew 來安裝,如下。
% brew install sqlcipher
接下來,在 Device File Explorer 中,下載資料庫檔案。記得那三個檔案都要一起下載下來。然後用以下的指令來開啟資料庫,並且輸入密碼,就可以存取資料庫裡的資料了。
% ls employee employee-shm employee-wal % sqlcipher employee SQLite version 3.37.2 2022-01-06 13:25:41 (SQLCipher 4.5.1 community) Enter ".help" for usage hints. sqlite> PRAGMA key = "1234"; ok sqlite> .tables employees room_master_table sqlite> select * from employees; David|FULL_TIME|1649824497125|1 Wayne|FULL_TIME|1649824502095|2 Peter|FULL_TIME|1649824509877|3 sqlite>.quit %
結語
Room 搭配 SQLCipher 使用,可以增加資料的安全性。