Шифрование != хеширование. Как шифруются документы и защищаются пароли

1 октября, 2021, Oleg Afonin
Рубрика: «Разное»
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  

Сколько раз вы видели фразу: «ваш пароль надёжно зашифрован»? Если воспринимать написанное буквально, то получается, что пароль где-то хранится и при необходимости может быть извлечён (расшифрован). Для узкого множества продуктов (например, программ для хранения паролей) это имеет смысл, но для защиты документов, шифрования файлов на диске или защиты учётной записи сохранять пароль в составе файла/документа или на удалённом сервере не только не нужно, но и категорически небезопасно. В этой публикации мы расскажем о различиях между шифрованием и хешированием.

Шифрование и хеширование

Пароли используются для защиты документов, баз данных, сжатых архивов, отдельных файлов и дисков целиком, а также учётных записей. За редкими исключениями (например, пароли в веб-браузерах, связке ключей или учётных записях IMAP / POP3), пароли практически никогда не сохраняются — ни в открытом виде, ни в зашифрованном. Вместо этого пароли «хешируются», а точнее — преобразуются с помощью односторонней математической функции. Результат преобразования, если он выполнен правильно, невозможно обратить, а исходный пароль, соответственно, невозможно «расшифровать».

Шифрование — обратимая двусторонняя операция

Суть хеширования — в детерминированном одностороннем (необратимом) преобразовании набора данных произвольного размера в массив фиксированной длины.

Хеширование — одностороннее необратимое преобразование данных

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

Оригинальный текст: 000000000000
SHA-1: C2311E92660DE47B456E721B0DABC9F857AB48F0

Оригинальный текст: 000000000001
SHA-1: F6A8135A89118200A9CC55D456C4D9A2D319FA29

Как легко заметить, изменение единственного бита привело к радикальному изменению всего хэша. Вы можете самостоятельно проверить различные комбинации в онлайновом калькуляторе SHA-1 hash generator.

Подводя итог, хеширование — это одностороннее преобразование, которое не может быть обращено (по крайней мере, тогда, когда применяется качественный алгоритм хеширования). Максимум, который доступен в процессе атаки — сгенерировать так называемую «коллизию», то есть найти другой текст, преобразование которого посредством заданной хеш-функции выдаст совпадение (то есть, такой же хэш, как при использовании оригинального пароля). Современные алгоритмы хеширования спроектированы таким образом, чтобы свести вероятность возникновения коллизий к статистической погрешности.

Впрочем, не все пользуются готовыми безопасными решениями. Время от времени находятся разработчики, уверенные, что смогут сделать лучше. Как правило, такая уверенность не имеет под собой оснований, а в результате появляется катастрофически безграмотное, небезопасное решение. Яркий пример — популярная в Индии бухгалтерская программа Tally ERP 9 Vault, исследование системы безопасности которой мы описали в статье Вскрываем защиту Tally ERP 9. Ниже — цитата из неё:

Разработчики Tally Vault решили не полагаться на существующие криптографические преобразования и создали свой собственный вариант, настоящий кошмар криптографа. Все существующие алгоритмы хеширования без исключений гарантируют, что изменение всего одного бита в хешируемой последовательности приведёт к полному изменению всей контрольной суммы. Индийским разработчикам удалось сделать невероятное: они создали хеш-функцию, в которой при небольшом изменении пароля результат тоже меняется очень незначительно. Более того, у нас создалось впечатление, что при определённых условиях этот хэш можно обратить, получив из него оригинальный пароль (разумеется, если энтропия пароля не превышает энтропии его контрольной суммы). Вишенка на торте: преобразование применяется ровно один раз.

Современные хеш-функции

На сегодняшний день самыми распространёнными (и считающимися в достаточной степени безопасными) являются хеш-функции SHA-256 и SHA-512, пришедшие на замену алгоритму SHA-1, в котором была обнаружена возможность коллизий.

Источник: Google security blog

Существуют и другие функции хеширования — к примеру, алгоритм Whirlpool. Все современные хеш-функции должны отвечать ряду требований как к безопасности (те самые коллизии), так и к скорости как вычисления, так и проверки хэша. Разумеется, результат работы хеш-функции должен быть абсолютно односторонним и абсолютно необратимым.

