Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Jetpack Security

Jetpack Security

Shibuya.apk #35発表資料
Google I/O 2019にてJetpack Securityという新しいライブラリが発表されました。
なぜ必要だったか、そしてどれだけ簡単に使うことができるのかについてまとめました。

Takaki Hoshikawa

June 28, 2019
Tweet

More Decks by Takaki Hoshikawa

Other Decks in Programming

Transcript

  1. Jetpack Security
    エムスリー株式会社 星川貴樹 (@oboenikui)
    Shibuya.apk #35

    View Slide

  2. Jetpack Security (androidx-security)
    ● Google I/O 2019で発表された暗号系ライブラリ
    ● 暗号化処理のベストプラクティスを実装しており、高い安全性かつ高
    速な処理を実現
    ● Android 6.0+ で利用可能
    ● 利用技術
    ○ Android Keystore
    ○ Tink (Google製の暗号ライブラリ)
    https://developer.android.com/jetpack/androidx/releases/security

    View Slide

  3. 登場背景 (想像)
    ● Android Keystoreや暗号系の機能の敷居が高いという問題
    ● ボイラープレートも多い
    ● Android Keystoreが本格的に使えるようになったAndroid 6.0
    をminSdkVersionにするアプリが増えてくる頃だから?

    View Slide

  4. 暗号系機能の敷居が高い問題
    Android Keystoreの説明が最初の説明からちょっと分かりづらい
    Android Keystore システムを使用すると、コンテナに暗号化キー
    を格納し、デバイスからのキーの抽出をより困難にすることができま
    す。キーストアに格納したキーは、エクスポート不可のキーマテリアル
    を使った暗号化処理に使用できます。
    https://developer.android.com/training/articles/keystore より引用

    View Slide

  5. 暗号系機能の敷居が高い問題
    Android Keystoreの説明が最初の説明からちょっと分かりづらい
    Android Keystore システムを使用すると、コンテナに暗号化キー
    を格納し、デバイスからのキーの抽出をより困難にすることができま
    す。キーストアに格納したキーは、エクスポート不可のキーマテリアル
    を使った暗号化処理に使用できます。
    キー? キーマテリアル?
    https://developer.android.com/training/articles/keystore より引用

    View Slide

  6. 暗号系機能の敷居が高い問題
    ボイラープレート長い、設定項目もよくわからない
    val kpg: KeyPairGenerator = KeyPairGenerator.getInstance(
    KeyProperties.KEY_ALGORITHM_EC,
    "AndroidKeyStore"
    )
    val parameterSpec: KeyGenParameterSpec = KeyGenParameterSpec.Builder(
    alias,
    KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY
    ).run {
    setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
    build()
    }
    kpg.initialize(parameterSpec)
    val kp = kpg.generateKeyPair()
    https://developer.android.com/training/articles/keystore より引用
    ECの鍵生成だけで
    この長さ

    View Slide

  7. 暗号系機能の敷居が高い問題
    アルゴリズムの選択肢が多すぎてどれ選べばよいかわからない問題

    View Slide

  8. 暗号系機能の敷居が高い問題
    アルゴリズムの選択肢が多すぎてどれ選べばよいかわからない問題

    View Slide

  9. 暗号系機能の敷居が高い問題
    アルゴリズムの選択肢が多すぎてどれ選べばよいかわからない問題

    View Slide

  10. 暗号系機能の敷居が高い問題
    アルゴリズムの選択肢が多すぎてどれ選べばよいかわからない問題

    View Slide

  11. 暗号系機能の敷居が高い問題
    アルゴリズムの選択肢が多すぎ

    View Slide

  12. 暗号系機能の敷居が高い問題
    アルゴリズムの選択肢が多すぎ

    View Slide

  13. 暗号系機能の敷居が高い問題
    アルゴリズムの選択肢が多すぎ

    View Slide

  14. 暗号系機能の敷居が高い問題
    アルゴリズムの選択肢が多すぎ

    View Slide

  15. 暗号系機能の敷居が高い問題
    アルゴリズムの選択肢が多すぎ
    https://developer.android.com/training/articles/keystore#SupportedCiphers より

    View Slide

  16. Jetpack Securityで何が変わる?
    ● 使うだけならAndroid Keystoreなどの事情を知る必要がない
    ● 利用用途を限ることでシンプルに
    ○ ファイルや設定の暗号化・復号の処理を短く書ける
    ○ 暗号アルゴリズムの選択肢が今のところ1つだけなので困らない

    View Slide

  17. 使い方 - build.gradle
    dependencies {
    def security_version = "1.0.0-alpha02"
    implementation "androidx.security:security-crypto:$security_version"
    }

    View Slide

  18. 使い方 - キーの生成
    val masterKeyAlias =
    MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)

    View Slide

  19. 使い方 - キーの生成
    val masterKeyAlias =
    MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
    推奨される設定が定数化されている &
    現バージョンでは他の選択肢がないので、迷わない

    View Slide

  20. 使い方 - ファイル暗号化
    val encryptedFile = EncryptedFile.Builder(
    File(path), context, masterKeyAlias,
    EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
    ).build()
    val result = runCatching {
    encryptedFile.openFileOutput().use {
    it.write(text.toByteArray(Charset.forName("UTF-8")))
    it.flush()
    }
    }

    View Slide

  21. 使い方 - ファイル暗号化
    val encryptedFile = EncryptedFile.Builder(
    File(path), context, masterKeyAlias,
    EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
    ).build()
    val result = runCatching {
    encryptedFile.openFileOutput().use {
    it.write(text.toByteArray(Charset.forName("UTF-8")))
    it.flush()
    }
    }
    先程生成したキー
    のエイリアス

    View Slide

  22. 使い方 - ファイル暗号化
    val encryptedFile = EncryptedFile.Builder(
    File(path), context, masterKeyAlias,
    EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
    ).build()
    val result = runCatching {
    encryptedFile.openFileOutput().use {
    it.write(text.toByteArray(Charset.forName("UTF-8")))
    it.flush()
    }
    }
    同じく選択肢はこれしか用意されていない

    View Slide

  23. 使い方 - ファイル暗号化
    val encryptedFile = EncryptedFile.Builder(
    File(path), context, masterKeyAlias,
    EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
    ).build()
    val result = runCatching {
    encryptedFile.openFileOutput().use {
    it.write(text.toByteArray(Charset.forName("UTF-8")))
    it.flush()
    }
    }
    通常のファイル読み書きと
    ほぼ同じ記述で書ける

    View Slide

  24. 使い方 - ファイル復号
    val encryptedFile = EncryptedFile.Builder(
    File(path), context, masterKeyAlias,
    EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
    ).build()
    val result = runCatching {
    encryptedFile.openFileInput().use {
    it.bufferedReader().readText()
    }
    }

    View Slide

  25. 使い方 - SharedPreference
    val pref: SharedPreference =
    EncryptedSharedPreferences.create(
    "pref_file_name",
    MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC),
    context,
    EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
    EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
    )

    View Slide

  26. 使い方 - SharedPreference
    val pref: SharedPreference =
    EncryptedSharedPreferences.create(
    "pref_file_name",
    MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC),
    context,
    EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
    EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
    )
    いつものSharedPreferenceインターフェースを
    実装しているのであとは普段どおり使える

    View Slide

  27. 暗号化されたPreference XML


    AV1M1P7NgVsTKwwfb4nesoj+Brz...
    12a901ba5467eb84...
    1288012427b544ed...

    View Slide

  28. 暗号化されたPreference XML


    AV1M1P7NgVsTKwwfb4nesoj+Brz...
    12a901ba5467eb84...
    1288012427b544ed...

    Preferenceのkey, valueそれぞれを暗号化
    するための共通鍵を更に暗号化したもの

    View Slide

  29. 暗号化されたPreference XML


    AV1M1P7NgVsTKwwfb4nesoj+Brz...
    12a901ba5467eb84...
    1288012427b544ed...

    key: foo, value: bar
    が暗号化されたもの

    View Slide

  30. 今のところサポートしていないこと
    ● SQLiteなど、その他のデータ暗号化
    ● カスタマイズした認証(指紋認証など)画面

    View Slide

  31. 注意点
    ● 自動バックアップを許可していると、他の端末でデータの不整合が起
    きる
    ○ バックアップ除外設定をする必要あり
    ● 将来的に推奨アルゴリズムが変更されるかも
    ○ より強固なものへ「世代交代」していくんじゃないかと予想
    ○ その際はマイグレーション処理が必要
    ● まだ alpha02 なのでAPIが変わる可能性は高い

    View Slide

  32. 補足 - で、Android Keystoreって何?
    A. 暗号化・復号の処理をAndroidシステムに代行してもらう仕組み
    鍵のデータはAndroidシステムのプロセス以外からは参照できないようになって
    いる。
    そのためアプリプロセス上で暗号化・復号処理はできないが、代わりにシステム
    プロセス上で暗号化・復号の処理を行ってくれる。
    プロセス間通信が行われるので、多分速くはない。

    View Slide

  33. 補足 - なぜ高速?
    A. プロセス間通信を最小限に留めているから (多分)
    Android Keystoreで暗号化・復号する場合プロセス間通信となるため少し遅
    くなる。
    Jetpack Securityでは、直接ファイルをKeystoreで暗号化するのではなく、
    別のAESキーを生成して暗号化や復号を行う。
    そのキーをKeystoreで暗号化し、SharedPreferenceに保存している。

    View Slide

  34. 補足 - Tinkとは?
    A. 多言語 & クロスプラットフォームな暗号ライブラリ
    Java & Android, C++, Obj-C対応
    Go, JavaScript向けに開発中
    https://github.com/google/tink

    View Slide