AndroidにSQLCipherを導入してみる

あけましておめでとうございます。
2018年最初の投稿です。

# なぜ今になってSQLCipherの導入？
この記事を書いてるのは2018年ですが、2016年末に担当しているプロジェクトでデータベースの暗号化を行うということでSQLCipherを導入しました。
SQLCipherは、ほんとに簡単に導入できて且つセキュリティ面の強化が行えるので、自分の作るアプリなどには標準装備させたいなと思っていました。

で、そう思っておきながら全然導入していなかったので、今回ようやく重たい腰を上げて導入するわけです。

しかし、導入したのが結構前で色々と忘れかけているのと、javaでなくkotlinで最近は書いているので、kotlin化したコードで導入したいと思ったため今回の記事を書いています。

# SQLCipherの導入
内容としてはかなり古い内容のため、他の記事もあるのでまずはその記事のリンクを貼っておきます。

CrunchTimerさんの佐々木さんが書いた記事です。
[[Android] 超簡単！DBを暗号化できるライブラリ”SQLCipher”の導入方法](https://www.crunchtimer.jp/blog/technology/android/3851/)

あともう一つ@tomichan_jp さんの記事。
[AndroidStudioでSQLiteを暗号化するSQLCipherを使う](https://qiita.com/tomichan_jp/items/6ee6733c50ad8b01ac88)

また、zentetic（SQLCipherの製造元会社）の公式リファレンスでも導入方法は書いてあります。
https://www.zetetic.net/sqlcipher/sqlcipher-for-android/

さて、上の記事の方々の記事を参考に、導入していきます。

導入に際してのステップです。
1. SQLCipherのライブラリを導入する
2. 暗号化キーを設定する
3. 実際に暗号化されているか確認する

では
## SQLCipherのライブラリの導入
ライブラリの導入は簡単です。
`https://www.zetetic.net/sqlcipher/sqlcipher-for-android/`
これをbuild.gradleに追加します。

```
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support:design:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    implementation 'com.android.support:support-vector-drawable:26.1.0'
    implementation 'com.android.support:support-v4:26.1.0'
    implementation 'com.google.android.gms:play-services-plus:11.8.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
    wearApp project(':wear')
    implementation 'com.google.android.gms:play-services-wearable:11.8.0'
    compile 'com.google.firebase:firebase-core:11.8.0'
    compile 'net.zetetic:android-database-sqlcipher:3.5.9@aar' ★ここに追加してみた
}
```

これで導入終わりです。

ただし、aarのライブラリファイルをlibs配下に置きたい場合もあると思うので、その方法についてはまた後日追記できそうなら追記します。
ひとまず、build.gradleのdependenciesに追加する方法で話を進めていきます。

導入が正常にできているかを、既に記述した標準のSQLiteを使用したコードを変更することで確認してみます。

### 大本のSQLiteOpenHelper継承クラス
```
package com.keiapp.birthdaycounter.database

import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteDatabase.CursorFactory
import android.database.sqlite.SQLiteException
import android.database.sqlite.SQLiteOpenHelper

class ExtendsSQLiteOpenHelper
(context : Context?, name : String?, factory : CursorFactory?, version : Int)
    : SQLiteOpenHelper(context, name, factory, version) {

    @Throws(Exception::class)
    override fun onCreate(database: SQLiteDatabase?) {
        database ?: throw SQLiteException()
        try {
            database.execSQL("CREATE TABLE users ( userid INTEGER  PRIMARY KEY, username TEXT )")
        } catch (e : SQLiteException) {
            throw e
        }
    }

    override fun onUpgrade(p0: SQLiteDatabase?, p1: Int, p2: Int) {
    }
}
```

importを変えてみます。

```
package com.keiapp.birthdaycounter.database

import android.content.Context
import net.sqlcipher.database.SQLiteDatabase
import net.sqlcipher.database.SQLiteDatabase.CursorFactory
import net.sqlcipher.database.SQLiteException
import net.sqlcipher.database.SQLiteOpenHelper

class ExtendsSQLiteOpenHelper
(context : Context?, name : String?, factory : CursorFactory?, version : Int)
    : SQLiteOpenHelper(context, name, factory, version) {

    @Throws(Exception::class)
    override fun onCreate(database: SQLiteDatabase?) {
        database ?: throw SQLiteException()
        try {
            database.execSQL("CREATE TABLE users ( userid INTEGER  PRIMARY KEY, username TEXT )")
        } catch (e : SQLiteException) {
            throw e
        }
    }

    override fun onUpgrade(p0: SQLiteDatabase?, p1: Int, p2: Int) {
    }
}
```

これで導入完了です。

次に、データベースにアクセスするためのキーの設定が必要になってきます。

## 暗号化キーを設定する
暗号化キーの作成については、zentetic社の導入方法をそのまま持ってきて大丈夫です。

コードはjavaで書いてありますが、ほとんどkotlinで書いても変わりません。
以下のように導入します。

```
class MainApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        initializeSQLCipher()
    }

    private fun initializeSQLCipher() {
        SQLiteDatabase.loadLibs(this)
        val databaseFile = getDatabasePath("demo.db")
        databaseFile.mkdirs()
        databaseFile.delete()
        val database = SQLiteDatabase.openOrCreateDatabase(databaseFile, "test123", null)
        database.execSQL("create table t1(a, b)")
        database.execSQL("insert into t1(a, b) values(?, ?)", arrayOf<Any>("one for the money", "two for the show"))
　　　　　　　　　　　　　　　　database.close
    }
}
```

これで`test123`をキーにした暗号化したデータベースが作成できました。

## 実際に暗号化されているか確認する。
現在確認中です。
run-asコマンドでデータベースをローカルに引っ張ってくる方法が有名（実際に現場ではrun-asコマンドでやってます）ですが、Android8.0からrun-asだとpermissionエラーが起きてしまうので、できません。

なので、別の方法で確認するので結果はまた後日追記します。

# ちなみに
この記事を書いている最終目標としては、Android Architecture ComponentsのRoomを使ったデータベース周りの設計パターンを実際に実装してみたかったので、それをメインにやりたい。
というより、Android Architecture ComponentsとSQLCipherを同時に導入することが可能なのかを確認したかったので、それが可能かを確認するまでが僕のやりたいことの最終目標です。

今回はとりあえずSQLCipherの導入のみ書いてますが、念のため補足です。