Каким образом «абсолютная необратимость» хеш-функций соотносится с существованием многочисленных программ для взлома паролей, включая наши собственные разработки? Дело в том, что пароли обычно состоят из ограниченного числа символов. Ограниченная длина большинства паролей позволяет проверить на совпадение результаты хеширования, произведённые от всех возможных комбинаций букв, цифр и специальных символов вплоть до заданной максимальной длины. Так работает атака методом полного перебора.

Криптографическая соль

Что произойдёт, если группа злоумышленников вычислит хэш-функции для десятков миллионов популярных паролей? В таком случае для взлома пароля будет достаточно подсчитать хэш, который будет достаточно просто найти в таблице. Существует и более продвинутая версия атаки под названием Rainbow Tables.

Rainbow Tables – это реализация метода time-memory trade-off, при котором нет необходимости хранить все возможные хэши. Вместо этого они разбиваются на взаимосвязанные цепочки, от которых сохраняются только начало и конец. «Радужные таблицы» требуют усилий по перебору, но перебирать нужно гораздо меньше полного диапазона, причём параметры атаки можно подобрать или вычислить заранее. Вычисление подобных таблиц занимает у хакеров длительное время, после чего сами атаки осуществляются крайне быстро.

Для противодействия подобным атакам был разработан метод, применяющий к хэшу так называемую криптографическую соль. Теперь хэш вычисляется не от самого пароля, а от комбинации пароля и добавленной к нему случайной строки («соли»). Значение соли (повторимся — это строка, состоящая из случайных данных) сохраняется рядом с хэшем; без неё восстановить правильный пароль не получится. В редких случаях в дополнение к соли используется ещё одна строка — Pepper («перец»), значение которой хранится на отдельном физическом сервере для обеспечения дополнительного уровня безопасности.

Для обеспечения адекватной защиты недостаточно использовать стойкий алгоритм шифрования и криптографически безопасную хеш-функцию; необходимо правильно реализовать всю систему защиты. Так, даже самый безопасный хэш можно атаковать с помощью таблиц, в которых содержатся как сами пароли, так и результат их обращения посредством популярных хеш-функций.

Итерации (раунды) хеширования

Итак, для преобразования пароля в ключ шифрования, как правило, используется хеширование, а число алгоритмов хеширования фактически ограничено «большой тройкой» — SHA-1, SHA-256 и SHA-512. В то же время скорость работы атак методом полного перебора может отличаться на многие порядки в зависимости от того, какой именно набор данных подвергается атаке. Почему так происходит?

Разумеется, нельзя сбрасывать со счетов разницу в алгоритмах хеширования. Так, преобразование SHA-1 работает быстрее, чем SHA-512, которое, в свою очередь, быстрее, чем SHA-256. Самым медленным из популярных алгоритмов является Whirlpool. В зависимости от того, какой именно алгоритм хеширования используют разработчики конкретного приложения или формата данных, атака может происходить с большей или меньшей скоростью.

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

Количество раундов (итераций хеширования) оказывает сильнейшее влияние на скорость проверки пароля. На современном оборудовании вычисление одного значения хеш-функции от короткой строки, которой является пароль, занимает доли миллисекунды. Если бы файлы были защищены с помощью единственной итерации хеширования, мы бы получили атаки, работающие со скоростью в диапазоне десятков, а то и сотен миллионов паролей в секунду. Подобные атаки были возможны в iOS 10.0 (порядка 6 миллионов паролей в секунду на процессоре Intel шестилетней давности).

В современных приложениях используются сотни тысяч и даже миллионы итераций хеш-функции. Так, документы Microsoft Office используют 100,000 итераций, что позволяет проверить порядка десятка паролей в секунду. После фиаско с iOS 10.0 разработчики Apple увеличили число раундов хеширования до миллиона (!), в результате чего скорость проверки паролей к резервным копиям iTunes составляет единицы паролей в минуту. Криптоконтейнеры VeraCrypt защищены 500,000 раундами хеширования, причём у пользователя есть возможность изменить это значение в большую сторону.

Разумеется, под «итерацией» хеширования не имеется в виду бесконечный цикл вычислений значения хэш-функции от предыдущего хэша. В такой прямолинейной реализации алгоритм хеширования вырождается, существенно увеличивается риск коллизий. Борются с этим путём добавления промежуточных значений соли на каждом этапе. Промежуточная соль вычисляется алгоритмически для каждой итерации; случайным образом генерируется только оригинальная соль, которая хранится вместе с паролем. Таким образом в результате получается стойкий детерминированный хэш, вычисление которого на заданном оборудовании занимает заранее заданное время.

