Jetpack Security

Jetpack Security

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

A87027204ff57be1dadbf36a78a73c1b?s=128

Takaki Hoshikawa

June 28, 2019
Tweet

Transcript

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

  2. Jetpack Security (androidx-security) • Google I/O 2019で発表された暗号系ライブラリ • 暗号化処理のベストプラクティスを実装しており、高い安全性かつ高 速な処理を実現

    • Android 6.0+ で利用可能 • 利用技術 ◦ Android Keystore ◦ Tink (Google製の暗号ライブラリ) https://developer.android.com/jetpack/androidx/releases/security
  3. 登場背景 (想像) • Android Keystoreや暗号系の機能の敷居が高いという問題 • ボイラープレートも多い • Android Keystoreが本格的に使えるようになったAndroid

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

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

    キーマテリアル? https://developer.android.com/training/articles/keystore より引用
  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の鍵生成だけで この長さ
  7. 暗号系機能の敷居が高い問題 アルゴリズムの選択肢が多すぎてどれ選べばよいかわからない問題

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

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

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

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

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

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

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

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

  16. Jetpack Securityで何が変わる? • 使うだけならAndroid Keystoreなどの事情を知る必要がない • 利用用途を限ることでシンプルに ◦ ファイルや設定の暗号化・復号の処理を短く書ける ◦

    暗号アルゴリズムの選択肢が今のところ1つだけなので困らない
  17. 使い方 - build.gradle dependencies { def security_version = "1.0.0-alpha02" implementation

    "androidx.security:security-crypto:$security_version" }
  18. 使い方 - キーの生成 val masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)

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

  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() } }
  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() } } 先程生成したキー のエイリアス
  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() } } 同じく選択肢はこれしか用意されていない
  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() } } 通常のファイル読み書きと ほぼ同じ記述で書ける
  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() } }
  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 )
  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インターフェースを 実装しているのであとは普段どおり使える
  27. 暗号化されたPreference XML <?xml version='1.0' encoding='utf-8' standalone='yes' ?> <map> <string name="AVh0wrPyiwYcYEfSJpVUvVTuXJcoRf/B">AV1M1P7NgVsTKwwfb4nesoj+Brz...</string>

    <string name="__androidx_security_crypto_encrypted_prefs_key_keyset__">12a901ba5467eb84...</string> <string name="__androidx_security_crypto_encrypted_prefs_value_keyset__">1288012427b544ed...</string> </map>
  28. 暗号化されたPreference XML <?xml version='1.0' encoding='utf-8' standalone='yes' ?> <map> <string name="AVh0wrPyiwYcYEfSJpVUvVTuXJcoRf/B">AV1M1P7NgVsTKwwfb4nesoj+Brz...</string>

    <string name="__androidx_security_crypto_encrypted_prefs_key_keyset__">12a901ba5467eb84...</string> <string name="__androidx_security_crypto_encrypted_prefs_value_keyset__">1288012427b544ed...</string> </map> Preferenceのkey, valueそれぞれを暗号化 するための共通鍵を更に暗号化したもの
  29. 暗号化されたPreference XML <?xml version='1.0' encoding='utf-8' standalone='yes' ?> <map> <string name="AVh0wrPyiwYcYEfSJpVUvVTuXJcoRf/B">AV1M1P7NgVsTKwwfb4nesoj+Brz...</string>

    <string name="__androidx_security_crypto_encrypted_prefs_key_keyset__">12a901ba5467eb84...</string> <string name="__androidx_security_crypto_encrypted_prefs_value_keyset__">1288012427b544ed...</string> </map> key: foo, value: bar が暗号化されたもの
  30. 今のところサポートしていないこと • SQLiteなど、その他のデータ暗号化 • カスタマイズした認証(指紋認証など)画面

  31. 注意点 • 自動バックアップを許可していると、他の端末でデータの不整合が起 きる ◦ バックアップ除外設定をする必要あり • 将来的に推奨アルゴリズムが変更されるかも ◦ より強固なものへ「世代交代」していくんじゃないかと予想

    ◦ その際はマイグレーション処理が必要 • まだ alpha02 なのでAPIが変わる可能性は高い
  32. 補足 - で、Android Keystoreって何? A. 暗号化・復号の処理をAndroidシステムに代行してもらう仕組み 鍵のデータはAndroidシステムのプロセス以外からは参照できないようになって いる。 そのためアプリプロセス上で暗号化・復号処理はできないが、代わりにシステム プロセス上で暗号化・復号の処理を行ってくれる。

    プロセス間通信が行われるので、多分速くはない。
  33. 補足 - なぜ高速? A. プロセス間通信を最小限に留めているから (多分) Android Keystoreで暗号化・復号する場合プロセス間通信となるため少し遅 くなる。 Jetpack

    Securityでは、直接ファイルをKeystoreで暗号化するのではなく、 別のAESキーを生成して暗号化や復号を行う。 そのキーをKeystoreで暗号化し、SharedPreferenceに保存している。
  34. 補足 - Tinkとは? A. 多言語 & クロスプラットフォームな暗号ライブラリ Java & Android,

    C++, Obj-C対応 Go, JavaScript向けに開発中 https://github.com/google/tink