![]() |
Это вторая часть разговора об инфраструктуре шифрования нового поколения "Crypt Next Generation". Впервоймы рассмотрели базовые сведения о шифровании данных, и режимы работы алгоритма AES. В том-что это действительно мотор поколения Next можно убедиться на сайте MSDN, где на невинный запрос описания какой-либоустаревшей функциииз библиотеки CAPI, мелкософт встречает нас грозным предупреждением типа: -"Этот API устарел! Новое программное обеспечение должно использовать CNG, т.к. Microsoft может удалить этот API в будущих выпусках". Таким образом нас просто ставят перед фактом, подталкивая на изучение современных методов. Так не будем-же противиться этому..
Содержание: 1. Хеширование информации; 2. AAD – дополнительные данные для хеша; 3. Алгоритм AES в режиме GCM; 4. Практика – шифрование с аутентификацией; 5. Использование AEAD в браузерах; 6. Выводы. ------------------------------------------------------- 1. Хеширование данных Как правило, информацию хешируют для проверки её целостности. Отправитель пересчитывает хеш со-своей инфы, и вкладывает его значение в конверт с данными. Получатель на другом конце извлекает из конверта значение полученного хеша, и при помощи всё той-же функции повторно снимает хеш с принятых данных. Если при сравнении оба значения совпадут, значит не один бит информации не потерялся в каналах связи, и полученная инфа валидна. Здесь нужно понимать, что расчёт хеша – это не шифрование данных, а своеобразная сумма всех байт, на которую накладываются сложные математические операции. По этой причине, хеширование является односторонней функцией, без возможности восстановления исходных данных. Вне зависимости от размера информации на входе, мы всегда получаем хеш фиксированной длины. К примеру алгоритмы MD2[4,5] генерируют на выходе 16-байтные значения, а разрядность хеша SHA (Secure Hash Algorithm) указывается в его названии, т.е. для SHA-512 будет соответственно 512-бит или 64 байта (особняком стоит SHA1 с размером хеша 160-бит = 20 байт). Возьмём к примеру пароль из четырёх символов "1234". Как его хранить в программе? Ясно, что не в открытом виде, а если зашифровать обычным ксором, то подбор его брутфорсом займёт пару минут. Поэтому мы снимаем с пароля хеш например SHA-256 (sha2) и на выходе получаем уже 32-байтное значение этого пароля. Так решаются сразу две проблемы: во-первых автоматически отваливается брутфорс любого рода, а во-вторых – скрывается от посторонних глаз пароль. Получить коллизию при 32-байтном значении нереально, а потому можно быть уверенным, что хеши двух паролей не совпадут. Для программного его расчёта нам понадобятся аж шесть функций из библиотеки CNG Bcrypt.dll, т.к. в нашем распоряжении не законченные функции, а их примитивы. Конечно удобней было-бы собрать все в один флакон и обозвать набор элементарно BCryptHash() (кстати подобная функция есть и добавлена она только в Win10), но мы имеем дело с библиотекой низкого уровня, где каждую единицу приходится обрабатывать отдельно – это раскрепощает нас, хотя и требует взамен больше телодвижений. Функция BCryptOpenAlgorithmProvider() возвращает дескриптор выбранного алгоритма. Поскольку мы собираемся хешировать данные, то передаём этой функции во-втором параметре указатель на Unicode-строку "SHA256". Подготавливает окружение для операции следующий примитив BCryptCreateHash(). При вызове, она запросит у нас память для временного своего объекта, так-что перед ней нужно будет узнать у провайдера размер этого объекта для данного алгоритма, при помощи BCryptGetProperty() с аргументом "OBJECT_LENGTH". Теперь можно приступать непосредственно к процессу хеширования BCryptHashData() – функция ожидает адрес исходных данных и их размер. Финализирует операцию BCryptFinishHash(), которая сохраняет готовый к употреблению хеш в указанный нами буфер. По окончании, временный объект и всё окружение подлежит уничтожению функцией BCryptDestroyHash(), но если это последнее, что делает наша программа, ExitProcess() на выходе сама подчистит все выделенные системой ресурсы. В своей демке, я посчитаю хеш введённого юзером пароля сразу двумя алгоритмами SHA-256 и MD5, чтобы можно было сравнить их значения: C-подобный: Код:
format pe consoleХешам находят разное применение на практике. К примеру аверы проверяют файлы на наличие блох только один раз, после чего сравнивают их хеши. Если файл заражён, он моментально всплывёт наружу – это быстрее, чем каждый раз повторять одну и ту-же процедуру по всей длине файлов. 2. AAD – дополнительные данные для хеша Хеширование информации в чистом виде просуществовало довольно долго. Но однажды кому-то понадобилось не только проверять целость данных, но и идентифицировать их отправителя. К примеру получили мы конверт с вложенным хешем, но как узнать, что это хеш конкретно принятых данных, ведь отправитель (или третье лицо) может подставить вместо него любое значение от фонаря? Одним из разумных решений стало добавление запроса на "ввод пароля" от отправителя. Теперь, на этапе хеширования информации, отправитель должен предоставить функции не только сами данные, но и дополнительную текстовую строку, чтобы однозначно идентифицировать себя – эту строку назвали AAD, или "Additional Authenticated Data". AAD можно рассматривать как внешнюю соль к хешу, и чтобы значения двух хешей совпали на передающей и принимающей стороне, получатель должен подтвердить оригинальный AAD (т.е. ввести пароль). Так появились хеши с аутентификацией. Их тут-же взяли на вооружения сразу несколько режимов шифрования AES, известных под общим именем AEAD – "Authenticated Encryption with Associated Data" (аутентифицированное шифрование с присоединёнными данными). В этих режимах, алгоритм сначала шифрует исходные данные, после чего сразу-же вычисляет с них хеш. В контексте шифрования, такие хеши назвали МАС, что в развёрнутом виде означает "Message Authentification Code", или код аутентификации сообщения. Таким образом, AEAD-режимы сочетают в себе две операции: непосредственно шифрование для конфиденциальности, и вычисление MAC для проверки целостности данных, с аутентификацией юзера. Это приводит к более низким вычислительным затратам, по сравнению с использованием отдельных функций шифрование + аутентификация. Здесь, первая часть сообщения шифруется, вторая часть в виде AAD остаётся открытой, и всё сообщение целиком накрыто аутентификацией. В настоящее время имеются несколько AEAD-режимов AES, но в тройке лидеров: OCB2 (Offset codebook), CCM (CBC+MAC), и герой данного чтива GCM (Galois Counter Mode, CTR+GMAC) как наиболее популярный. Один из примеров использования AAD – это когда наше приложение служит прокси-сервером для развёртывания интерфейса с одним симметричным ключом и неограниченным кол-вом клиентов (причём каждый клиент находится в своём сегменте безопасности). Например, приложение может быть базой, в которую юзеры заносят данные личного характера. Когда одному из них нужно просмотреть свои записи, приложение может затребовать уникальное его имя в качестве AAD. В этом сценарии, функция AES откажет в расшифровке данных, если для крипт/декрипта не используется одно и то-же значение AAD. Параметр является опциональным в функции шифрования BCryptEncrypt(), однако он всегда принимает участие в процессе – если мы игнорируем его, просто используется пустая строка. 3. Алгоритм AES в режиме GCM На рисунке ниже представлена схема режима AES/GCM где видно, что он состоит из двух самостоятельных модулей – это шифрование и аутентификация (серый блок). Обратите внимание на локацию доп.данных AAD, обозначенных здесь как "Auth-Data". Они поступают в модуль GMAC и не шифруются, подвергаясь только операции хеш. Результатом функций AEAD является зашифрованный текст + тег аутентификации МАС (синие блоки). Вместе с ключом, вектором IV и необязательным AAD, 16-байтный тег МАС необходим для расшифровки закрытого CipherText. Криптографы всегда рекомендуют использовать режимы AEAD для блочных алгоритмов шифрования с симметричным ключом: https://forum.antichat.xyz/attachmen...fb2edb3b40.png Если присмотреться к этой схеме, то режим AES/GMAC есть ничто-иное как расширенная версия режима CTR(см.предыдущую часть статьи), к которому добавлен модуль GMAC для одновременного вычисления хеша: https://forum.antichat.xyz/attachmen...529eb01bce.png Все блочные алгоритмы с счётчиком на борту, благодарягаммированиюпо сути превращаются в потоковый шифр. Поэтому важно, чтобы для каждого блока AES использовался не повторяющийся IV, для чего собственно и служит счётчик. В отличии от блочных шифров, поточные не увеличивают исходные данные после шифрования – это относится и к AES/GCM. Зоопарк режимов AES может иметь разные характеристики производительности. GCM в полной мере использует преимущества параллельной обработки на нескольких ядрах процессора, и его реализация эффективно использует конвейер команд CPU. А вот цепочечные режимы AES (типа CBC) напротив приводят к остановкам конвейера, и это снижает их производительность. Чтобы увеличить скорость шифрования, начиная с процессоров "Xeon-56xx" Intel ввела специальный набор инструкций под названием AES-NI (New Instruction). Так появиласьаппаратная поддержкашифрования AES и хеширования SHA. Несмотря на то, что в данный набор входят всего несколько инструкций, они относятся к разряду SIMD, когда одна инструкция выполняет сразу несколько микроопераций (Single Instruction, Multiple Data). Благодаря тому, что каждая такая инструкция проделывает свою часть глобальной работы (AES включает в себя 4-этапа) – это позволило добиться 5-кратного увеличения скорости. Таким образом, если вам нужен быстрый режим шифрования с массой дополнений, используйте AES/GCM. Типичный интерфейс его программирования выглядит так: • Шифрование - Вход: открытый текст + ключ + IV + опционально AAD в виде открытого текста, который не будет зашифрован, но будет защищён аутентификацией. - Выход: зашифрованный текст + тег аутентификации МАС. • Расшифровка - Вход: зашифрованный текст + ключ + IV + МАС + AAD (если он использовался во время шифрования). - Выход: открытый текст или ошибка, если МАС или AAD не соответствуют зашифрованному тексту. Кстати в литературе, мнение криптографов на счёт определения "вектор инициализации IV" расходятся. Дело в том, что термин применяется как в контексте шифрования, так и в руководствах по хешированию данных. Поэтому (если дотошно придираться к мелочам), здесь нужно внести ясность.. Для хэш-функций, вектор инициализации – это постоянная константа, которая никогда не меняется (полином, см.вописание MD5). Для блочных-же шифров, одним из обязательных условий является уникальный IV для каждого блока AES – такие векторы назвали Nonce, или одноразовое не повторяющееся значение Код:
N(once)4. Практика – шифрование AES без аутентификации Теперь к практической реализации AES.. Говорят, что качество имеет различные метрики, и это утверждение как-нельзя лучше подходит к выбору нами алгоритма шифрования. Если задача проста и не требует особой криптко-стойкости, то зачем нагружать программу лишним кодом, ведь чем он проще, тем стабильней работает софт. По этой причине, сначала рассмотрим обычное шифрование AES без тегов аутентификации МАС (в числе которых режимы CBC и CFB), а потом и AEAD-режимы CCM/GCM с дополнительными данными AAD. Всё-что нужно режимам без МАС, это ключ шифрования и вектор инициализации IV. Как-правило, оба эти значения на подготовительном этапе генерируются рандомно, при этом мы можем выбрать один из трёх размеров ключей на своё усмотрение: 16, 24, 32 байта (для AES-128, 192, 256 соответственно). Поскольку в данных режимах нет внутреннего 4-байтного счётчика, то вектор IV должен быть строго размером 16 байт, чтобы он захватил весь первый блок AES: https://forum.antichat.xyz/attachmen...e518e37e23.png Программная реализация шифрования включает в себя пять этапов по такой схеме: 1. BCryptOpenAlgorithmProvider() с аргументом "AES_ALGORITHM" – возвращает дескриптор алгоритма; 2. BCryptSetProperty() с аргументом "CHAIN_MODE_CBC" – устанавливает в свойствах дескриптора режим CBC; 3. BCryptGenRandom() – сгенерировать случайные ключ и вектор IV; 4. BCryptGenerateSymmetricKey() – получить дескриптор симметричного ключа шифрования; 5. BCryptEncrypt() – зашифровать данные ключом и вектором IV. На что здесь следует обратить особое внимание, так это на значение вектора IV. Дело в том, что согласно докам MSDN, функция шифрования BCryptEncrypt() может испортить его при переходе к следующему блоку AES, и если мы не хотим потерять исходные данные, то должны заблаговременно сделать резервную копию оригинального IV, чтобы в первоначальном виде передать его функции последующей расшифровки BCryptDecrypt(). Иначе мы получим невалидный вектор, и данные уйдут к праотцам. Отметьте сей факт красным фломастером! Функция-же непосредственно шифрования BCryptEncrypt() принимает на грудь 10 параметров, из них в приоритете четвёртый "PaddingInfo" и последний "dwFlags". Два этих аргумента содержат информацию о заполнении 16-байтных блоков AES, и для режимов без аутентификации первый должен быть нуль, а во-втором нужно выставить флаг авто-выравнивания "BCRYPT_BLOCK_PADDING". Если его не указать, функция шифрования начнёт требовать от нас, чтобы мы подавали на вход кратные блоку AES данные, т.е. минимум 16 и дальше 32,48 и т.д. байт. Так-что паддинг ставим в единицу, что даст возможность вводить пароли произвольной длины. C-подобный: Код:
NTSTATUS BCryptEncryptКак видим тут всё просто, но программисты предпочитают что-то позабористей, ведь за почти такое-же количество "приседаний" можно получить более лучший эффект. Достаточно в этом коде задействовать параметр "pPaddingInfo", как в нашем распоряжении оказываются дополнительные данные AAD, с возможностью получить тег-аутентификации МАС. Если мы сталкиваемся с зашифрованными данными и их длина кратна 16-ти, то можно предположить, что это AES в блочном режиме. Если-же длина кратна восьми, как вариант перед нами DES. 4.1. Практика – шифрование AES-256 в режиме GCM Режимы шифрования с аутентификацией GCM/CCM можно сравнить с безоборотным метанием ножа – они при любых обстоятельствах бьют точно в цель. Такие бонусы мы получаем благодаря структуре "BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO", указатель на которую передаётся в параметре(4) Padding. C этой структурой связана одна мерзкая неприятность – по неизвестным причинам, её размер везде (на MSDN и хидере bcrypt.h) указывается на 8-байт меньше, чем этого требуют функции BCryptEncrypt/Decrypt(). Правится баг обычным добавление в хвост структуры ещё одного 8-байтного поля, которое я обозначил как резерв. Иначе крипто-функции выше возвращают ошибку Код:
"INVALID_PARAMETR"Код:
0xC000000dC-подобный: Код:
struct BCRYPT_AUTH_CIPHER_MODE_INFOЕсли расчехлить отладчик и вскормить ему этот код, то нырнув в функцию BCryptEncrypt() по F7 можно обнаружить, что функция не использует преимущества аппаратного шифрования AES-NI, а весь алгоритм реализует исключительно обычными Код:
MOVКод:
XORОбратите внимание на формат результата шифрования – он включает в себя три составляющие: 12-байтный вектор IV, зашифрованный пароль, и в хвосте тег-аутентификации GМАС. А вот данные AAD как-правило не передаются принимающей стороне, иначе в них теряется смысл. Их нужно держать в тайне, накрыв протектом на уровне самой программы. Это-же относится и 32-байтному ключу шифрования AES. Рассмотрим, как справляется с этой задачей, например, браузер Хром. 5. Использование AEAD в браузерах Поскольку высказывания ниже могут классифицироваться в рамках шпионажа, я не буду заострять внимание на мелочах, а лишь приведу общую картину. Достаточно будет сказать, что алгоритм проверенный и воркает исправно. На предыдущем скрине, я не зря расположил результат шифрования AES/GCM в таком порядке. По сути, от перестановки мест слагаемых сумма не меняется. Однако интернет браузеры Chrome версии 80+ держат эту информацию в своих базах SQLite именно в таком виде, только добавляют к ним ещё и сигнатуру "v10". То-есть получаем сл.табличку: https://forum.antichat.xyz/attachmen...4f40f14447.png Это типичный формат хранения хромом паролей и кукисов, базы которых можно найти по следующим адресам: • Пароли – AppData\Local\Google\Chrome\User Data\Default\Login Data • Кукисы – AppData\Local\Google\Chrome\User Data\Default\Cookies Открываем базу кукисов в каком-нибудь редакторе SQLite3 (типа SQLite Expert Personal), и обнаруживаем в ней две таблицы с названиями "cookies" и "meta". В первой имеется столбец "encrypted_value", где и хранятся зашифрованные алгоритмом AES-256/GCM непосредственно куки различных сайтов. Если щёлкнуть на пимпу любой строки в этом столбце, то перед нами откроется встроенный Hex-редактор, где будет красоваться соответствующий закриптованный кукис. Вот как это выглядит у меня: https://forum.antichat.xyz/attachmen...887151c725.png В процессе расшифровки данного кукиса, нам нужно просто отбросить сигнатуру "v10" и передать всю оставшуюся информацию в свой код. Отметим, что Хром не использует данные AAD, тогда для достижении цели нам остаётся добыть только 32-байтный ключ шифрования. Как и следовало ожидать, он прописан там-же, только в файле Json по адресу: • AppData\Local\Google\Chrome\User Data\Local State Помимо ключа, в этом файле хранится всякое барахло, а сам ключ в нём можно найти по Json-строке Код:
"os_crypt":{"encrypted_key":https://forum.antichat.xyz/attachmen...9abf0dbc1f.png 6. Послесловие Шифрование является основным методом защиты информации, однако в основе криптографии лежит не только крипт, но и ряд вспомогательных методов. В частности это не рассмотренная здесь "электронная подпись" (используется для подтверждения авторства передаваемых данных). Такие алгоритмы называют "сигнатурными", и в них подписывается обычно хэш данных, а не все данные целиком. Они используют два вида ключей – секретный для вычисления электронной подписи, и открытый для её проверки. У нас не было-бы безопасного современного Интернета без работы В.Реймена, Д.Дэемен, Д.Виеги, Д.МакГрю и бесчисленного множества других криптографов и исследователей безопасности, которые сделали возможным использование AES в режиме GCM. Это по истине один из самых продвинутых на сегодняшний день алгоритмов шифрования, который прочно пустил свои корни во-все направления современной сферы IT. В скрепке лежат три рассмотренных выше исполняемых файла, а так-же инклуд "вcrypt.inc" для сборки исходников. Надеюсь ещё увидимся, удачи, пока! |
Прекрасные статьи! Было бы ещё очень интересно в Вашем исполнении прочитать про winsocs и wininet.
|
Цитата:
|
Я читал про winsocs, и даже работал с ними но у автора уж больно хорошо и красиво выходит. Ну есть ещё wininet, которая организует протоколы высокого уровня над winsocs и которой уделено уже гораздо меньше внимания
За ссылки спасибо, ознакомлюсь! P.s. ещё раз спасибо за ссылки, они как-то мимо меня прошли!!! |
Вы так давно не писали статьи, жаль...
|
| Время: 23:54 |