Настройка Encrypted SharedPreferences в Android-приложении
Когда приложению не нужна биометрия или сложная схема ключей, но токены в plaintext SharedPreferences — очевидный риск, EncryptedSharedPreferences из Jetpack Security закрывает 80% кейсов за полдня работы.
Что именно шифруется
EncryptedSharedPreferences использует библиотеку Tink от Google с двухуровневым шифрованием: ключи шифруются AES256-SIV (детерминированное шифрование, позволяет поиск по ключу), значения — AES256-GCM. Мастер-ключ хранится в Android Keystore. В итоге XML-файл преференций содержит нечитаемый blob вместо <string name="auth_token">eyJhb...</string>.
Инициализация
val masterKey = MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.setUserAuthenticationRequired(false) // true если нужна биометрия
.build()
val prefs = EncryptedSharedPreferences.create(
context,
"secure_prefs",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
После этого API идентичен обычному SharedPreferences — putString, getString, edit().apply(). Никакого дополнительного кода.
Ограничения, которые важно знать
EncryptedSharedPreferences не поддерживает getAll() — метод выбрасывает UnsupportedOperationException. Если ваш код где-то итерируется по всем ключам, нужен рефакторинг до перехода.
Файл преференций нельзя скопировать между устройствами — мастер-ключ привязан к Keystore конкретного устройства. Это ограничение, о котором нужно предупредить при миграции с обычных SharedPreferences: восстановление из бэкапа (Auto Backup) не принесёт зашифрованные данные.
Jetpack Security версии 1.1.0-alpha (и выше) стабилизировала API после долгого альфа-периода. Используйте не ниже 1.1.0-alpha06 — в более ранних версиях есть известный баг с повреждением файла при определённых условиях записи.
Когда EncryptedSharedPreferences недостаточно
Если данные нужны в background worker без пользователя на экране, и устройство может быть перезагружено — нужен явный контроль над kSecAttrAccessible-аналогом, то есть прямая работа с Keystore и настройка setUserAuthenticationRequired(false) с нужной схемой доступа. EncryptedSharedPreferences использует BIOMETRIC_STRONG or DEVICE_CREDENTIAL если биометрия включена, что может заблокировать фоновый доступ.
Для хранения больших объёмов (файлы, базы данных) — EncryptedFile из того же Jetpack Security, не SharedPreferences.
Сроки
Простая замена SharedPreferences на EncryptedSharedPreferences — 4–8 часов включая тестирование на нескольких API уровнях. Если есть Auto Backup и нужно правильно настроить backup_rules.xml для исключения зашифрованного файла из бэкапа — добавьте ещё несколько часов.







