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

  Android Jetpack の一部

セキュリティ ライブラリでは、保存データの読み取りと書き込みに加え、キーの作成と検証に関連するセキュリティに関するおすすめの方法の実装が提供されます。

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

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

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

キーの管理

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

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

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

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

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

EncryptedFile

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

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

EncryptedSharedPreferences

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

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

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

プロジェクトにライブラリを組み込む

セキュリティ ライブラリを使用するには、必要に応じて、アプリ モジュールの build.gradle ファイルに次の依存関係を追加します。

Groovy

dependencies {
    implementation "androidx.security:security-crypto:1.0.0"

    // For Identity Credential APIs
    implementation "androidx.security:security-identity-credential:1.0.0-alpha03"

     // For App Authentication APIs
    implementation "androidx.security:security-app-authenticator:1.0.0-alpha02"

    // For App Authentication API testing
    androidTestImplementation "androidx.security:security-app-authenticator:1.0.0-alpha01"
}

Kotlin

dependencies {
    implementation("androidx.security:security-crypto:1.0.0")

    // For Identity Credential APIs
    implementation("androidx.security:security-identity-credential:1.0.0-alpha03")

    // For App Authentication APIs
    implementation("androidx.security:security-app-authenticator:1.0.0-alpha02")

    // For App Authentication API testing
    androidTestImplementation("androidx.security:security-app-authenticator:1.0.0-alpha01")

}

ファイルを読み取る

次のコード スニペットは、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 mainKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)

