EncryptedSharedPreferences — это компонент библиотеки AndroidX Security, обеспечивающий прозрачное шифрование данных, сохраняемых через SharedPreferences API. В отличие от обычных SharedPreferences, где данные хранятся в открытом XML-файле, EncryptedSharedPreferences автоматически шифрует ключи и значения перед записью на диск. Согласно Android Developers, библиотека использует AES-256 GCM для значений и AES-256 SIV (RFC 5297) для ключей, обеспечивая конфиденциальность и целостность данных.
Главное
EncryptedSharedPreferences — это класс из пакета androidx.security.crypto, представленный в AndroidX Security 1.0.0 (2019). Он реализует интерфейс SharedPreferences, но все операции записи (putString, putInt, putBoolean и т.д.) предварительно шифруют данные, а операции чтения расшифровывают их перед возвратом.
Стандартные SharedPreferences сохраняют данные в файл XML в директории приложения (/data/data/package/shared_prefs/). Файл не зашифрован — при root-доступе к устройству или при анализе бэкапа все данные читаются как обычный XML. Токены аутентификации, ключи API, персональные данные пользователя становятся доступны злоумышленнику.
EncryptedSharedPreferences решает эту проблему на уровне библиотеки: данные шифруются перед записью на диск и расшифровываются при чтении. Разработчику не нужно вызывать криптографические функции вручную — API остаётся идентичным обычным SharedPreferences.
Библиотека AndroidX Security v1.0.0 вышла в декабре 2019. EncryptedSharedPreferences заменила устаревший подход с ручным шифрованием через Cipher + SharedPreferences. Текущая стабильная версия — 1.1.0-alpha06 (2024), поддерживающая API 19+. Библиотека входит в состав Jetpack и не требует дополнительных разрешений.
По данным Google Security Blog (2024), EncryptedSharedPreferences — рекомендованный способ хранения конфиденциальных настроек приложения, не требующих синхронизации через облако. Для более сложных сценариев предлагается Room с шифрованием через SQLCipher.
EncryptedSharedPreferences использует двухуровневую схему шифрования: мастер-ключ (Master Key) хранится в Android Keystore, а для шифрования данных используются производные ключи. Это сочетание защиты Keystore и производительности симметричного шифрования.
Для значений используется AES-256 GCM (Galois/Counter Mode) — режим аутентифицированного шифрования (AEAD), обеспечивающий конфиденциальность и целостность данных. Для ключей (имён параметров) применяется AES-256 SIV (RFC 5297) — детерминированное шифрование, необходимое для поиска по ключу без раскрытия его содержимого.
Каждый файл EncryptedSharedPreferences содержит зашифрованные пары ключ-значение. Структура файла: сначала заголовок с метаданными (версия, идентификатор ключа), затем список зашифрованных записей. Файл не является валидным XML и не читается текстовыми редакторами.
Класс MasterKey отвечает за создание и управление 256-битным мастер-ключом, который хранится в Android Keystore. MasterKey.Builder позволяет настроить: тип хранилища (Keystore или программный), защиту биометрией, время жизни ключа. По умолчанию мастер-ключ генерируется в Android Keystore с алгоритмом 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 принимает пять параметров: контекст, имя файла, мастер-ключ, схему шифрования ключей и схему шифрования значений. От выбора схем зависит производительность и уровень защиты.
AES256_SIV — детерминированное шифрование: одинаковые ключи всегда дают одинаковый зашифрованный текст. Это необходимо для поиска по ключу (SharedPreferences.getX(key)). Недостаток: злоумышленник может определить, какие ключи используются, по повторяющимся шифротекстам. AES256_SIV2 — улучшенная версия с дополнительной рандомизацией.
Для значений используется AES256_GCM. GCM добавляет 12-байтовый IV (вектор инициализации) и 16-байтовый тег аутентификации к каждому значению. Это обеспечивает конфиденциальность (никто не прочитает значение) и аутентификацию (никто не подменит значение без обнаружения).
Метод setUserAuthenticationRequired(true) в MasterKey.Builder требует биометрического подтверждения перед получением мастер-ключа из Keystore. Это добавляет дополнительный уровень: даже если приложение запущено на разблокированном устройстве, злоумышленник не сможет прочитать EncryptedSharedPreferences без Face ID или Touch ID.
Важно: при setUserAuthenticationRequired мастер-ключ становится недоступным, если пользователь изменил или удалил биометрию. Необходимо обрабатывать KeyPermanentlyInvalidatedException и создавать новый мастер-ключ с миграцией данных.
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) {
// Биометрия изменилась — нужно пересоздать ключ
}
}
Рассмотрим полный пример интеграции EncryptedSharedPreferences в Android-приложении на Kotlin. Библиотека androidx.security:security-crypto подключается через Gradle.
В файл build.gradle (app) добавьте: implementation "androidx.security:security-crypto:1.1.0-alpha06". Для Kotlin-проектов дополнительно требуется kotlin-stdlib. Инициализация MasterKey происходит однократно, обычно в Application.onCreate или через DI-контейнер.
После создания экземпляра EncryptedSharedPreferences API не отличается от обычных SharedPreferences. edit() возвращает Editor, все методы (putString, getString, putBoolean, getBoolean) работают аналогично. Разница только внутри: данные шифруются при записи и расшифровываются при чтении.
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()
}
}
Для миграции существующих данных из незащищённых SharedPreferences в EncryptedSharedPreferences необходимо: прочитать все данные из старого файла, создать новый EncryptedSharedPreferences, записать все данные, удалить старый файл. Google не предоставляет встроенного мигратора — разработчик реализует его самостоятельно.
Выбор между SharedPreferences и EncryptedSharedPreferences зависит от типа хранимых данных. Для настроек интерфейса (тема, язык, сортировка) обычные SharedPreferences достаточны. Для конфиденциальной информации (токены, пароли, ключи) EncryptedSharedPreferences обязателен.
EncryptedSharedPreferences медленнее обычных из-за криптографических операций. Запись одного строкового значения занимает ~5-15 мс (зависит от размера данных и аппаратного ускорения AES). Чтение — 2-5 мс. Для большинства приложений это незаметно, но при пакетных операциях (миграция, восстановление) стоит использовать apply() вместо commit().
Обычные SharedPreferences не обеспечивают никакой криптографической защиты: файл XML читается любым процессом с root-доступом или через adb backup. EncryptedSharedPreferences шифрует данные на уровне приложения, а мастер-ключ хранится в Android Keystore с возможностью аппаратной защиты (StrongBox).
| Характеристика | SharedPreferences | EncryptedSharedPreferences |
|---|---|---|
| Хранение | Открытый XML | Зашифрованный бинарный файл |
| Шифрование | Нет | AES-256 GCM + SIV |
| Защита ключей | Нет | Android Keystore + StrongBox |
| Производительность | 0.1-1 мс | 2-15 мс |
| Рекомендация | Настройки UI | Токены, ключи, PII |
Используйте EncryptedSharedPreferences для хранения: refresh token OAuth, ключей API для внешних сервисов, email или номера телефона пользователя, конфиденциальных настроек приложения (PIN, флаги аутентификации). Для хранения биометрических данных или больших документов EncryptedSharedPreferences не подходит — используйте EncryptedFile или Room с SQLCipher.
Общее правило: если данные при утечке нанесут вред пользователю или бизнесу — используйте EncryptedSharedPreferences. Если данные только косметические (тема, язык, сортировка) — обычные SharedPreferences. EncryptedSharedPreferences имеет смысл внедрять сразу, без рефакторинга: замена в существующем проекте потребует миграции и обработки старых незашифрованных данных.
Помните, что EncryptedSharedPreferences не защищает данные во время работы приложения — только на диске. Если злоумышленник имеет доступ к памяти процесса, расшифрованные данные могут быть перехвачены. Используйте дополнительную защиту: ProGuard/DexGuard для обфускации.
Часто задаваемые вопросы
Jetpack DataStore — это более современная альтернатива SharedPreferences, основанная на Flow и Kotlin корутинах. DataStore не шифрует данные по умолчанию, но может быть скомбинирован с EncryptedSharedPreferences или использоваться с ручным шифрованием через Proto DataStore с криптографическими протоколами.
Не рекомендуется. EncryptedSharedPreferences предназначен для небольших объёмов (до 100-200 КБ). Для больших данных используйте Room с SQLCipher или шифрование файлов через EncryptedFile из той же библиотеки AndroidX Security.
Нет, автоматической миграции схемы нет. При изменении структуры данных разработчик должен вручную прочитать старые данные через старый KeyGen и записать их через новый. Рекомендуется хранить версию схемы в отдельном параметре.
AndroidX Security 1.0.0 поддерживает API 19+ (Android KitKat). Версия 1.1.0-alpha06 также поддерживает API 19+. Для работы StrongBox требуется API 28+ и устройство с аппаратной поддержкой (Google Pixel 3+, Samsung Galaxy S9+).
Да, refresh token — один из основных сценариев использования. Шифрование AES-256 GCM, мастер-ключ в Keystore, биометрическая защита — достаточный уровень для OAuth токенов. Для access token с коротким временем жизни также подходит, хотя некоторые команды предпочитают хранить его в памяти.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также