Простой вектор инициализации (IV)
В ходе развития программных и аппаратных средств, а также в связи с новыми исследованиями в теории чисел и научной криптографии существующие решения и подходы шифрования данных могут устаревать. При выборе того или иного решения для шифрования данных следует всегда убеждаться, что выбранный алгоритм (трансформация) не устарел и на него нет успешных криптографических атак. Если же выбирается целое программное решение (библиотека, фреймворк, API), следует убедиться, что оно само не содержит ошибок или уязвимостей и также использует актуальные подходы к шифрованию.
Общие понятия
Чтобы лучше понимать описанное далее, рекомендуется ознакомиться с основными понятиями и определениями из мира криптографии. Не будем глубоко погружаться в математику и сложные вычисления, но остановимся на базовых вещах, которые помогут лучше понять подсвеченные инструментом проблемы.
Шифр — совокупность заранее оговоренных способов преобразования исходного секретного сообщения с целью его защиты.
Сообщение (открытый текст), полученное после преобразования с использованием любого шифра, называется шифрованным сообщением (закрытым текстом, криптограммой). В иностранной литературе закрытый текст и исходное сообщение называют ciphertext и plaintext соответственно.
Ключ — информация, необходимая для шифрования и расшифровки сообщений.
Соль — случайный набор данных, добавляемый к сообщению при хешировании для усложнения обратного преобразования (поиска исходных данных по известному результату хеширования).
Криптостойкостью называется характеристика шифра, определяющая его стойкость к дешифрованию без знания ключа.
Шифрование бывает симметричное и асимметричное. В симметричном (для шифрования и расшифровки используется один и тот же ключ) основной проблемой является безопасная передача данного значения между сторонами. Поэтому, как правило, его применяют, если шифровать/расшифровывать данные необходимо только на устройстве и никуда их передавать не нужно.
При асимметричном шифровании используются два ключа, которые называются публичный (public key) и приватный (private key). Эти ключи математически связаны друг с другом и их пара уникальна. На публичном ключе происходит шифрование данных, а приватным — расшифровка. Данный алгоритм используют чаще, если есть необходимость передавать данные куда-либо вне устройства.
Помимо различия в ключах, алгоритмы шифрования бывают блочные и поточные. Поточные шифры в рамках данной уязвимости не рассматриваются. Особенность блочных шифров в том, что они работают с блоками строго определенной длины. То есть, если входная информация по размеру больше, чем умеет обрабатывать тот или иной алгоритм, то она будет разделена на блоки, каждый из которых будет зашифрован.
Простой вектор инициализации
Initialization vector (IV) — произвольное число для предотвращения повторения шифрования данных в первом блоке. Может быть использовано вместе с ключом для шифрования данных.
Использование пустого или предсказуемого вектора инициализации является недопустимым в операциях шифрования. Для его генерации рекомендуется использовать класс SecureRandom
.
ivLength
(то есть длина вектора инициализации) зависит от режима работы. И для большинства режимов, включая CBC, IV должен иметь ту же длину, что и блок. Алгоритм AES использует 128-битные блоки, поэтому длина вектора инициализации равна 128 битам (ivLength
= 16 байт).
После генерации вектора инициализации достаточно создать экземпляр Cipher с его помощью:
cipher.init(Cipher.ENCRYPT_MODE, key, IvParameterSpec(iv))
cipher.init(Cipher.DECRYPT_MODE, key, IvParameterSpec(iv))
Рекомендации
-
Используйте случайные и уникальные IV для каждого шифрования: Генерируйте случайные векторы инициализации для каждого зашифрованного сообщения, чтобы обеспечить уникальность шифротекста. Это можно сделать с использованием класса
SecureRandom
:Пример безопасной генерации IV:
byte[] iv = new byte[16]; SecureRandom secureRandom = new SecureRandom(); secureRandom.nextBytes(iv); IvParameterSpec ivSpec = new IvParameterSpec(iv); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec); byte[] encryptedData = cipher.doFinal(plainTextData);
-
Используйте подходящие библиотеки и фреймворки: При реализации шифрования используйте современные криптографические библиотеки, которые обеспечивают безопасное управление векторами инициализации и ключами. Убедитесь, что библиотека поддерживает современные стандарты безопасности.
-
Не используйте предсказуемые или фиксированные значения IV: Избегайте использования нулевых массивов или фиксированных значений для векторов инициализации. Например, не используйте такие значения, как массив из нулей или заранее известные статические строки.
-
Используйте режимы шифрования с аутентификацией: Предпочтительно использовать AES в режиме GCM (Galois/Counter Mode), так как этот режим обеспечивает как шифрование, так и аутентификацию данных, что предотвращает подмену IV и защищает данные от атак.
Пример использования AES в режиме GCM:
-
Регулярно проверяйте актуальность используемых алгоритмов и реализаций: Убедитесь, что используемые вами криптографические методы соответствуют текущим стандартам безопасности и не имеют известных уязвимостей.
Ссылки
- https://www.baeldung.com/java-encryption-iv
- https://proandroiddev.com/secure-data-in-android-initialization-vector-6ca1c659762c
- https://medium.com/beautycoder/android-security-and-fingerprint-ef0f6f344888
- https://developer.android.com/training/articles/keystore
- https://medium.com/@josiassena/using-the-android-keystore-system-to-store-sensitive-information-3a56175a454b
- https://habr.com/ru/company/swordfish_security/blog/658433/
- https://habr.com/ru/company/swordfish_security/blog/664720/
- https://github.com/d0nutptr/Android-Security-Examples/blob/master/Cryptography/app/src/main/java/com/iismathwizard/cryptonote/Crypto.java
- https://github.com/flast101/padding-oracle-attack-explained/blob/master/oracle.py
- https://habr.com/ru/post/247527/?ysclid=l9wqtx7li4787340116
- https://en.wikipedia.org/wiki/Padding_oracle_attack