【正社員】還元率83%【フリーランス】マージン一律5万円で案件をご紹介させていただきます。 詳細はこちら

【Android】<Kotlin>EncryptedSharedPreferencesやSQLCipherを活用して暗号化されたストレージを構築する方法

【Android】<Kotlin>EncryptedSharedPreferencesやSQLCipherを活用して暗号化されたストレージを構築する方法
すだ

みなさまこんにちは〜!
メモリアインクのすだです。

本日は、
KotlinのEncryptedSharedPreferencesやSQLCipherを使って
暗号化されたストレージを構築する方法を、
実際のコードを利用して徹底解説していきます!

この記事を読んでわかること…
・暗号化されたストレージとは?
・EncryptedSharedPreferencesを使った暗号化されたストレージを構築する方法
・SQLCipherを使った暗号化データベースを構築する方法

目次

環境

  • Kotlin (ver 1.9.0)
  • Android Studio (Giraffe | 2022.3.1 Patch 3)

暗号化されたストレージとは?

暗号化されたストレージとは、保存されるデータを暗号化することで、第三者からデータを保護する仕組みです。
これにより、万が一ストレージが漏洩してもデータが読み取られることはありませ

  • 用途
    • ユーザーの個人情報の保護。
    • パスワードやトークンなど、機密情報の安全な保存。
    • コンプライアンス(GDPR、HIPAAなど)の遵守。

EncryptedSharedPreferencesを使った暗号化

EncryptedSharedPreferencesは、Androidが提供する暗号化されたSharedPreferencesです。
データをファイル単位で暗号化して保存でき、簡単にセットアップできるのが特徴です。

EncryptedSharedPreferencesのセットアップ

EncryptedSharedPreferencesを使用するには、build.gradle ファイルに以下のように依存関係を追加します。

dependencies {
    implementation "androidx.security:security-crypto:1.1.0-alpha05"
}

セットアップが完了したら、早速実装していきましょう!

import android.content.Context
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKeys

fun getEncryptedSharedPreferences(context: Context): SharedPreferences {
    val masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)

    return EncryptedSharedPreferences.create(
        "secure_prefs", // ファイル名
        masterKeyAlias,
        context,
        EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
        EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
    )
}

// データの保存
fun saveData(context: Context, key: String, value: String) {
    val encryptedPrefs = getEncryptedSharedPreferences(context)
    encryptedPrefs.edit().putString(key, value).apply()
}
// データの取得
fun getData(context: Context, key: String): String? {
    val encryptedPrefs = getEncryptedSharedPreferences(context)
    return encryptedPrefs.getString(key, null)
}

6行目:

  • MasterKeys.getOrCreate
    • 暗号化キーを作成または取得します。
    • AES256_GCM_SPEC に基づく安全な暗号化キーを利用しています。

8行目:

  • EncryptedSharedPreferences.create
    • 暗号化されたSharedPreferencesを作成します。
    • キーと値の両方が暗号化されます。

18行目、23行目:

  • データの保存・取得
    • 通常のSharedPreferencesと同様に、putStringgetStringを使用できます。

SQLCipherを使った暗号化データベース

SQLCipherは、SQLiteデータベースを暗号化するライブラリで、データベース全体を暗号化し、高いセキュリティを提供します。
特に、大量のデータを扱う場合に最適です。

SQLCipherのセットアップ

SQLCipherを使用するには、build.gradle ファイルに以下のように依存関係を追加します。

dependencies {
    implementation 'net.zetetic:android-database-sqlcipher:4.5.3'
}

セットアップが完了したら、早速実装していきましょう!
まずは EncryptedDatabaseHelper クラスを定義していきます ▼

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

class EncryptedDatabaseHelper(context: Context) : SQLiteOpenHelper(
    context, "encrypted_database.db", null, 1
) {
    override fun onCreate(db: SQLiteDatabase) {
        db.execSQL("CREATE TABLE secure_table (id INTEGER PRIMARY KEY, data TEXT)")
    }

    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
        db.execSQL("DROP TABLE IF EXISTS secure_table")
        onCreate(db)
    }
}

