Отгремел Google I/O 2019 и пришла пора переписывать проекты на новую архитектуру изучать новинки. Так как я интересуюсь безопасностью мобильных приложений, то в первую очередь обратил внимание на новую библиотеку в семействе JetPack — security-crypto. Библиотека помогает правильно организовывать шифрование данных и при этом ограждает разработчиков от всех нюансов, которые сопровождают этот процесс.


Историческая справка


Шифрование данных в Android всегда порождало много дискуссий. Какой алгоритм выбрать? Какой режим шифрования использовать? Что такое padding? Где хранить ключи? Для обычного разработчика изучать всё это и поддерживать знания в актуальном состоянии может быть трудно. Поэтому история чаще всего заканчивалась одним из трех сценариев:


  • копипаст первого попавшегося решения со stackoverflow
  • поиск «подходящего мануала» с последующей имплементацией и сбором граблей
  • активация протокола «И так сойдет!»

По мере развития сообщества android-разработчиков начали появляться библиотеки, помогающие решать эту задачу. Качество этих решений было очень разным: из всего этого многообразия я могу выделить только java-aes-crypto, которую мы и использовали в Redmadrobot. Довольно качественная имплементация, но с ней была пара проблем.


Во-первых, это было просто шифрование строк. Само по себе это не плохо, но ведь эти строки нужно где-то хранить, в БД или SharedPreferences. А значит, нужно писать обертку над источником данных, чтобы все шифровалось на лету (что мы когда-то и делали). Но это код, который нужно поддерживать, таскать из проекта в проект или оформлять в библиотеку для удобства использования. В конечном итоге это тоже было сделано, но это не принесло успокоения пытливым умам.


Во-вторых, это решение ничего не предлагало для решения проблемы управления ключами. Их можно было сгенерить, но вот хранение полностью ложилось на плечи разработчика. Со всеми приседаниями вокруг AndroidKeystore на разных версиях ОС и устройствах, пришедших с Mainland China.


Этому городу нужен новый герой


Все шло своим чередом, пока летом 2018-го я не обнаружил, что есть такая замечательная библиотека от Google как Tink. Она достаточно проста в освоении и ограждает разработчика от огромного количества нюансов, касающихся криптографии. Используя эту библиотеку, практически невозможно сделать что-то неправильно. Более того, Tink полностью берет на себя управление ключами и абстрагирует все операции с AndroidKeystore от разработчика.


Но это все еще было просто шифрование строк. И тут очень удачно подвернулась Binary Preferences — библиотека от отечественного производителя, на которую давно хотелось посмотреть. Она позволяет шифровать все сохраняемые данные любых алгоритмов — для этого было достаточно написать реализацию двух интерфейсов, KeyEncryption и ValueEncryption (для ключей и значений соответственно).


В итоге мы стали применять две этих библиотеки в связке и были счастливы, что наш код стал чище и проще для понимания.


security-crypto



Теперь Google в очередной раз решил пойти навстречу разработчикам и упростить их жизнь в области шифрования сохраняемых данных. Была анонсирована еще одна JetPack библиотека, которая призвана с этим помочь. Мне стало интересно, что же они такого революционного там написали, и я полез искать документацию (спойлер: ее нет). Нашел только javadoc-и по входящим в состав библиотеки классам, но и на том спасибо. Оказалось, что возможностей там негусто: шифрование файлов, SharedPreferences и работа с ключами.


Для проверки работоспособности библиотеки написал пару снипетов:


Шифрование файлов
val file = File(filesDir, "super_secure_file")
val encryptedFile = EncryptedFile.Builder(file, this, "my_secret_key", EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB)
    .setKeysetAlias("my_test_keyset_alias")
    .setKeysetPrefName("keyset_pref_file")
    .build()

val outputStream = encryptedFile.openFileOutput()

outputStream.use {
    it.write("secret info".toByteArray())
}

Шифрование SharedPreferences
val encryptedPreferences = EncryptedSharedPreferences.create(
    "super_secret_preferences",
    "prefrences_master_key",
    this,
    EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
    EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)

encryptedPreferences.edit().putString("secret", "super secret token")

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


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


Демонстрация работы связки BinaryPreferences + Tink
Исходный код библиотеки security-crypto
Демонстрация работы security-crypto

Комментарии (3)


  1. Revertis
    18.05.2019 11:23

    for Android 6.0+
    Google в очередной раз решил пойти навстречу разработчикам и упростить их жизнь

    Что-то не сходится…


    1. LionisIAm
      18.05.2019 13:57

      @minSdkVersion больше года назад твитнул про 21. На 21+22 в сумме сидит меньше 15% юзеров, неизвестно, сколько из них ещё платежеспособных(читай — целевая аудитория). Так что 23 не за горами. А в новых проектах и вовсе уже кое у кого стоит. А если это старый Легаси проект, то там джетапак не спасет: либо там нету нужды использовать security пакет, либо он давным давно самописан, о чем и пишет автор.


      1. Revertis
        18.05.2019 14:16

        Это всё хорошо, но 15% юзеров мало кому захочется терять. Возможно, даже зря, могли бы подстегнуть юзеров перейти на новые аппараты, но вою в поддержке будет очень много.
        Недавно мы перешли с 16 на 21, и уже есть пара недовольных юзеров.