Ну что же, разопьем по бутылочке темного пива и продолжим знакомиться с возможностями Windows Vista, доступными разработчикам программного обеспечения (или, как подсказывает Крыс Касперски из своей глубокой норы в недрах аргентинского болота, «точить»). На этот раз давай посмотрим, что же изменилось в операционной системе с точки зрения шифрования данных. А изменилось, надо сказать, немало: начиная с основательного обновления CryptoAPI и заканчивая созданием принципиально новой сущности – криптоядра CNG (Cryptography API Next Generation). Дело за малым – разобраться со всем этим богатством и научиться применять криптотехнологии WV на практике.

 

Windows Crypto – время перемен

Aaloha, Guy! Думаешь, ты уже изучил Висту вдоль и поперек и познакомился со всеми ее фишками? Не тут-то было. Пора копнуть глубже и заглянуть ей под капот. Видишь во-о-он ту блестящую штуковину с моторчиком? Нравится? А знаешь, что это такое? Нет? Ну тогда слушай и запоминай.

Итак, на повестке дня - криптосистема Windows Vista.

Если тебе приходилось использовать криптографические возможности более ранних версий Винды, ты должен знать, что доступ к этим возможностям предоставляется системой CAPI (Crypto API). Так вот Vista несет на своем борту новую, не столь убогую, как в Windows XP, версию CAPI. Но как это дело не причесывай, конфетку из него все равно не сделаешь. И в Microsoft это хорошо понимают. Нет, они не переписали CAPI с нуля (на фига напрягаться), они просто засунули CAPI в дальний темный угол системы. Теперь за взаимодействие с CAPI отвечает красивая блестящая обертка под названием CNG. Но парни действительно старались, и обертка получилась не только красивой, но и весьма полезной. О том, какие
возможности перед тобой открывает система CNG, читай ниже.

Перечень изменений в криптографической системе выглядит следующим образом:

  • Введен новый уровень абстракции, реализованный через CNG.
  • CAPI сменил свою версию на 2.0 (при этом CAPI 1.0 никуда не исчез, поддержка его функций сохранена в полном объеме).
  • .Net Framework теперь имеет в своем составе все необходимые интерфейсы, обеспечивающие взаимодействие CLR с криптографической подсистемой.

Согласись, перемены достаточно серьезные. И это я еще не упомянул о кардинальной перестройке архитектуры интерфейса PKI. Следуя известной мудрости, гласящей о том, что «нельзя объять необъятное», давай остановимся на центральной теме нововведений в криптосистеме – на интерфейсе CNG, а все остальное пусть будет твоим домашним заданием :).

Итак, технология CNG (Cryptography Next Generation) пришла к нам всерьез и надолго, будучи призванной заменить устаревший CryptoAPI. Основной логической единицей как в CryptoAPI, так и в CNG является криптопримитив, то есть некоторая сущность, обеспечивающая выполнение одной специализированной операции. Если провести сравнение криптопримитивов, входящих в состав CryptoAPI и CNG, то можно сказать, что CNG в полном объеме включает в себя CryptoAPI плюс новые дополнительные возможности. Основу технологии составляют два элемента – NCrypt и BCrypt.

NCrypt отвечает за хранение ключей, используемых ассиметричными алгоритмами шифрования. Кроме того, NCrypt обеспечивает поддержку смарт-карт и прочего оборудования. А вот функции BCrypt гораздо шире и интереснее. Именно здесь находится все богатство криптографических примитивов, которыми располагает CNG. Эти примитивы могут быть использованы как в режиме ядра, так и в пользовательском режиме, в то время как хранилище ключей NCrypt доступно только из пользовательского режима.

CNG предоставляет специальный API для доступа к криптографическим возможностям Windows Vista. Причем реализован этот доступ, в отличие от других аналогичных систем, не в виде отдельных функций, а в виде набора интерфейсов криптоядра. Набор логических криптоинтерфейсов представляет собой криптомаршрутизатор. Посмотри на схему структуры CNG, чтобы получить представление о том, какие криптопримитивы в твоем распоряжении. Ну как, впечатляет?

Криптографические примитивы CNG
Криптографические примитивы CNG

Допустим, ты решил написать супербезопасную программу, предназначенную для работы под Windows Vista. Как при этом получить доступ к криптографическим примитивам? Слушай сюда, и будет тебе счастье.

Есть универсальный интерфейс CNG, который называется провайдером алгоритмов (Algorithm Provider). Для обращения к провайдеру алгоритмов существует дескриптор BCRYPT_HANDLE. Инициализация провайдера алгоритмов не представляет ничего сложного:

