[Перевод] Зашифрованные предпочтения в Андроид

Добрый день. Меня зовут Дмитрий и я являюсь преподавателем базового курса «Android разработчик» в Otus. Сегодня я решил поделиться переводом статьи, которую считаю интересной и думаю, что она может быть полезной для многих читателей нашего блога.

4dhpxsdj_oanpmzk36jeum0bbk4.png

Хранить данные в SharedPreferences очень быстро и удобно. Злоумышленникам также легко взглянуть на данные, хранящиеся в SharedPreferences…так что будьте осторожны с тем, что вы там поместили, и, возможно, придется задуматься о том, как хранить данные в зашифрованном формате.
Для небольших объемов данных, которые не оправдывают использование механизма БД, такого как SqlCipher, наши возможности были ограничены:

  • Собственные методы шифрования (если вы знаете, что делаете)
  • Готовые решения, такие как Secure-preferences, другие Secure-preferences, Armadillo и т.д.
  • Борьба с самыми странными проблемами жизненного цикла системы Android Keystore в каждой версии Android

Это работало раньше, но теперь у нас есть правильное и официальное решение.
Хотя это все еще альфа, она какое-то время работала хорошо, когда я использовал ее в своих проектах. Использование EncryptedSharedPreferences приветствуется (или же вы можете использовать его), для всех своих с min-sdk 23+.

Давайте рассмотрим пример того, как его использовать:

Пример EncryptedSharedPreferences


Минимальный SDK


На сегодняшний день 23 (Android 6.0)

minSdkVersion 23

Добавьте зависимости

implementation "androidx.security:security-crypto:1.0.0-alpha02"

Инициализировать / открыть


Просто создайте или извлеките мастер-ключ из хранилища ключей Android и используйте его для инициализации / открытия экземпляра EncryptedSharedPreferences:

// Шаг 1: Создать или получить мастер-ключ для шифрования / дешифрования
val masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)

// Шаг 2. Инициализируйте / создайте экземпляр EncryptedSharedPreferences
val sharedPreferences = EncryptedSharedPreferences.create(
    "PreferencesFilename",
    masterKeyAlias,
    applicationContext,
    EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
    EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)

Сохранить записи


Сохраните данные, как вы всегда делали с SharedPreferences:

// Шаг 3. Сохраните данные в EncryptedSharedPreferences
sharedPreferences.edit()
    .putString("DATA", saveText.text.toString())
    .apply()

Читать записи


Читайте данные, как вы всегда делали с SharedPreferences:

// Шаг 3: Считайте данные из EncryptedSharedPreferences
val value = sharedPreferences.getString("DATA", "")

Действительно ли настройки зашифрованы?


Да, и действительно довольно хорошо зашифрованы.

Скажем, я поместил значение akaita в SharedPreferences. Вот как будет выглядеть файл:



    akaita

Если я добавлю значение akaita в EncryptedSharedPreferences, я получу что-то совсем другое:



    ASnO9uni11t3m9sNgDJbiYllL/tE+i99TYKfQ0h8XV6AUN0O3rBxBsMmcpw2DCY=
    12a901eb372af4775b09f5b51d20d49428931c5d8e0b17dd103d2169c1879b8b13958274d7e25d3cc052f301461495fd40b70806ae244f456726802460318bdf19dce444e7a60f20c903c5a57140ea8e90a19a1b48559961d145a50000d1c0e22ca918b02ea0cc34e433900f44c00e9c791ecb678f26d293c0226d6c2a9e25e610616ec34241b06410481427a850eeedf85ee4c725d5dbd715b5a8d0e017be9a568a9f960989271d14d2d0531a4408a5d0dae705123c0a30747970652e676f6f676c65617069732e636f6d2f676f6f676c652e63727970746f2e74696e6b2e4165735369764b6579100118a5d0dae7052001
    12880189e734bbbf9cfa3bc15b5e53ea8df03341269cf97112a60a1f6482732dd33248b3f821397fb04ef3372ff54336e9045a0b0c0fb7afdf475dbc98a1107d09de66afcc5ad063e5e5b59a7d616e14834e19769bc84de7e5c8716a811814a6cd7a6d72a1c64ce4317f2f482181c437b70f010219ca6407a98bac18f1101c02fd8e2c4a9009ad2a1ebbdc1a4408e9edbbce02123c0a30747970652e676f6f676c65617069732e636f6d2f676f6f676c652e63727970746f2e74696e6b2e41657347636d4b6579100118e9edbbce022001


Более того, зашифрованный файл будет меняться каждый раз, когда мы сохраняем, что затрудняет доступ к нему.

Большое предостережение: производительность


Существует значительная разница в производительности между SharedPreferences и EncryptedSharedPreferences.

Вы можете проверить сами, используя мой пример кода или просто скачав пример приложения из Play Store. Я сам провожу несколько тестов на реальном устройстве, получая следующие результаты:
twgoigffmr6h8qzbndqcvuh7buc.jpeg
EncryptedSharedPreferences в сравнении с SharedPreferences

mrrggm0jiydl4wsp7hcnd_vla6u.png
График «EncryptedSharedPreferences в сравнении с SharedPreferences»

Заключение

EncryptedSharedPreferences является надежным и очень простым решением для Android 6.0 и выше.

Он имеет два больших плюса:

  1. нам не нужно ничего кодировать в нашем коде. Он просто использует Android Keystore для нас, избавляя себя от необходимости справляться с этим
  2. пользователю не нужно устанавливать экран блокировки. EncryptedSharedPreferences будет работать так же хорошо, без блокировки экрана

Это почти полная замена SharedPreferences. Просто убедитесь, что инициализация / открытие EncryptedSharedPreferences не влияет негативно на ваших пользователей.

Это решение определенно останется. Я использую это в любом подходящем сценарии. Теперь я просто хочу сказать, что ребята из Android улучшат его производительность, так что нам можно беспокоиться еще меньше:)

Пример приложения

Просто, чтобы было проще протестировать и убедиться, что все хорошо связано, я создал и приложение для вас. Загрузите его или скомпилируйте и попробуйте!
https://github.com/akaita/encryptedsharedpreferences-example

Ставьте плюс, если считаете статью полезной, а на любые вопросы буду рад ответить в комментариях.

© Habrahabr.ru