val fileToRead = "my_sensitive_data.txt"
val encryptedFile = EncryptedFile.Builder(
    File(DIRECTORY, fileToRead),
    applicationContext,
    mainKeyAlias,
    EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build()

val inputStream = encryptedFile.openFileInput()
val byteArrayOutputStream = ByteArrayOutputStream()
var nextByte: Int = inputStream.read()
while (nextByte != -1) {
    byteArrayOutputStream.write(nextByte)
    nextByte = inputStream.read()
}

val plaintext: ByteArray = byteArrayOutputStream.toByteArray()

Java

Context context = getApplicationContext();

// 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 mainKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec);

String fileToRead = "my_sensitive_data.txt";
EncryptedFile encryptedFile = new EncryptedFile.Builder(
        new File(DIRECTORY, fileToRead),
        context,
        mainKeyAlias,
        EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build();

InputStream inputStream = encryptedFile.openFileInput();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int nextByte = inputStream.read();
while (nextByte != -1) {
    byteArrayOutputStream.write(nextByte);
    nextByte = inputStream.read();
}

byte[] plaintext = byteArrayOutputStream.toByteArray();

ファイルを書き込む

次のコード スニペットは、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 mainKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)

// Create a file with this name or replace an entire existing file
// that has the same name. Note that you cannot append to an existing file,
// and the filename cannot contain path separators.
val fileToWrite = "my_sensitive_data.txt"
val encryptedFile = EncryptedFile.Builder(
    File(DIRECTORY, fileToWrite),
    applicationContext,
    mainKeyAlias,
    EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build()

val fileContent = "MY SUPER-SECRET INFORMATION"
        .toByteArray(StandardCharsets.UTF_8)
encryptedFile.openFileOutput().apply {
    write(fileContent)
    flush()
    close()
}

Java

Context context = getApplicationContext();

// 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 mainKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec);

// Create a file with this name or replace an entire existing file
// that has the same name. Note that you cannot append to an existing file,
// and the filename cannot contain path separators.
String fileToWrite = "my_sensitive_data.txt";
EncryptedFile encryptedFile = new EncryptedFile.Builder(
        new File(DIRECTORY, fileToWrite),
        context,
        mainKeyAlias,
        EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build();

byte[] fileContent = "MY SUPER-SECRET INFORMATION"
        .getBytes(StandardCharsets.UTF_8);
OutputStream outputStream = encryptedFile.openFileOutput();
outputStream.write(fileContent);
outputStream.flush();
outputStream.close();

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

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

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

共有設定を編集する

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

Kotlin

val sharedPrefsFile: String = FILE_NAME
val sharedPreferences: SharedPreferences = EncryptedSharedPreferences.create(
        sharedPrefsFile,
        mainKeyAlias,
        applicationContext,
        EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
        EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)

with (sharedPreferences.edit()) {
    // Edit the user's shared preferences...
    apply()
}

Java

String sharedPrefsFile = FILE_NAME;
SharedPreferences sharedPreferences = EncryptedSharedPreferences.create(
        sharedPrefsFile,
        mainKeyAlias,
        getApplicationContext(),
        EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
        EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
);

SharedPreferences.Editor sharedPrefsEditor = sharedPreferences.edit();
// Edit the user's shared preferences...
sharedPrefsEditor.apply();

Android 5.0 デバイスと Android 5.1 デバイスをサポートする

セキュリティ ライブラリのバージョン 1.1.0 では、Android 5.0(API レベル 21)以降を搭載しているデバイスをサポートできます。Android 5.0 と Android 5.1(API レベル 22)では、Android キーストアを使用してキーセットを保存することはできません。

ファイルを読み取る

次のコード スニペットは、EncryptedFile を使用して、セキュリティ ライブラリのバージョン 1.1.0 でファイルの内容を読み取る方法を示しています。

Kotlin

val mainKey = MasterKey.Builder(applicationContext)
        .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
        .build()

val fileToRead = "my_sensitive_data.txt"
val encryptedFile = EncryptedFile.Builder(applicationContext,
        File(DIRECTORY, fileToRead),
        mainKey,
        EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build()

val inputStream = encryptedFile.openFileInput()
val byteArrayOutputStream = ByteArrayOutputStream()
var nextByte: Int = inputStream.read()
while (nextByte != -1) {
    byteArrayOutputStream.write(nextByte)
    nextByte = inputStream.read()
}

val plaintext: ByteArray = byteArrayOutputStream.toByteArray()

Java

Context context = getApplicationContext();
MasterKey mainKey = new MasterKey.Builder(context)
        .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
        .build();

String fileToRead = "my_sensitive_data.txt";
EncryptedFile encryptedFile = new EncryptedFile.Builder(context,
        new File(DIRECTORY, fileToRead),
        mainKey,
        EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build();

InputStream inputStream = encryptedFile.openFileInput();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int nextByte = inputStream.read();
while (nextByte != -1) {
    byteArrayOutputStream.write(nextByte);
    nextByte = inputStream.read();
}

byte[] plaintext = byteArrayOutputStream.toByteArray();

ファイルを書き込む

次のコード スニペットは、EncryptedFile を使用して、セキュリティ ライブラリのバージョン 1.1.0 でファイルの内容を書き込む方法を示しています。

Kotlin

val mainKey = MasterKey.Builder(applicationContext)
        .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
        .build()

// 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 = File(DIRECTORY, "my_sensitive_data.txt")
val encryptedFile = EncryptedFile.Builder(applicationContext,
        fileToWrite,
        mainKey,
        EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build()

// File cannot exist before using openFileOutput
if (fileToWrite.exists()) {
    fileToWrite.delete()
}

val fileContent = "MY SUPER-SECRET INFORMATION"
        .toByteArray(StandardCharsets.UTF_8))
encryptedFile.openFileOutput().apply {
    write(fileContent)
    flush()
    close()
}

Java

Context context = getApplicationContext();
MasterKey mainKey = new MasterKey.Builder(context)
        .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
        .build();

// 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.
File fileToWrite = new File(DIRECTORY, "my_sensitive_data.txt");
EncryptedFile encryptedFile = new EncryptedFile.Builder(context,
        fileToWrite,
        mainKey,
        EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build();

// File cannot exist before using openFileOutput
if (fileToWrite.exists()) {
    fileToWrite.delete();
}

byte[] fileContent = "MY SUPER-SECRET INFORMATION"
        .getBytes(StandardCharsets.UTF_8);
OutputStream outputStream = encryptedFile.openFileOutput();
outputStream.write(fileContent);
outputStream.flush();
outputStream.close();

共有設定を編集する

次のコード スニペットは、EncryptedSharedPreferences を使用して、セキュリティ ライブラリのバージョン 1.1.0 でユーザーの共有設定のセットを編集する方法を示しています。

Kotlin

val context = applicationContext
val mainKey = MasterKey.Builder(applicationContext)
        .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
        .build()

val sharedPreferences = EncryptedSharedPreferences.create(
    applicationContext,
    FILE_NAME,
    mainKey,
    EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
    EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)

with (sharedPreferences.edit()) {
    // Edit the user's shared preferences...
    apply()
}

Java

Context context = getApplicationContext();
MasterKey mainKey = new MasterKey.Builder(context)
        .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
        .build();

SharedPreferences sharedPreferences = EncryptedSharedPreferences
        .create(
            context,
            FILE_NAME,
            mainKey,
            EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
            EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
        );

SharedPreferences.Editor sharedPrefsEditor = sharedPreferences.edit();
// Edit the user's shared preferences...
sharedPrefsEditor.apply();