EncryptedSharedPreferences est un composant de la bibliothèque AndroidX Security qui fournit un chiffrement transparent des données enregistrées via l'API SharedPreferences. Contrairement aux SharedPreferences classiques, où les données sont stockées dans un fichier XML en clair, EncryptedSharedPreferences chiffre automatiquement les clés et les valeurs avant de les écrire sur le disque. Selon Android Developers, la bibliothèque utilise AES-256 GCM pour les valeurs et AES-256 SIV (RFC 5297) pour les clés, garantissant la confidentialité et l'intégrité des données.
Points clés
EncryptedSharedPreferences est une classe du paquet androidx.security.crypto, introduite dans AndroidX Security 1.0.0 (2019). Elle implémente l'interface SharedPreferences, mais toutes les opérations d'écriture (putString, putInt, putBoolean, etc.) chiffrent les données au préalable, et les opérations de lecture les déchiffrent avant de les renvoyer.
Les SharedPreferences standard enregistrent les données dans un fichier XML dans le répertoire de l'application (/data/data/package/shared_prefs/). Le fichier n'est pas chiffré — avec un accès root à l'appareil ou lors de l'analyse de la sauvegarde, toutes les données sont lisibles en XML clair. Les jetons d'authentification, les clés API et les données personnelles de l'utilisateur deviennent accessibles à un attaquant.
EncryptedSharedPreferences résout ce problème au niveau de la bibliothèque : les données sont chiffrées avant d'être écrites sur le disque et déchiffrées à la lecture. Le développeur n'a pas besoin d'appeler manuellement des fonctions cryptographiques — l'API reste identique aux SharedPreferences classiques.
La bibliothèque AndroidX Security v1.0.0 est sortie en décembre 2019. EncryptedSharedPreferences a remplacé l'approche obsolète du chiffrement manuel via Cipher + SharedPreferences. La version stable actuelle est 1.1.0-alpha06 (2024), compatible avec API 19+. La bibliothèque fait partie de Jetpack et ne nécessite aucune autorisation supplémentaire.
Selon Google Security Blog (2024), EncryptedSharedPreferences est la méthode recommandée pour stocker les paramètres sensibles de l'application qui ne nécessitent pas de synchronisation cloud. Pour les scénarios plus complexes, Room avec chiffrement SQLCipher est recommandé.
EncryptedSharedPreferences utilise un schéma de chiffrement à deux niveaux : la Master Key est stockée dans Android Keystore et des clés dérivées sont utilisées pour le chiffrement des données. Cela combine la protection du Keystore avec les performances du chiffrement symétrique.
Pour les valeurs, AES-256 GCM (mode Galois/Counter) est utilisé — un mode de chiffrement authentifié (AEAD) garantissant la confidentialité et l'intégrité des données. Pour les clés (noms de paramètres), AES-256 SIV (RFC 5297) est appliqué — un chiffrement déterministe nécessaire pour la recherche de clés sans révéler leur contenu.
Chaque fichier d'EncryptedSharedPreferences contient des paires clé-valeur chiffrées. La structure du fichier comprend : d'abord un en-tête avec des métadonnées (version, identifiant de clé), puis une liste d'entrées chiffrées. Le fichier n'est pas un XML valide et ne peut pas être lu par des éditeurs de texte.
La classe MasterKey est responsable de la création et de la gestion d'une clé maître de 256 bits stockée dans Android Keystore. MasterKey.Builder permet de configurer : le type de stockage (Keystore ou logiciel), la protection biométrique et la durée de vie de la clé. Par défaut, la clé maître est générée dans Android Keystore avec l'algorithme AES/GCM/NoPadding.
import androidx.security.crypto.MasterKey
import androidx.security.crypto.EncryptedSharedPreferences
fun getEncryptedPrefs() {
val masterKey = MasterKey.Builder(context)
.setKeyScheme(MasterKey.AES256_GCM_SPEC)
.build()
val prefs = EncryptedSharedPreferences.create(
context,
"secure_prefs",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
}
EncryptedSharedPreferences.create accepte cinq paramètres : le contexte, le nom du fichier, la clé maître, le schéma de chiffrement des clés et le schéma de chiffrement des valeurs. Le choix des schémas affecte les performances et le niveau de sécurité.
AES256_SIV — chiffrement déterministe : des clés identiques produisent toujours le même texte chiffré. Ceci est nécessaire pour la recherche de clés (SharedPreferences.getX(key)). Inconvénient : un attaquant peut déterminer quelles clés sont utilisées en comparant les textes chiffrés répétés. AES256_SIV2 — une version améliorée avec randomisation supplémentaire.
Pour les valeurs, AES256_GCM est utilisé. GCM ajoute un IV de 12 octets (vecteur d'initialisation) et un tag d'authentification de 16 octets à chaque valeur. Cela assure la confidentialité (personne ne peut lire la valeur) et l'authentification (personne ne peut modifier la valeur sans être détecté).
La méthode setUserAuthenticationRequired(true) dans MasterKey.Builder exige une confirmation biométrique avant de récupérer la clé maître du Keystore. Cela ajoute une couche supplémentaire : même si l'application s'exécute sur un appareil déverrouillé, un attaquant ne peut pas lire EncryptedSharedPreferences sans Face ID ou Touch ID.
Important : avec setUserAuthenticationRequired, la clé maître devient indisponible si l'utilisateur modifie ou supprime ses données biométriques. Il faut gérer KeyPermanentlyInvalidatedException et créer une nouvelle clé maître avec migration des données.
fun createBiometricKey(): MasterKey {
return MasterKey.Builder(context)
.setKeyScheme(MasterKey.AES256_GCM_SPEC)
.setUserAuthenticationRequired(true)
.setRequestStrongBoxBacked(true)
.build()
}
fun writeSecureToken(token: String) {
try {
prefs.edit().putString("auth_token", token).apply()
} catch (e: KeyPermanentlyInvalidatedException) {
// La biométrie a changé — la clé doit être recréée
}
}
Examinons un exemple complet d'intégration d'EncryptedSharedPreferences dans une application Android avec Kotlin. La bibliothèque androidx.security:security-crypto est ajoutée via Gradle.
Dans le fichier build.gradle (app), ajoutez : implementation «androidx.security:security-crypto:1.1.0-alpha06». Pour les projets Kotlin, kotlin-stdlib est également nécessaire. L'initialisation de MasterKey se fait une fois, généralement dans Application.onCreate ou via un conteneur DI.
Après avoir créé une instance d'EncryptedSharedPreferences, l'API ne diffère pas des SharedPreferences classiques. edit() retourne un Editor, toutes les méthodes (putString, getString, putBoolean, getBoolean) fonctionnent de la même manière. La seule différence est interne : les données sont chiffrées à l'écriture et déchiffrées à la lecture.
class AuthRepository(context: Context) {
private val prefs = createEncryptedPrefs(context)
fun saveCredentials(login: String, password: String) {
prefs.edit()
.putString("login", login)
.putString("password", password)
.apply()
}
fun getToken(): String? {
return prefs.getString("auth_token", null)
}
fun clearAll() {
prefs.edit().clear().apply()
}
}
Pour migrer des données existantes depuis des SharedPreferences non chiffrées vers EncryptedSharedPreferences, il faut : lire toutes les données de l'ancien fichier, créer une nouvelle EncryptedSharedPreferences, écrire toutes les données et supprimer l'ancien fichier. Google ne fournit pas de migrateur intégré — le développeur l'implémente manuellement.
Le choix entre SharedPreferences et EncryptedSharedPreferences dépend du type de données stockées. Pour les paramètres d'interface (thème, langue, tri), les SharedPreferences classiques suffisent. Pour les informations confidentielles (jetons, mots de passe, clés), EncryptedSharedPreferences est obligatoire.
EncryptedSharedPreferences est plus lent que le classique en raison des opérations cryptographiques. L'écriture d'une seule valeur de chaîne prend ~5-15 ms (selon la taille des données et l'accélération matérielle AES). La lecture prend 2-5 ms. Pour la plupart des applications, cela est imperceptible, mais pour les opérations par lots (migration, restauration), utilisez apply() au lieu de commit().
Les SharedPreferences classiques n'offrent aucune protection cryptographique : le fichier XML peut être lu par tout processus disposant d'un accès root ou via adb backup. EncryptedSharedPreferences chiffre les données au niveau de l'application, et la clé maître est stockée dans Android Keystore avec une protection matérielle optionnelle (StrongBox).
| Caractéristique | SharedPreferences | EncryptedSharedPreferences |
|---|---|---|
| Stockage | XML en clair | Fichier binaire chiffré |
| Chiffrement | Aucun | AES-256 GCM + SIV |
| Protection des clés | Aucune | Android Keystore + StrongBox |
| Performances | 0.1-1 ms | 2-15 ms |
| Recommandation | Paramètres UI | Jetons, clés, PII |
Utilisez EncryptedSharedPreferences pour stocker : les jetons d'actualisation OAuth, les clés API pour les services externes, l'email ou le numéro de téléphone de l'utilisateur, et les paramètres sensibles de l'application (PIN, indicateurs d'authentification). EncryptedSharedPreferences n'est pas adapté pour stocker des données biométriques ou des documents volumineux — utilisez EncryptedFile ou Room avec SQLCipher.
La règle générale : si une fuite de données nuit à l'utilisateur ou à l'entreprise — utilisez EncryptedSharedPreferences. Si les données sont uniquement cosmétiques (thème, langue, tri) — SharedPreferences classiques. Il est judicieux d'implémenter EncryptedSharedPreferences dès le départ, sans refactorisation : son remplacement dans un projet existant nécessite une migration et le traitement des anciennes données non chiffrées.
N'oubliez pas que EncryptedSharedPreferences ne protège pas les données pendant l'exécution de l'application — uniquement sur le disque. Si un attaquant a accès à la mémoire du processus, les données déchiffrées peuvent être interceptées. Utilisez une protection supplémentaire : ProGuard/DexGuard pour l'obfuscation.
Foire aux questions
Jetpack DataStore est une alternative plus moderne à SharedPreferences, basée sur Flow et les coroutines Kotlin. DataStore ne chiffre pas les données par défaut, mais peut être combiné avec EncryptedSharedPreferences ou utilisé avec un chiffrement manuel via Proto DataStore avec des protocoles cryptographiques.
Non recommandé. EncryptedSharedPreferences est conçu pour de petits volumes (jusqu'à 100-200 Ko). Pour des données plus volumineuses, utilisez Room avec SQLCipher ou le chiffrement de fichiers via EncryptedFile de la même bibliothèque AndroidX Security.
Non, il n'y a pas de migration de schéma automatique. Lors du changement de structure des données, le développeur doit lire manuellement les anciennes données via l'ancien KeyGen et les écrire via le nouveau. Il est recommandé de stocker la version du schéma dans un paramètre séparé.
AndroidX Security 1.0.0 prend en charge API 19+ (Android KitKat). La version 1.1.0-alpha06 prend également en charge API 19+. StrongBox nécessite API 28+ et un appareil avec prise en charge matérielle (Google Pixel 3+, Samsung Galaxy S9+).
Oui, le refresh token est l'un des principaux cas d'utilisation. Chiffrement AES-256 GCM, clé maître dans Keystore, protection biométrique — un niveau suffisant pour les jetons OAuth. Pour les jetons d'accès à courte durée de vie, c'est également adapté, bien que certaines équipes préfèrent les stocker en mémoire.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi