0

I am trying to encrypt my SQLDelight database using SqlCipher. I've found one appropriate example on GitHub, however, it uses outdated cwac-saferoom which connects Room with SQLCipher for Android. The oudated library mentions to use SQLCipher for Android. So, taking into consideration the NoteDelight repository from the GitHub mentioned above and the SQLCipher Android documentation I tried implementing this approach. However, I cannot seem to understand how to make this work.

  1. I have followed SQLDelight documentation and implemented my .sq files under src/main/sqldelight as well added necessary imports.
  2. Under the commonMain package I have
expect val databaseModule: Module

val repositoriesModule = module {
    single { AddressRepository(get()) }
    // more repositories
}
class AddressRepository(private val database: Database) {

    fun insertAddress(address: Address) =
        database.addressQueries.insertAddress(
            // parameters
        )

    // more functions
}
  1. Now in androidMain I provide the actual implementation of databaseModule:
actual val databaseModule: Module = module {
    single<Database> { AndroidDatabase(get()) }
}
abstract class DatabaseQueries {
    abstract val addressQueries: AddressQueries
    // more queries
}

abstract class Database : DatabaseQueries() {
    abstract fun initializeDatabase(passphrase: CharSequence = ""): DatabaseHolder

    // encrypt, decrypt, repass and other abstract methods
}

class AndroidDatabase(private val context: Context) : Database() {
    private var databaseHolder: DatabaseHolder? = null

    override val addressQueries: AddressQueries
        get() = initializeDatabase("").addressQueries

    override fun initializeDatabase(passphrase: CharSequence): DatabaseHolder {
        var instance = databaseHolder

        if (instance == null) {
            instance = AndroidDatabaseHolder(context, SpannableStringBuilder(passphrase))
            databaseHolder = instance
        }

        return instance
    }

    // other methods that override abstract methods
}
  1. I implement my database holder class
abstract class DatabaseHolder : DatabaseQueries() {
    abstract val database: MyDatabase
    abstract val driver: SqlDriver
}


class AndroidDatabaseHolder(
    context: Context,
    passphrase: CharSequence
) : DatabaseHolder() {

    init {
        System.loadLibrary("sqlcipher")
    }

    private val encryptedDatabase = SQLiteDatabase.openOrCreateDatabase(
        context.getDatabasePath(DATABASE_NAME),
        passphrase.toString(),
        null
    )

    override val driver = AndroidSqliteDriver(encryptedDatabase)
    override val database: MyDatabase = createQueryWrapper(driver)

    override val addressQueries: AddressQueries = database.addressQueries
    // more overriden queries

    override fun close() {
        driver.close()
    }

}
  1. Util method
fun createQueryWrapper(driver: SqlDriver): MyDatabase {
    return MyDatabase(
        driver = driver,
        photoAdapter = /* My adapter */)
    )
}

I first open clean app and create the database using initializeDatabase with my provided password. Then in the login page I provide the password and the app calls the initializeDatabase method again. Then I get to the main page where all the repositories get all the records from the database. That's where the error occurs for each of the repository:

android.database.sqlite.SQLiteException: no such table: address: , while compiling: SELECT * FROM address

Is the approach I am following is correct to implement SqlCipher encryption together with SQLDelight for the best practices? Are there any examples I have missed for correct implementation? And how to fix my error? Thanks.

Captain Jacky
  • 888
  • 1
  • 12
  • 26

0 Answers0