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