BCRYPT_HANDLE algorithmProvider = 0;
NTSTATUS status = ::BCryptOpenAlgorithmProvider(
&algorithmProvider, algorithmName,
implementation, flags);
if (NT_SUCCESS(status))
{
//
Используем CNG-примитивы
}

За управление инициализацией провайдера алгоритмов отвечает строка «BCRYPT_HANDLE algorithmProvider = arg», где arg – это как раз и есть параметр, управляющий процессом инициализации. В частности, если он равен нулю, то по умолчанию будет использован криптоалгоритм, определяемый параметром algorithmName.

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

status = ::BCryptCloseAlgorithmProvider(
algorithmProvider, flags);
ASSERT(NT_SUCCESS(status));

То есть мы передаем функции BCryptCloseAlgorithmProvider() ранее созданный дескриптор провайдера алгоритмов и забываем о том, что у нас вообще когда-то был такой объект.

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

 

CNG на практике

Прежде всего, если ты собрался использовать в своем проекте возможности CNG, не забудь о заголовочном файле <bcrypt.h>, а также укажи линкеру, что при сборке проекта понадобится библиотека bcrypt.dll. Большинство функций, входящих в CNG, может генерировать различные сообщения о текущем статусе. Для этого используется файл ntstatus.h, следовательно, если тебе понадобится обработка этих сообщений, используй вот такой макрос:

#ifndef NT_SUCCESS
# define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif

Шифруем данные:

BCryptOpenAlgorithmProvider(&hAlg,...)
BCryptGetProperty(hAlg,BCRYPT_BLOCK_LENGTH,&dwBlockSize,...)
BCryptGetProperty(hAlg,BCRYPT_OBJECT_LENGTH,&cbKeyObjectLen,...)
BCryptGenerateSymmetricKey(hAlg,&hKey,...)
BCryptEncrypt(hKey,...)
BCryptDestroyKey(hKey)
BcryptCloseAlgorithmProvider(hAlg,0)

Не все понятно? Ок. Давай разбираться, что тут написано. Первая строка подключает и инициализирует провайдера криптоалгоритмов. Дальше с помощью функции BCryptGetProperty() мы выделяем в буфере место под размещение кодируемых данных и ключа, которым будет осуществляться шифрование. После того как мы позаботимся о выделении памяти, можно приступать непосредственно к шифрованию. Оно выполняется в два этапа: сначала генерируем ключ симметричного шифрования – BCryptGenerateSymmetricKey(), затем шифруем данные – BCryptEncrypt(). И не забываем убирать за собой – BCryptDestroyKey(), BCryptCloseAlgorithmProvider(). Наверняка, у кого-то из гиков, привыкших к жесткому порно, точнее, к жесткой
оптимизации (вроде того нарисованного хрена, который считает себя другом второго нарисованного хрена, более интеллигентного вида), возник вполне резонный вопрос: почему мы пошли в обход, использовав BCryptOpenAlgorithmProvider вместо обращения непосредственно к функциям шифрования? Все дело в том, что обращение к кэшируемому объекту гораздо эффективнее, чем непосредственный вызов функций шифрования. Кстати, подобный подход использовался и раньше, например при обращении к функциям
CAPI.

Так же просто с помощью CNG можно получить и хэш-функцию объекта:

BCryptOpenAlgorithmProvider(&hAlg,...)
BCryptGetProperty(hAlg,BCRYPT_OBJECT_LENGTH,&cbHash,...)
BCryptCreateHash(hAlg,&hHash,...)
BCryptHashData(hHash,...)
BCryptFinishHash(hHash,...)
BCryptDestroyHash(hHash)
BСryptCloseAlgorithmProvider(hAlg,0)

По аналогии с предыдущим примером перво-наперво необходимо позаботиться о выделении адресного пространства для работы с объектами. За работу с хэш-функциями отвечают методы BCryptCreateHash(), BCryptHashData() и BCryptFinishHash(). Ну и, как обычно, завершаем все уничтожением ненужных более объектов и ссылок: BСryptDestroyHash() и BCryptCloseAlgorithmProvider().

Идем дальше. Если ты не знаешь, что такое MAC, – бегом учить матчасть. И не спеши возмущенно заявлять, что о
Media Access Control знают даже первоклассники. MAC - это еще и Message Authentification Code, то есть одна из реализаций технологии
цифровой подписи. Создание MAC аналогично расчету хэш-функции, за исключением двух моментов. Во-первых, при вызове BCryptOpenAlgorithmProvider последним из передаваемых функции параметров должен быть BCRYTP_ALG_HANDLE_HMAC_FLAG. Во-вторых, дополнительно нужно указать секретный
MAC-ключ и его размер. Таким образом, вызов функции будет похож на тот, что приведен ниже:

