The Basics of SQLCipher for Android
The ToDoCrypt
module of the book’s primary sample project contains its own edition of those classes, plus the whole to-do app UI that employs them. In addition, this app adds SQLCipher for Android, in case the user really wants to protect those to-do items.
Adding the Dependency
Zetetic maintains a standard Android AAR artifact, available in Maven Central and its mirrors (e.g., Bintray’s JCenter), using net.zetetic:android-database-sqlcipher
as the base Maven coordinates. So, ToDoCrypt
adds that library to the roster of libraries that it pulls in via the dependencies
closure in the module’s build.gradle
file:
implementation "net.zetetic:android-database-sqlcipher:4.4.2"
Creating and Applying the Factory
That gives us access to a SupportFactory
class. This is an implementation of SupportSQLiteHelper.Factory
and serves as the “glue” between SQLCipher for Android and clients like Room.
The simplest SupportFactory
constructor takes a byte[]
that represents the passphrase for the database. This will be used in two cases:
- If the database does not yet exist, SQLCipher for Android will create one, and this passphrase will be used for encrypting the database
- If the database does exist, SQLCipher for Android will try to open it using this passphrase to decrypt the database
How you get that byte[]
for the passphrase is up to you. In this sample, we take a very easy and very lousy approach: hardcoding it. So, we have a PASSPHRASE
constant and use that in the SupportFactory
constructor:
package com.commonsware.todo.repo
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import net.sqlcipher.database.SupportFactory
private const val DB_NAME = "stuff.db"
private const val PASSPHRASE = "sekr1t"
@Database(entities = [ToDoEntity::class], version = 1)
@TypeConverters(TypeTransmogrifier::class)
abstract class ToDoDatabase : RoomDatabase() {
abstract fun todoStore(): ToDoEntity.Store
companion object {
fun newInstance(context: Context) =
Room.databaseBuilder(context, ToDoDatabase::class.java, DB_NAME)
.openHelperFactory(SupportFactory(PASSPHRASE.toByteArray()))
.build()
}
}
We pass that SupportFactory
to openHelperFactory()
on our RoomDatabase.Builder
, and from there, Room will take over and integrate with SQLCipher for Android.
Using the Database
The beauty of the SupportSQLite*
family of APIs is that, for the most part, Room clients neither know nor care about the actual SQLite implementation. ToDoEntity
and ToDoEntity.Store
do not need anything special for SQLCipher for Android. Even ToDoDatabase
has just the change to add that one openHelperFactory()
call — nothing else is affected. ToDoRepository
and its clients (e.g., viewmodels) are also unaffected. So, everything that has been covered to date in the book just works, with the added improvement of encryption.
Using the Database… Outside the App
To work with a database encrypted by SQLCipher for Android, you will need a client that has SQLCipher compiled in. SQLCipher databases are portable across platforms, just as SQLite databases are, but plain SQLite clients will not know how to deal with SQLCipher’s encryption scheme. So, for example, neither Android Studio’s Database Inspector nor the sqlite3
binary that is part of Android itself will be able to work with SQLCipher for Android databases.
DB Browser for SQLite, however, does support SQLCipher.
Prev Table of Contents Next
This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.