データをより安全に取り扱う

Android Jetpack の一部である Security ライブラリには、保存データの読み取りと書き込み、および鍵の作成と検証に関連するセキュリティに関するおすすめの方法の実装があります。

このライブラリでは、ビルダー パターンを使用して、次のセキュリティ レベルの安全なデフォルト設定を使用できます。

  • 高度な暗号化と優れたパフォーマンスを両立する強力なセキュリティ。 このセキュリティ レベルは、銀行アプリやチャットアプリなどの一般向けアプリ、証明書失効チェックを行う企業向けアプリに適しています。
  • 最高セキュリティ。 このセキュリティ レベルは、キーへのアクセスにハードウェア格納型キーストアとユーザー操作を必要とするアプリに適しています。

このガイドでは、セキュリティ ライブラリの推奨セキュリティ設定の利用方法と、ファイルに保存されている暗号化されたデータおよび共有設定を簡単かつ安全に読み書きする方法を説明します。

キーの管理

セキュリティ ライブラリは、キー管理に 2 部構成のシステムを使用します。

  • ファイルまたは共有設定データを暗号化するための 1 つ以上のキーを含むキーセット。キーセット自体は SharedPreferences に格納されます。

  • すべてのキーセットを暗号化するマスターキー。このキーは Android キーストア システムを使用して保存されます。

ライブラリに含まれるクラス

セキュリティ ライブラリに含まれる以下のクラスを使用すると、データをより安全に保存できます。

EncryptedFile

カスタム実装の FileInputStreamFileOutputStream を使って、アプリによるストリーミング読み取り操作とストリーミング書き込み操作のセキュリティを強化できます。

ファイル ストリームの安全な読み取り操作と書き込み操作を実現するため、セキュリティ ライブラリではストリーミング認証付き暗号(AEAD)プリミティブを使用します。このプリミティブの詳細は GitHub の Tink ライブラリのドキュメントをご覧ください。

EncryptedSharedPreferences

SharedPreferences クラスをラップし、2 スキーマ方式を使用してキーと値を自動的に暗号化します。

  • キーは、暗号化された状態でも検索できるように、決定性暗号化アルゴリズムを使用して暗号化されます。
  • は、AES-256 GCM を使用して暗号化されます。これは非決定性です。

以下のセクションでは、これらのクラスを使用して、ファイルおよび共有設定に一般的な操作を実行する方法を示します。

ファイルを読み取る

次のコード スニペットは、EncryptedFile を使用して、ファイルの内容をより安全な方法で読み取る方法を示しています。

Kotlin

    // Although you can define your own key generation parameter specification, it's
    // recommended that you use the value specified here.
    val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC
    val masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)

    val fileToRead = "my_sensitive_data.txt"
    lateinit var byteStream: ByteArrayOutputStream
    val encryptedFile = EncryptedFile.Builder(
        File(directory, fileToRead),
        context,
        masterKeyAlias,
        EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
    ).build()

    val contents = encryptedFile.bufferedReader().useLines { lines ->
        lines.fold("") { working, line ->
            "$working\n$line"
        }
    }
    

Java

    // Although you can define your own key generation parameter specification, it's
    // recommended that you use the value specified here.
    KeyGenParameterSpec keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC;
    String masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec);

    String fileToRead = "my_sensitive_data.txt";
    ByteArrayOutputStream byteStream;

    EncryptedFile encryptedFile = new EncryptedFile.Builder(
            File(directory, fileToRead),
            context,
            masterKeyAlias,
            EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
    ).build();

    StringBuffer stringBuffer = new StringBuffer();
    try (BufferedReader reader =
                 new BufferedReader(new FileReader(encryptedFile))) {

        String line = reader.readLine();
        while (line != null) {
            stringBuffer.append(line).append('\n');
            line = reader.readLine();
        }
    } catch (IOException e) {
        // Error occurred opening raw file for reading.
    } finally {
        String contents = stringBuffer.toString();
    }
    

ファイルを書き込む

次のコード スニペットは、EncryptedFile を使用して、ファイルの内容をより安全な方法で書き込む方法を示しています。

Kotlin

    // Although you can define your own key generation parameter specification, it's
    // recommended that you use the value specified here.
    val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC
    val masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)

    // Creates a file with this name, or replaces an existing file
    // that has the same name. Note that the file name cannot contain
    // path separators.
    val fileToWrite = "my_sensitive_data.txt"
    val encryptedFile = EncryptedFile.Builder(
        File(directory, fileToWrite),
        context,
        masterKeyAlias,
        EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
    ).build()

    encryptedFile.bufferedWriter().use { writer ->
        writer.write("MY SUPER-SECRET INFORMATION")
    }
    

Java

    // Although you can define your own key generation parameter specification, it's
    // recommended that you use the value specified here.
    KeyGenParameterSpec keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC;
    String masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec);

    // Creates a file with this name, or replaces an existing file
    // that has the same name. Note that the file name cannot contain
    // path separators.
    String fileToWrite = "my_sensitive_data.txt";
    try {
        EncryptedFile encryptedFile = new EncryptedFile.Builder(
                new File(directory, fileToWrite),
                context,
                masterKeyAlias,
                EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
        ).build();

        // Write to a file.
        BufferedWriter writer = new BufferedWriter(new FileWriter(encryptedFile));
        writer.write("MY SUPER-SECRET INFORMATION");
    } catch (GeneralSecurityException gse) {
        // Error occurred getting or creating keyset.
    } catch (IOException ex) {
        // Error occurred opening file for writing.
    }
    

さらに強化されたセキュリティが必要なユースケースでは、次の手順を実行します。

  1. KeyGenParameterSpec.Builder オブジェクトを作成して、truesetUserAuthenticationRequired() に、0 より大きな値を setUserAuthenticationValidityDurationSeconds() に渡します。
  2. createConfirmDeviceCredentialIntent() を使用して、認証情報の入力をユーザーに求めます。鍵を使用するためのユーザー認証を求める方法をご覧ください。

  3. onActivityResult() をオーバーライドして、確認済み認証情報のコールバックを取得します。

詳細については、鍵を使用するためのユーザー認証の要求をご覧ください。

共有設定を編集する

次のコード スニペットは、EncryptedSharedPreferences を使用して、ユーザーの共有設定のセットをより安全な方法で編集する方法を示しています。

Kotlin

    val sharedPreferences = EncryptedSharedPreferences
        .create(
        fileName,
        masterKeyAlias,
        context,
        EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
        EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
    )

    val sharedPrefsEditor = sharedPreferences.edit()
    

Java

    EncryptedSharedPreferences sharedPreferences = EncryptedSharedPreferences
            .create(
                    fileName,
                    masterKeyAlias,
                    context,
                    EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
                    EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
            );

    SharedPreferences.Editor sharedPrefsEditor = sharedPreferences.edit();