Как проверяется пароль

Для проверки пароля (например, в онлайновых сервисах или при входе в локальную учётную запись Windows, Linux или macOS) по заданному алгоритму подсчитывается его хэш, который система сравнивает с контрольной строкой. Рассмотрим для примера файл /etc/shadow, в котором хранятся пароли к ОС Linux.

В описаниях формата /etc/shadow часто можно встретить упоминание, что в файле хранятся «зашифрованные пароли». Как вы уже знаете, это не так: на самом деле в файле /etc/shadow хранятся хеши паролей, соль и некоторая дополнительная информация, включая информацию о том, каким образом должен вычисляться хэш. Хэши паролей хранятся хранятся в виде $type$salt$hashed, где значение переменной type указывает на тип хеш-функции из следующего списка:

  1. $1$ — MD5
  2. $2a$ — Blowfish
  3. $2y$ — Blowfish
  4. $5$ — SHA-256
  5. $6$ — SHA-512

В примере ниже приводится начало строки из файла /etc/shadow (у неё есть продолжение, в котором содержится сервисная информация — такая, как время последней смены пароля, оставшийся срок действия пароля и т.п.)

root:$6$Zwg4GkPw$5ggbsXCbCzjT3i8O7DGUqXH8vQiPqCySGLWSPDVR4ionV3AIkG0rqjeosDZGwpCQmsH6oP.6jqz6Zr.oA2DbA/

Здесь «root» — имя пользователя, $6$ указывает на то, что используется алгоритм хеширования SHA-512, «Zwg4GkPw» — соль, а строка, начинающаяся с «$5ggbs» — соответственно, хэш от пароля. В качестве эксперимента вы можете попробовать восстановить этот пароль или самостоятельно сгенерировать его командой mkpasswd -m sha-512 PASSWORD [SALT]

Обратите внимание: если отредактировать файл /etc/shadow (для этого нужен доступ root), то пароль любого пользователя можно сменить, зайдя от его имени. А можно ли сделать так же, например, для зашифрованного архива или документа?

Когда хэш не хранится

В ряде случаев при шифровании файла или документа хэш от оригинального пароля не сохраняется и, соответственно, не проверяется. Так работает, например, шифрование в формате RAR4 (а вот в пришедшем ему на смену формате RAR5 хэш от пароля вычисляется и сохраняется в заголовке архива). Вариантов два:

  • ключом, сгенерированным из пароля, шифруется фиксированная строка, которая используется для шифрования файла или документа (так, например, работает BitLocker)
  • ключом, сгенерированным из пароля, шифруется весь документ (так работает формат RAR4)

В обоих случаях хеширование используется для генерации ключа из пароля, однако во втором случае, если был указан неправильный пароль, файл или документ будет расшифрован, но «расшифрованные» данные не пройдут валидации. В таком случае скорость проверки пароля (и, соответственно, скорость атаки) не будет детерминированной. Вот скорость перебора паролей в Elcomsoft Distributed Password Recovery для формата RAR5, в котором хэш от пароля сохраняется в заголовке архива:

Логично было бы сравнить скорость атаки на этот формат с предшествующим форматом RAR4, но сделать это невозможно: из-за того, что в RAR4 не сохраняется хэш от пароля, для проверки пароля необходимо расшифровать хотя бы один файл, вычислить его контрольную сумму и проверить её совпадение с той, которая хранится в архиве. Если контрольная сумма расшифрованного файла совпадёт с эталоном, пароль считается правильным. Если же пароль неправильный, то файл до конца распаковать не удастся. Ошибка распаковки — тоже индикатор неправильного пароля, и этот момент учтён в процессе оптимизации перебора в Elcomsoft Distributed Password Recovery.

Заключение

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


  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  

REFERENCES:

Elcomsoft Distributed Password Recovery

Производительное решение для восстановление паролей к десяткам форматов файлов, документов, ключей и сертификатов. Аппаратное ускорение с использованием потребительских видеокарт и лёгкое масштабирование до 10,000 рабочих станций делают решение Элкомсофт оптимальным для исследовательских лабораторий и государственных агентств.

Официальная страница Elcomsoft Distributed Password Recovery »

НАШИ НОВОСТИ