EncryptedSharedPreferences — este o componentă a bibliotecii AndroidX Security care asigură criptarea transparentă a datelor salvate prin API-ul SharedPreferences. Spre deosebire de SharedPreferences obișnuite, unde datele sunt stocate într-un fișier XML deschis, EncryptedSharedPreferences criptează automat cheile și valorile înainte de scrierea pe disc. Conform Android Developers, biblioteca utilizează AES-256 GCM pentru valori și AES-256 SIV (RFC 5297) pentru chei, asigurând confidențialitatea și integritatea datelor.
Principalele puncte
EncryptedSharedPreferences — este o clasă din pachetul androidx.security.crypto, introdusă în AndroidX Security 1.0.0 (2019). Implementează interfața SharedPreferences, dar toate operațiile de scriere (putString, putInt, putBoolean etc.) criptează datele în prealabil, iar operațiile de citire le decriptează înainte de a le returna.
SharedPreferences standard salvează datele într-un fișier XML în directorul aplicației (/data/data/package/shared_prefs/). Fișierul nu este criptat — cu acces root la dispozitiv sau la analiza backupului, toate datele se citesc ca XML simplu. Tokenurile de autentificare, cheile API, datele personale ale utilizatorului devin accesibile atacatorului.
EncryptedSharedPreferences rezolvă această problemă la nivel de bibliotecă: datele sunt criptate înainte de scrierea pe disc și decriptate la citire. Dezvoltatorul nu trebuie să apeleze manual funcții criptografice — API-ul rămâne identic cu SharedPreferences obișnuite.
Biblioteca AndroidX Security v1.0.0 a fost lansată în decembrie 2019. EncryptedSharedPreferences a înlocuit abordarea învechită cu criptarea manuală prin Cipher + SharedPreferences. Versiunea stabilă actuală este 1.1.0-alpha06 (2024), care suportă API 19+. Biblioteca face parte din Jetpack și nu necesită permisiuni suplimentare.
Conform Google Security Blog (2024), EncryptedSharedPreferences este metoda recomandată pentru stocarea setărilor confidențiale ale aplicației care nu necesită sincronizare prin cloud. Pentru scenarii mai complexe, se recomandă Room cu criptare prin SQLCipher.
EncryptedSharedPreferences utilizează o schemă de criptare pe două niveluri: cheia principală (Master Key) este stocată în Android Keystore, iar pentru criptarea datelor se folosesc chei derivate. Aceasta este o combinație de protecție Keystore și performanță a criptării simetrice.
Pentru valori se utilizează AES-256 GCM (Galois/Counter Mode) — mod de criptare autentificată (AEAD), care asigură confidențialitatea și integritatea datelor. Pentru chei (nume de parametri) se aplică AES-256 SIV (RFC 5297) — criptare deterministă, necesară pentru căutarea după cheie fără a dezvălui conținutul acesteia.
Fiecare fișier EncryptedSharedPreferences conține perechi cheie-valoare criptate. Structura fișierului: mai întâi un antet cu metadate (versiune, identificator cheie), apoi o listă de intrări criptate. Fișierul nu este un XML valid și nu poate fi citit cu editori de text.
Clasa MasterKey se ocupă de crearea și gestionarea cheii principale de 256 de biți, care este stocată în Android Keystore. MasterKey.Builder permite configurarea: tipul de stocare (Keystore sau software), protecția biometrică, durata de viață a cheii. Implicit, cheia principală este generată în Android Keystore cu algoritmul 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 primește cinci parametri: context, nume fișier, cheie principală, schema de criptare a cheilor și schema de criptare a valorilor. Alegerea schemelor influențează performanța și nivelul de protecție.
AES256_SIV — criptare deterministă: cheile identice produc întotdeauna același text criptat. Acest lucru este necesar pentru căutarea după cheie (SharedPreferences.getX(key)). Dezavantaj: atacatorul poate determina ce chei sunt utilizate după textele criptate repetitive. AES256_SIV2 — versiune îmbunătățită cu randomizare suplimentară.
Pentru valori se utilizează AES256_GCM. GCM adaugă un IV de 12 octeți (vector de inițializare) și un tag de autentificare de 16 octeți la fiecare valoare. Aceasta asigură confidențialitatea (nimeni nu poate citi valoarea) și autentificarea (nimeni nu poate modifica valoarea fără a fi detectat).
Metoda setUserAuthenticationRequired(true) în MasterKey.Builder necesită confirmare biometrică înainte de obținerea cheii principale din Keystore. Acest lucru adaugă un nivel suplimentar: chiar dacă aplicația rulează pe un dispozitiv deblocat, atacatorul nu poate citi EncryptedSharedPreferences fără Face ID sau Touch ID.
Important: cu setUserAuthenticationRequired, cheia principală devine indisponibilă dacă utilizatorul a schimbat sau șters biometria. Trebuie tratată KeyPermanentlyInvalidatedException și creată o nouă cheie principală cu migrarea datelor.
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) {
// Biometria s-a schimbat — trebuie recreată cheia
}
}
Să analizăm un exemplu complet de integrare a EncryptedSharedPreferences într-o aplicație Android în Kotlin. Biblioteca androidx.security:security-crypto se adaugă prin Gradle.
În fișierul build.gradle (app) adăugați: implementation „androidx.security:security-crypto:1.1.0-alpha06“. Pentru proiectele Kotlin, este necesar și kotlin-stdlib. Inițializarea MasterKey are loc o singură dată, de obicei în Application.onCreate sau printr-un container DI.
După crearea instanței EncryptedSharedPreferences, API-ul nu diferă de SharedPreferences obișnuite. edit() returnează un Editor, toate metodele (putString, getString, putBoolean, getBoolean) funcționează similar. Diferența este doar în interior: datele sunt criptate la scriere și decriptate la citire.
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()
}
}
Pentru migrarea datelor existente din SharedPreferences neprotejate în EncryptedSharedPreferences este necesar: citiți toate datele din fișierul vechi, creați un nou EncryptedSharedPreferences, scrieți toate datele, ștergeți fișierul vechi. Google nu oferă un instrument de migrare încorporat — dezvoltatorul îl implementează singur.
Alegerea între SharedPreferences și EncryptedSharedPreferences depinde de tipul datelor stocate. Pentru setările interfeței (temă, limbă, sortare) SharedPreferences obișnuite sunt suficiente. Pentru informații confidențiale (tokenuri, parole, chei) EncryptedSharedPreferences este obligatoriu.
EncryptedSharedPreferences este mai lent decât cel obișnuit din cauza operațiilor criptografice. Scrierea unei valori de tip string durează ~5-15 ms (depinde de dimensiunea datelor și de accelerarea hardware AES). Citirea — 2-5 ms. Pentru majoritatea aplicațiilor, acest lucru este imperceptibil, dar la operații batch (migrare, restaurare) merită să folosiți apply() în loc de commit().
SharedPreferences obișnuite nu oferă nicio protecție criptografică: fișierul XML poate fi citit de orice proces cu acces root sau prin adb backup. EncryptedSharedPreferences criptează datele la nivelul aplicației, iar cheia principală este stocată în Android Keystore cu posibilitatea de protecție hardware (StrongBox).
| Caracteristică | SharedPreferences | EncryptedSharedPreferences |
|---|---|---|
| Stocare | XML deschis | Fișier binar criptat |
| Criptare | Nu | AES-256 GCM + SIV |
| Protecția cheilor | Nu | Android Keystore + StrongBox |
| Performanță | 0.1-1 ms | 2-15 ms |
| Recomandare | Setări UI | Tokenuri, chei, PII |
Utilizați EncryptedSharedPreferences pentru stocarea: tokenului de reîmprospătare OAuth, cheilor API pentru servicii externe, e-mailului sau numărului de telefon al utilizatorului, setărilor confidențiale ale aplicației (PIN, flags de autentificare). Pentru stocarea datelor biometrice sau a documentelor mari, EncryptedSharedPreferences nu este potrivit — utilizați EncryptedFile sau Room cu SQLCipher.
Regula generală: dacă scurgerea datelor va dăuna utilizatorului sau afacerii — utilizați EncryptedSharedPreferences. Dacă datele sunt doar cosmetice (temă, limbă, sortare) — SharedPreferences obișnuite. Implementarea EncryptedSharedPreferences are sens imediat, fără refactorizare: înlocuirea într-un proiect existent necesită migrare și gestionarea datelor vechi necriptate.
Amintiți-vă că EncryptedSharedPreferences nu protejează datele în timpul funcționării aplicației — doar pe disc. Dacă atacatorul are acces la memoria procesului, datele decriptate pot fi interceptate. Utilizați protecție suplimentară: ProGuard/DexGuard pentru ofuscarea codului.
Întrebări frecvente
Jetpack DataStore — este o alternativă mai modernă la SharedPreferences, bazată pe Flow și corutine Kotlin. DataStore nu criptează datele implicit, dar poate fi combinat cu EncryptedSharedPreferences sau utilizat cu criptare manuală prin Proto DataStore cu protocoale criptografice.
Nu se recomandă. EncryptedSharedPreferences este destinat volumelor mici (până la 100-200 KB). Pentru date mari, utilizați Room cu SQLCipher sau criptarea fișierelor prin EncryptedFile din aceeași bibliotecă AndroidX Security.
Nu, migrarea automată a schemei nu există. La modificarea structurii datelor, dezvoltatorul trebuie să citească manual datele vechi prin vechiul KeyGen și să le scrie prin noul. Se recomandă stocarea versiunii schemei într-un parametru separat.
AndroidX Security 1.0.0 suportă API 19+ (Android KitKat). Versiunea 1.1.0-alpha06 suportă de asemenea API 19+. Pentru StrongBox, este necesar API 28+ și un dispozitiv cu suport hardware (Google Pixel 3+, Samsung Galaxy S9+).
Da, tokenul de reîmprospătare — este unul dintre scenariile principale de utilizare. Criptarea AES-256 GCM, cheia principală în Keystore, protecția biometrică — nivel suficient pentru tokenurile OAuth. Pentru tokenul de acces cu durată scurtă de viață, este de asemenea potrivit, deși unele echipe preferă să-l stocheze în memorie.
Concluzii
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și