Ну что же, разопьем по бутылочке темного пива и продолжим знакомиться с возможностями 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
Допустим, ты решил написать супербезопасную программу, предназначенную для работы под 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.
|