Travailler avec des données de manière plus sécurisée Fait partie d'Android Jetpack.
La bibliothèque de sécurité implémente les bonnes pratiques de sécurité liées à la lecture et à l'écriture de données au repos, ainsi qu'à la création et à la vérification des clés.
La bibliothèque utilise le modèle de compilateur pour fournir des paramètres par défaut sécurisés pour les niveaux de sécurité suivants :
- Une sécurité renforcée qui assure un juste équilibre entre un chiffrement élevé et de bonnes performances. Ce niveau de sécurité convient aux applications grand public telles que les applications bancaires et de chat, ainsi qu'aux applications d'entreprise qui vérifient la révocation des certificats.
- Sécurité maximale. Ce niveau de sécurité convient aux applications qui nécessitent un keystore intégré au matériel et la présence de l'utilisateur pour fournir l'accès aux clés.
Ce guide explique comment utiliser les configurations de sécurité recommandées de la bibliothèque de sécurité, et comment lire et écrire des données chiffrées stockées dans des fichiers et des préférences partagées.
Gestion des clés
La bibliothèque de sécurité utilise un système en deux parties pour gérer les clés :
-
Un ensemble de clés contenant une ou plusieurs clés pour chiffrer un fichier ou des données de préférences partagées. L'ensemble de clés est stocké dans
SharedPreferences
. -
Une clé (
master
) primaire qui chiffre tous les ensembles de clés. Cette clé est stockée à l'aide du système de keystore Android.
Classes incluses dans la bibliothèque
La bibliothèque de sécurité contient les classes suivantes pour fournir des données au repos plus sécurisées :
EncryptedFile
-
Fournit des implémentations personnalisées de
FileInputStream
etFileOutputStream
, ce qui permet à votre application d'effectuer des opérations de lecture et d'écriture en flux continu plus sécurisées.Pour fournir des opérations de lecture et d'écriture sécurisées à partir de flux de fichiers, la bibliothèque de sécurité utilise la primitive Streaming Authenticated Encryption with Associated Data (AEAD). Pour en savoir plus sur cette primitive, consultez la documentation de la bibliothèque Tink sur GitHub.
EncryptedSharedPreferences
-
Encapsule la classe
SharedPreferences
, et chiffre automatiquement les clés et les valeurs à l'aide d'une méthode à deux schémas :- Les clés sont chiffrées à l'aide d'un algorithme déterministe de sorte qu'elles puissent être chiffrées et correctement recherchées.
- Les valeurs sont chiffrées à l'aide de la norme AES-256 GCM et ne sont pas déterministes.
Les sections suivantes expliquent comment utiliser ces classes pour effectuer des opérations courantes avec les fichiers et les préférences partagées.
Inclure la bibliothèque dans votre projet
Pour utiliser la bibliothèque de sécurité, ajoutez les dépendances suivantes, selon vos besoins, au fichier build.gradle
de votre module d'application :
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") }
Lecture de fichiers
L'extrait de code suivant montre comment utiliser EncryptedFile
pour lire le contenu d'un fichier :
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();
Écrire des fichiers
L'extrait de code suivant montre comment utiliser EncryptedFile
pour écrire le contenu d'un fichier :
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();
Pour les cas d'utilisation nécessitant une sécurité supplémentaire, procédez comme suit :
- Créez un objet
KeyGenParameterSpec.Builder
, en transmettanttrue
danssetUserAuthenticationRequired()
et une valeur supérieure à 0 comme premier argument desetUserAuthenticationParameters()
. Invitez l'utilisateur à saisir des identifiants à l'aide de
createConfirmDeviceCredentialIntent()
. Découvrez comment demander l'authentification de l'utilisateur pour utiliser des clés.Ignorez
onActivityResult()
pour obtenir le rappel d'identifiant confirmé.
Modifier les préférences partagées
L'extrait de code suivant montre comment utiliser EncryptedSharedPreferences
pour modifier les préférences partagées d'un utilisateur :
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();
Prendre en charge les appareils Android 5.0 et Android 5.1
La version 1.1.0 de la bibliothèque de sécurité vous permet de prendre en charge les appareils exécutant Android 5.0 (niveau d'API 21) ou version ultérieure. Sur Android 5.0 et Android 5.1 (niveau d'API 22), vous ne pouvez pas utiliser le keystore Android pour stocker des ensembles de clés.
Lecture de fichiers
L'extrait de code suivant montre comment utiliser EncryptedFile
pour lire le contenu d'un fichier utilisant la version 1.1.0 de la bibliothèque de sécurité :
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();
Écrire des fichiers
L'extrait de code suivant montre comment utiliser EncryptedFile
pour écrire le contenu d'un fichier utilisant la version 1.1.0 de la bibliothèque de sécurité :
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();
Modifier les préférences partagées
L'extrait de code suivant montre comment utiliser EncryptedSharedPreferences
pour modifier les préférences partagées d'un utilisateur utilisant la version 1.1.0 de la bibliothèque de sécurité :
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();