fun getEncryptedDatabase(context: Context, password: String): SQLiteDatabase {
    SQLiteDatabase.loadLibs(context)
    return EncryptedDatabaseHelper(context).writableDatabase.apply {
        openOrCreateDatabase("encrypted_database.db", password, null)
    }
}

5〜16行目:

  • EncryptedDatabaseHelper クラス
    • SQLiteOpenHelperを継承したクラスで、データベースの作成やアップグレードの処理を定義しています。
    • onCreate: データベースが初めて作成されるときに呼び出されます。
      • この中でテーブル secure_table を作成するSQL文を実行します。▼
        • CREATE TABLE secure_table (id INTEGER PRIMARY KEY, data TEXT)
        • id は主キー、data はテキストデータを保存するためのカラムです。
    • onUpgrade: データベースのバージョンが更新されたときに呼び出されます。
      • 既存のテーブルを削除(DROP TABLE IF EXISTS)し、新しいテーブルを再作成する処理を行います。

18〜23行目:

  • getEncryptedDatabaseクラス
    • SQLCipherを使って暗号化されたデータベースを取得します。
    • SQLiteDatabase.loadLibs(context):SQLCipherのライブラリをロードし、暗号化・復号化の機能を使えるようにします。
    • openOrCreateDatabase:指定したパスワードを使ってデータベースを開きます。データベースが存在しない場合は新しく作成します。

apply ブロック内でデータベース操作を実行することで、暗号化された状態で処理が行われます。)

そして
データの追加や取得に関しては、以下のように実装してください。 ▼

// データの追加
fun insertData(context: Context, password: String, data: String) {
    val db = getEncryptedDatabase(context, password)
    db.execSQL("INSERT INTO secure_table (data) VALUES (?)", arrayOf(data))
    db.close()
}

// データの取得
fun getData(context: Context, password: String): List<String> {
    val db = getEncryptedDatabase(context, password)
    val cursor = db.rawQuery("SELECT data FROM secure_table", null)
    val results = mutableListOf<String>()
    while (cursor.moveToNext()) {
        results.add(cursor.getString(0))
    }
    cursor.close()
    db.close()
    return results
}

2〜6行目:

  • insertData 関数
    • 暗号化されたデータベースにデータを挿入します。
    • getEncryptedDatabase を使って暗号化されたデータベースを開き、execSQL メソッドでSQL文を実行し、データを挿入していきます。▼
      • db.execSQL("INSERT INTO secure_table (data) VALUES (?)", arrayOf(data))
      • ? はプレースホルダーで、arrayOf(data) で指定されたデータが埋め込まれます。
    • 挿入後にデータベースを閉じてください(db.close())。

9〜19行目:

  • getData 関数
    • 暗号化されたデータベースからデータを取得し、リスト形式で返します。
    • getEncryptedDatabase を使って暗号化されたデータベースを開き、rawQuery メソッドを使ってデータを取得していきます。▼
      • db.rawQuery("SELECT data FROM secure_table", null)
      • data カラムの全データを取得します。
    • 取得したデータをカーソル (Cursor) でループ処理してリストに追加、最後にデータベースを閉じてください。

選択のポイント:どちらを使うべきか

それぞれに以下の特徴がありますので、状況に応じて使い分けてください。

項目EncryptedSharedPreferencesSQLCipher
データ量少量のキーと値のペア大量のデータ
使いやすさ設定が簡単若干複雑
セキュリティAndroid標準の暗号化高い暗号化レベル
パフォーマンス小規模データでは高速データ量が多いとやや遅い

まとめ

おつかれさまでした。いかがでしたでしょうか!

どちらも用途に応じて選択し、アプリのセキュリティを強化するのに活用してください!

すだ

技術者としてのキャリアパスを次のレベルへと進めたい皆様、
未経験からIT・Webエンジニアを目指すなら【ユニゾンキャリア】
を通じて、
自分の市場価値をさらに向上させてみませんか?

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

弊社テックブログをご愛読いただきありがとうございます。
当テックブログを運用している株式会社メモリアインクは、
【正社員】還元率83%
【フリーランス】マージン一律5万円で案件のご紹介
と、エンジニアの皆様に分かりやすい形で稼げる仕組みを構築し提供させていただいております。

コメント

コメントする

目次