BCRYPT_ALG_HANDLE hAlg = NULL;
NTSTATUS status = STATUS_UNSUCCESSFUL;
status = BCryptOpenAlgorithmProvider(&hAlg,
GetPreferredHmacAlg(),
NULL,
BCRYPT_ALG_HANDLE_HMAC_FLAG)))

Но известная фирма на букву М не была бы сама собой, если бы все было прозрачно, ясно и понятно. Видишь функцию GetPreferredHmacAlg()? Так вот эта функция не является частью библиотеки
CNG, как логично было бы предположить. Ее реализация отдается на откуп программисту, который сам должен решить, в соответствии с каким алгоритмом будет рассчитываться
MAC. А ты как хотел: понавызывал кучу API-функций и айда на печку сметану есть? Нет, иногда еще и думать приходится. Такие вот дела, брат.

Ну и, наконец, такая полезная возможность, предоставляемая CNG, как генерация случайных чисел. С этой задачей справится даже стая леммингов, добравшаяся до клавиатуры:

BCRYPT_ALG_HANDLE hRngAlg = NULL;
if (BCryptOpenAlgorithmProvider(&hRngAlg,
BCRYPT_RNG_ALGORITHM,
NULL,
0) == STATUS_SUCCESS) {
BYTE buf[32];
if (BCryptGenRandom(hRngAlg,
buf,
sizeof buf,
0) == STATUS_SUCCESS) {
}
BCryptCloseAlgorithmProvider(hRngAlg,0);
hRngAlg = NULL;
}

Полный список функций CNG API ты можешь найти в документации, которой комплектуется
CNG SDK, или же на сайте MSDN. Кроме того, на диске, идущем в комплекте с журналом, мы выложили подборку примеров использования
CNG. Так что, если какие-то моменты тебе не особо понятны, смотри исходники.

И несколько слов о собственно использовании CNG. Прежде всего, это технология, тесно завязанная на криптофункциях Висты. Следовательно, не рассчитывай на то, что тебе удастся поюзать
CNG, к примеру, в Windows XP. Для разработки приложений, использующих новые криптографические возможности, понадобится
Visual Studio 2005 с первым сервис-паком (естественно, бета-версия VS 2008, которая выкладывалась на диске к августовскому номеру журнала, тоже подойдет). Я тут уже упоминал, что
CNG совместима только с WV. А это значит, что помимо IDE нам понадобится еще и
Windows Vista SDK, позволяющий разрабатывать приложения для этой операционной системы. И, наконец, самое главное, без чего тебе не
обойтись, - это CNG SDK, содержащий все необходимые заголовочные файлы, библиотеки и криптоинструменты. Где его взять? Ну, во-первых, на сайте производителя (хм... почему-то это слово у меня ассоциируется исключительно с мужской особью крупного рогатого скота). А во-вторых, на нашем диске - такие вот мы добрые и щедрые.

И последнее замечание. Если ты фанат Visual Basic'a или крутой перец, не признающий ничего, кроме жутко модного C#, спешу тебя огорчить:
CNG SDK совместим только с проектами, написанными на приплюснутом Си.

Теперь детали...

Для того чтобы начать работать с CNG, нужно в свойствах проекта в группе параметров C/C++ (строка Additional Include Directories) прописать путь к файлам CNG SDK. Если ты не менял предложенный по умолчанию каталог установки SDK, тогда это будет C:\Program Files\Microsoft CNG Development Kit\Include.

Кроме того, в свойствах линкера необходимо указать, где он сможет найти необходимые DLL-файлы (C:\Program Files\Microsoft CNG Development Kit\Lib\X86).

 

Криптография нового поколения

Как видишь, парни из Microsoft действительно приложили немало усилий к тому, чтобы заменить малопопулярный у разработчиков
CAPI более надежным и более функциональным набором инструментов. И это у них, безусловно, получилось. Хотя, возможно, они немного погорячились, назвав это криптографией нового поколения, поскольку ничего принципиально нового придумано не было. Просто широко известные и проверенные временем алгоритмы были объединены в
криптоядро со своим API, доступным как из пользовательского режима, так и из режима ядра. Простая идея. Но, несмотря на свою простоту, она позволяет вывести криптографические возможности операционной системы на новый уровень. Считать ли это криптографией
нового поколения, решать тебе. Adios!

 

WWW

http://msdn2.microsoft.com/en-us/library/aa376214.aspx - подробное описание CNG на сайте MSDN.

www.microsoft.com/security/glossary.mspx - словарь терминов по IT-безопасности, используемых в технологиях компании Microsoft.


Полную версию статьи
читай в декабрьском номере Хакера! А так же специально для тебя мы выложили на наш диск CNG SDK! Шифруйся на здоровье. Лучше один раз увидеть, чем бла-бла-бла... Забирай с диска архив с примерами, распаковывай и изучай.

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии