- CryptoApi и Криптопровайдер VipNet CSP
- Вкратце о Microsoft CryptoApi
- ViPNet CSP
- Пример использования
- Использование Crypto API
- Введение
- Общие основы
- Строение и возможности Crypto API
- Криптопровайдеры
- Контейнеры ключей
- Алгоритмы
- Сертификаты
- Базовые функции
- Шифрование
- Экспорт сессионных ключей
- Импорт сессионных ключей
- Расшифровывание
- Хеширование
- Цифровая подпись
- Проверка цифровой подписи
- Высокоуровневые функции обработки сообщений
- Введение
- Шифрование
- Расшифровывание
- Цифровая подпись
- Проверка цифровой подписи
- Совмещение цифровой подписи и шифрованных данных
- Расшифровывание и проверка совмещенной цифровой подписи и шифрованных данных
- Работа с форматом Base64 (PEM)
- CAPICOM
CryptoApi и Криптопровайдер VipNet CSP
Вкратце о Microsoft CryptoApi
Итак, CryptoAPI это — интерфейс программирования приложений, который обеспечивает разработчиков Windows-приложений стандартным набором функций для работы с криптопровайдером. Входит в состав операционных систем Microsoft. Большинство функций CryptoAPI поддерживается начиная с Windows 2000.
CryptoAPI поддерживает работу с асимметричными и симметричными ключами, то есть позволяет шифровать и расшифровывать данные, а также работать с электронными сертификатами. Набор поддерживаемых криптографических алгоритмов зависит от конкретного криптопровайдера.
Реализация всех алгоритмов (шифрования, цифровой подписи и т.п.) полностью выведена из состава самого Crypto API и реализуется в отдельных, независимых динамических библиотеках – «криптопровайдерах» (Cryptographic Service Provider – CSP). Сам же Crypto API просто предъявляет определенные требования к набору функций (интерфейсу) криптопровайдера и предоставляет конечному пользователю интерфейс работы с CSP. Для использования всех функций криптопровайдера достаточно знать его строковое имя и номер типа.
ViPNet CSP
VipNet CSP – это программный комплекс, который реализует интерфейс Microsoft CryptoApi.
ViPNet CSP обеспечивает выполнение следующих функций:
- Генерация закрытых и открытых ключей ЭЦП и шифрования в соответствии с алгоритмом ГОСТ Р 34.10 – 2001.
- Вычисление хеш-функции в соответствии с алгоритмом ГОСТ Р 34.11-94.
- Вычисление и проверка ЭЦП в соответствии с алгоритмом ГОСТ Р 34.10-2001.
- Выработка случайных и псевдослучайных чисел, сессионных ключей шифрования.
- Шифрование и имитозащита данных в соответствии с алгоритмом ГОСТ 28147-89.
- Аутентификация и шифрование при передаче данных по протоколам SSL/TLS.
- Операции с сертификатами открытых ключей, соответствующих стандарту X.509 v3.
Совместимость
ViPNet CSP функционирует под управлением ОС Windows 2000 (32 бит)/XP (32 бит)/Server 2003 (32 бит)/Vista (32 бит) /Windows 7 (32/64 бит).
К сожалению VipNet CSP – это платный продукт, но на сайте есть бета-версии, которые отлично функционируют.
Разобраться с криптопровайдером довольно легко, в скачиваемый пакет входит проработанная до мелочей документация, а также множество примеров кода. Скачать последнюю версию можно здесь. Более подробно ознакомиться с описанным выше криптопровайдером можно здесь.
Пример использования
Итак, мы инсталлировали криптопровайдер, можем написать программу, шифрующую данные с использованием ГОСТ 28147-89. В скачиваемом пакете (архиве) есть папка «ViPNet CSP SDK (для разработчиков)», найдем там заголовочный файл importitccsp.h, в нем объявлены необходимые нам константы. Смотрим пример:
HCRYPTPROV hProv;
HCRYPTKEY hSessionKey;
// Получение контекста криптопровайдера
// VPN_DEF_PROV и VPN_PROV_TYPE — указывают на то, что мы используем ViPNet CSP
if (!CryptAcquireContext(&hProv, NULL, VPN_DEF_PROV, VPN_PROV_TYPE, CRYPT_VERIFYCONTEXT))
<
printf(«Error CryptAcquireContext»);
return;
>
// Генерация сессионного ключа
// CPCSP_ENCRYPT_ID — используется ГОСТ 28147-89
if (!CryptGenKey(hProv, CPCSP_ENCRYPT_ID, CRYPT_ENCRYPT | CRYPT_DECRYPT, &hSessionKey))
<
printf(«Error CryptGenKey»);
return;
>
// Данные для шифрования
char data[]=»habrahabr»;
DWORD count=strlen(data);
// Тестовый вывод на экран
printf(«Encrypted string: %s», data);
// Тестовый вывод на экран
printf(«Decrypted string: %s», data);
// Освобождение контекста локальных переменных
CryptDestroyKey(hSessionKey);
CryptReleaseContext(hProv, 0);
Шифрование данных и расшифрование их на другом компьютере — тема отдельной статьи.
Спасибо за внимание.
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.
Использование Crypto API
Автор: Юрий Строжевский
свободный художник
Источник: RSDN Magazine #5-2004
Опубликовано: 23.04.2005
Исправлено: 10.12.2016
Версия текста: 2.0
Введение
Эта статья основана на моем личном опыте в деле написания программных продуктов криптографической направленности. Несмотря на данный, прежде всего коммерческий, опыт, здесь я постараюсь абстрагироваться от какого-то конкретного направления в Crypto API, и рассмотреть общий случай его применения.
Предполагается, что читатель знаком с некоторыми общими для криптографии понятиями: ключ шифрования, симметричные/ассиметричные алгоритмы шифрования, понятия протоколов шифрования и т.п. Также предполагается, что читатель имеет доступ к MSDN как можно более новой редакции.
Общие основы
Строение и возможности Crypto API
Прежде всего, постараемся описать круг задач, на решение которых ориентирован Crypto API:
- надежное сокрытие данных;
- возможность передачи сокрытых данных третьим лицам;
- надежная система проверки достоверности пришедшей от третьих лиц информации;
- расшифровывание полученных конфиденциальных данных;
- работа с «идентификационными удостоверениями» третьих лиц;
- обеспечение работы с признанными криптографическими стандартами;
- возможность расширения и работы с пока еще неизвестными алгоритмами.
Сперва я постараюсь рассмотреть решение задачи расширения. В Crypto API эту задачу решили довольно элегантно. Реализация всех алгоритмов (шифрования, цифровой подписи и т.п.) полностью выведена из состава самого Crypto API и реализуется в отдельных, независимых динамических библиотеках – «криптопровайдерах» (Cryptographic Service Provider – CSP). Сам же Crypto API просто предъявляет определенные требования к набору функций (интерфейсу) криптопровайдера и предоставляет конечному пользователю унифицированный интерфейс работы с CSP. Конечному пользователю для полноценного использования всех функций криптопровайдера достаточно знать его строковое имя и номер типа.
Кроме задачи расширения одной из основных задач Crypto API является возможность однозначной идентификации передающей/принимающей стороны в протоколе передачи данных. Общепризнанным решением в данном вопросе является использование механизма сертификатов. Сертификаты как бы стали «цифровыми паспортами», несущими информацию о своих владельцах. Полный рассказ о данном механизме последует несколько позже, а сейчас стоит упомянуть, что Crypto API также полно реализует весь спектр функций работы с ним. Большинство функций Crypto API, работающих с передаваемыми данными, так или иначе, используют сертификаты в своей работе.
В программных решениях рано или поздно встает вопрос стандартизации передаваемых между приложениями данных. В сфере криптографии для решения данного вопроса уже давно и успешно применяет набор стандартов «PKCS», предложенный компанией RSA Security. В данном комплекте стандартов учитываются все возможные случаи, возникающие в криптографических приложениях. Предусмотрены стандарты для обмена сертификатами, зашифрованными и подписанными данными и многое другое. Crypto API, как основная библиотека для обеспечения работы с криптографическими данными в Windows, также достаточно полно поддерживает данный комплект стандартов и позволяет формировать криптографические приложения, которые могут быть обработаны в дальнейшем любыми программными продуктами.
Таким образом, мы можем разделить весь интерфейс Crypto API на 5 функциональных групп:
1. Базовые криптографические функции:
- функции шифрования/расшифровывания данных;
- функции хеширования и получения цифровой подписи данных;
- функции инициализации криптопровайдера и работы с полученным контекстом;
- функции генерации ключей;
- функции обмена ключами.
2. Функции кодирования/декодирования. Под кодированием в данном случае подразумевается получение на выходе информации, кодированной в формате ASN.1 (Abstract Syntax Notation One).
3. Функции работы с сертификатами.
4. Высокоуровневые функции обработки криптографических сообщений.
5. Низкоуровневые функции обработки криптографических сообщений.
Криптопровайдеры
Криптопровайдером называют независимый модуль, обеспечивающий непосредственную работу с криптографическими алгоритмами. Каждый криптопровайдер должен обеспечивать:
- реализацию стандартного интерфейса криптопровайдера;
- работу с ключами шифрования, предназначенными для обеспечения работы алгоритмов, специфичных для данного криптопровайдера;
- невозможность вмешательства третьих лиц в схему работы алгоритмов.
Как уже говорилось выше, сами криптопровайдеры реализуются в виде динамически загружаемых библиотек (DLL). Таким образом, достаточно трудно повлиять на ход алгоритма, реализованного в криптопровайдере, поскольку компоненты криптосистемы Windows (все) должны иметь цифровую подпись (то есть подписывается и DLL криптопровайдера). У криптопровайдеров должны отсутствовать возможности изменения алгоритма через установку его параметров. Таким образом решается задача обеспечения целостности алгоритмов криптопровайдера. Задача обеспечения целостности ключей шифрования решается с использованием контейнера ключей, о котором рассказывается ниже.
Функции работы c криптопровайдерами можно разделить на следующие группы:
- функции инициализации контекста и получения параметров криптопровайдера;
- функции генерации ключей и работы с ними;
- функции шифрования/расшифровывания данных;
- Функции хеширования и получения цифровой подписи данных.
В группу функций инициализации контекста входят следующие функции:
- CryptAcquireContext . С помощью данной функции в первую очередь производится инициализация контекста криптопровайдера (получение ссылки на HANDLE, которую в дальнейшем можно использовать в других функциях). Также с помощью последнего параметра данной функции можно создать или удалить контейнер ключей.
- CryptContextAddRef . Данная функция служит для увеличения внутреннего счетчика ссылок криптопровайдера. Эту функцию рекомендуется использовать при передаче контекста криптопровайдера в качестве члена различных структур, передаваемых функциям.
- CryptReleaseContext . Данная функция предназначена для освобождения контекста криптопровайдера, полученного с помощью функции CryptAcquireContext . Фактически, производится только уменьшение внутреннего счетчика ссылок криптопровайдера (нечто вроде механизма подсчета ссылок у COM-объекта). Когда внутренний счетчик ссылок становится равным нулю, данный контекст криптопровайдера полностью освобождается и не может быть более нигде использован.
- CryptGetProvParam . С помощью этой функции можно получить значение различных параметров криптопровайдера. Нужно сказать, что для всех криптопровайдеров стандартом определен лишь ограниченный набор параметров. Набор параметров криптопровайдера может сильно варьироваться в зависимости от реализации криптопровайдера.
В группу генерации и работы с ключами входят следующие функции:
- CryptGenKey . Данная функция предназначена для генерации сессионного ключа (ключ, используемый только в течение текущей сессии работы), а также для генерации пар ключей для обмена (публичный и закрытый ключ) и цифровой подписи.
- CryptDuplicateKey . Функция предназначена для копирования ключа.
- CryptGetUserKey . Функция предназначена для получения значения публичного ключа для указанного контейнера ключей. Используется для получения значений публичных ключей, предназначенных для обмена ключами и цифровой подписи.
- CryptDestroyKey . Функция предназначена для освобождения ранее полученного хэндла ключа. Функцию следует вызывать всегда для предотвращения утечек памяти в приложении.
- CryptGetKeyParam . Функция предназначена для получения различных параметров ключа. В качестве параметров используются алгоритм ключа (его цифровой обозначение в системе), флаги разрешения использования ключа (например, если отсутствует установленный флаг ключа CRYPY_ENCYPT, данным ключом невозможно будет зашифровать данные), данные о длине блока ключа и многое другое. В практических реализациях данной функции следует уделять достаточно большое внимание, так как зачастую именно от параметров ключа зависит работа используемого алгоритма криптопровайдера.
- CryptSetKeyParam . Функция, обратная предыдущей. Используется для установки параметров ключа.
- CryptDeriveKey . Функция предназначена для генерации сессионного ключа на основе хеша данных. То есть данная функция генерирует один и тот же сессионный ключ, если ей передаются одинаковые значения хеша данных. Функция полезна в случае генерации сессионного ключа на основе пароля.
- CryptGenRandom . Функция используется для заполнения переданного ей буфера случайными данными. Используется, например, для генерации нового имени контейнера ключей.
- CryptExportKey . Функция экспорта ключа для его передачи по каналам информации. Возможны различные варианты передачи ключа, включая передачу публичного ключа пары ключей, а также передачу секретного или сессионного ключа.
- CryptImportKey . Функция, обратная предыдущей. Предназначена для получения из каналов информации значения ключа.
В группу функций шифрования/расшифровывания данных входят:
- CryptEncrypt . Основная базовая функция шифрования данных. В качестве параметров использует ранее полученные контексты криптопровайдера и сессионного ключа. Данные, генерируемые на выходе этой функции, не являются форматированными и не содержат никакой другой информации, помимо шифрованного контента (в отличие от, скажем, стандарта PKCS #7, использующего совместную передачу кодированных данных и экспортированного сессионного ключа).
- CryptDecrypt . Основная базовая функция расшифровывания данных. В качестве параметров используются ранее полученные контекст криптопровайдера и хэндл сессионного ключа.
В группу функций хеширования и получения цифровой подписи входят:
- CryptCreateHash . Функция создающая хеш-объект, предназначенный для генерации хеш-значения данных. В качестве основных параметров принимает ранее полученные контекст криптопровайдера и алгоритм формирования хеша данных.
- CryptHashData . Основная функция хеширования данных. Самым важным параметром этой функции является ссылка на хешируемые данные.
- CryptGetHashParam . Функция используется в основном для получения значения сформированного хеша данных. Функция CryptGetHashParam завершает процедуру создания хеш-значения, и дальнейшие вызовы функции CryptHashData будут возвращать ошибку.
- CryptSetHashParam . Функция используется для установки параметров хеша. Может быть использована, скажем, для изменения алгоритма формирования хеша.
- CryptDestroyHash . Функция используется для освобождения хеш-объекта.
- CryptDuplicateHash . Функция получения копии хеша. Используется при передаче хеша между функциями.
- CryptSignHash . Основная базовая функция получения цифровой подписи данных. Нужно отметить, что в Crypto API для уменьшения длины цифровой подписи (и ускорения работы ассиметричных алгоритмов, используемых для формирования цифровой подписи) в качестве входных данных используют хеш. Функций, использующих для получения цифровой подписи сами данные, в Crypto API нет.
- CryptVerifySignature . Основная базовая функция проверки цифровой подписи. В качестве входных данных опять-таки используется значение хеша.
В Crypto API криптопровайдеры принято группировать по их названиям (строковые величины), а также по номерам их типов. Тип криптопровайдера, в общем случае, ничего не сигнализирует обычному пользователю и служит лишь для вспомогательной группировки провайдеров. Исключение составляет тип PROV_RSA_FULL (его номер – 1), который присваивают себе только те криптопровайдеры, которые полностью поддерживают работу со стандартом RSA.
Сначала получим полный перечень строковых имен криптопровайдеров. Наиболее простым способом для этого является использование функции CryptEnumProviders :
Для перечисления типов криптопровайдеров, установленных в системе, можно использовать функцию CryptEnumProviderTypes :
Но, к сожалению, использование данных функций иногда вызывает трудности, так как в Windows 98 эти функции не работают. В качестве выхода из ситуации используют прямое обращение к реестру для перечисления как всех криптопровайдеров, так и их типов.
Пример перечисления криптопровайдеров с прямым обращением к реестру:
Пример перечисления типов криптопровайдеров при прямом обращении к реестру:
Контейнеры ключей
Контейнером ключей называют часть базы данных ключей, которая содержит пару ключей для обмена ключами и формирования цифровой подписи. В качестве контейнеров ключей (хранилищ пар ключей) используют, например, область временной памяти, участок реестра, файл на диске, смарт-карты. Контейнеры ключей в системе могут быть двух типов: пользовательские и уровня системы. Пользовательские контейнеры существуют в контексте работы текущего пользователя. По умолчанию доступа к ним больше никто не имеет (правда, существуют возможности выдачи доступа к контейнерам для других пользователей). Контейнеры ключей уровня системы используются, в основном, не в пользовательских программах, а, например, в сервисах (доступ к контейнерам ключей уровня системы возможен без интерактивной идентификации пользователя в системе). Контейнеры ключей не существуют сами по себе, а существуют только в контексте криптопровайдера. Для каждого криптопровайдера существует свой собственный набор контейнеров ключей. Это объясняется тем, что разные криптопровайдеры могут по-разному реализовывать даже один и тот же математический алгоритм. Следовательно, и способы хранения ключей могут также сильно варьироваться от криптопровайдера к криптопровайдеру.
Основными операциями с контейнерами ключей можно считать:
- Создание нового контейнера ключей. Выполняется посредством функции CryptAcquireContext , описанной ранее в разделе о криптопровайдерах. Для создания нового контейнера ключей в качестве последнего параметра данной функции передается значение CRYPT_NEWKEYSET. Необходимо также заметить, что исходно в новом контейнере ключей никаких данных не содержится, и пары ключей необходимо генерировать самостоятельно посредством вызова функции CryptGenKey , или импортировать.
- Удаление существующего контейнера ключей. Выполняется посредством вызова функции CryptAcquireContext с последним параметром, установленным в CRYPT_DELETEKEYSET.
- Генерация новой пары ключей. Выполняется посредством вызова функции CryptGenKey . При генерации пары ключей для обмена ключами третий параметр данной функции устанавливают в AT_KEYEXCHANGE, а при генерации пары ключей для формирования цифровой подписи – AT_SIGNATURE. Нужно заметить, что многие криптопровайдеры позволяют использовать пару ключей, созданную для обмена, также и для формирования цифровой подписи.
- Получение значения пары ключей. Выполняется посредством вызова функции CryptGetUserKey . Флаги, передаваемые в данную функцию, соответствуют флагам для генерации пары ключей.
- Установка параметров. Выполняется посредством вызова функции CryptSetProvParam . В основном устанавливают только один параметр – дескриптор безопасности контейнера ключей. Данный параметр используется, например, для выдачи доступа к контейнеру не только пользователю, создавшему контейнер. Остальные параметры контейнера ключей могут сильно варьироваться от криптопровайдера к криптопровайдеру, и обычно хорошо расписаны в документации, поставляемой непосредственно с криптопровайдером.
- Получение параметров. Выполняется посредством вызова функции CryptGetProvParam . Набор получаемых параметров также может сильно варьироваться в зависимости от криптопровайдера. В качестве интересного стандартного параметра можно назвать параметр PP_UNIQUE_CONTAINER. В качестве возвращаемого параметра передается уникальная (в масштабах всей системы) строка, идентифицирующая контейнер ключей. В частности, по этой строке часто можно узнать физическое расположение контейнера ключей (например, для контейнера ключей, расположенного в регистре системы, в начале возвращаемой строки будет «REGISTRY»).
- Перечисление контейнеров ключей. Выполняется отдельно для каждого криптопровайдера в системе с помощью вызова функции CryptGetProvParam c параметром dwParam установленным в PP_ENUMCONTAINERS.
Алгоритмы
В Crypto API все криптографические алгоритмы реализуются внутри криптопровайдеров. Таким образом, криптопровайдер позволяет устанавливать или получать различные параметры алгоритма, получать выходную информацию алгоритма и многое другое. Внутри Crypto API алгоритмы принято делить на следующие группы:
- алгоритмы шифрования/расшифровывания;
- алгоритмы получения значения хеша;
- алгоритмы получения цифровой подписи;
- алгоритмы обмена криптографическими ключами.
Для дальнейшего понимания сущности работы с алгоритмами необходимо также ввести понятия симметричных и ассиметричных алгоритмов шифрования. Симметричным алгоритмом называют алгоритм, в котором для шифрования и расшифровывания используется один и тот же ключ. Ассиметричными называют алгоритмы, в которых используется пара ключей (в общем случае может быть и более двух ключей), один из которых используется для шифрования (и только для шифрования) информации, а другой – для расшифровывания. В качестве ассиметричных алгоритмов принято применять так называемые алгоритмы с открытым ключом. В таких алгоритмах существует пара ключей – открытый (публичный) и закрытый (секретный) ключи. В большинстве случаев для шифрования информации используется публичный ключ, а для расшифровывания – секретный. Публичный ключ не является предметом секретности и предназначен для передачи по открытым каналам. Лицо, получившее публичный ключ, может зашифровать им данные и отослать их по тем же открытым каналам лицу, владеющему секретным ключом. В свою очередь на стороне получателя расшифровывание возможно только при наличии секретного ключа из той пары ключей, к которой принадлежит публичный ключ, применявшийся для шифрования. Таким образом, достигается возможность обмениваться шифрованными сообщениями, не заботясь о том, что ключ может быть перехвачен в процессе пересылки.
Ассиметричные алгоритмы в обычной жизни мало применимы. Причина тому – высокая трудоемкость шифрования, обусловленная повышенной сложностью ассиметричных алгоритмов. Обычно используют следующую схему: шифрование данных выполняется симметричным криптографическим алгоритмом некоторым сгенерированным для этого сессионным ключом. Затем для передачи получателю этот ключ шифруется с помощью асимметричного алгоритма (длина ключа несущественно мала по сравнению с возможным размером данных). На стороне получателя с помощью асимметричного алгоритма расшифровывается сессионный ключ, который используется для расшифровывания полученных данных с помощью симметричного алгоритма. Такой способ передачи шифрованной информации позволяет использовать преимущества обоих подходов.
Именно такой подход использован во всех ключевых алгоритмах работы Crypto API. Контейнеры ключей хранят пары ключей, необходимые для обмена сессионными ключами, а для непосредственно шифрования данных необходимо каждый раз генерировать новые сессионные ключи.
Рассмотрим основные операции, выполняемые над алгоритмами в Crypto API:
- Перечисление всех криптографических алгоритмов. Выполняется посредством вызова функции CryptGetProvParam с параметром dwParam, установленным в PP_ENUMALGS.
- Получение параметров алгоритмов. Обычно выполняется прямо во время перечисления алгоритмов посредством вызова функции CryptGetProvParam с параметром dwParam установленным в PP_ENUMALGS_EX. В этом случае получаемая структура может содержать практически всю информацию об алгоритме.
Зачастую также требуется найти криптопровайдер, реализующий некий известный нам алгоритм. Для идентификации алгоритмов в пределах системы все алгоритмы криптопровайдеров имеют уникальный цифровой номер. Данный номер в системе имеет тип ALG_ID и представляет собой простое число типа DWORD. Наряду с нумерацией алгоритмов на основе ALG_ID существует и другой идентификатор – OID. Данный идентификатор пришел из спецификаций криптографических стандартов фирмы RSA Security и представляет собой строку, состоящую из групп цифр, разделенных точками. В стандартах жестко закреплено значение каждой группы цифр в OID, и по данному номеру можно получить некоторую дополнительную информацию (например, фирму-разработчика алгоритма). Преобразование между типами номеров алгоритмов осуществляется функциями CertAlgIdToOID и CertOIDToAlgId .
Сертификаты
Полное пояснение по данному понятию будет дано в отдельном разделе. Здесь же о сертификатах упомянуто, поскольку сертификаты все-таки используются в высокоуровневых функциях обработки криптографических сообщений типа CryptSignMessage . Пока важно понимать, что сертификаты в системе используются для:
- хранения дополнительной информации о владельце сертификата;
- хранения значения публичного ключа владельца;
- получения ссылки на контейнер ключей. С сертификатом, установленным в системе, может быть физически связан контейнер ключей. То есть, имея только ссылку на контекст сертификата можно установить однозначную связь с секретным ключом и использовать это, например, при проверке цифровой подписи или расшифровывании данных.
В упрощенном виде сертификаты можно считать некоторыми удостоверениями личности. Правами выдавать сертификаты (как и паспорта), в идеале должны обладать только доверенные центры (например, ФСБ или милиция). Но, в принципе, можно генерировать сертификаты и самому. В этом случае тот пользователь, который будет использовать данный сертификат, вправе либо доверять, либо не доверять сертификату («. паспорт можно и самому нарисовать. »). Для целей дальнейшего изучения высокоуровневых функций обработки криптографической информации нам важны лишь два последних случая использования сертификатов из перечисленных: сертификаты хранят публичный ключ и могут быть связаны с контейнером ключей, в котором хранится секретный ключ. Этой информации на данном этапе будет достаточно.
Если вы не имели опыта работы с сертификатами, то для ознакомления с ними, можно вызвать Internet Explorer, выбрать в его меню пункт «Сервис / Свойства обозревателя» («Tools / Internet Options»), а затем на закладке «Содержание» («Content») нажать на кнопку «Сертификаты» («Certificates»). Вашему вниманию будет представлен список сертификатов, установленных в системе.
Базовые функции
Шифрование
Базовая функция шифрования данных имеет следующее объявление:
Первым параметром данной функции передается хендл сессионного ключа, применяемого для шифрования. Второй параметр достаточно редко используется и предназначен для получения хеша данных одновременно с их шифрованием. Такая возможность достаточно полезна при формировании одновременно как шифрованных данных, так и цифровой подписи этих же данных.
Эта функция может обрабатывать данные блоками. То есть нет необходимости сразу загружать в память целиком весь массив данных, а лишь потом передавать ссылку на него криптографической функции. Достаточно передавать массив данных поблочно, специальным образом отметив лишь последний блок данных (это обычно нужно, чтобы криптопровайдер провел некоторые действия после использования сессионного ключа). Для указания того, что это последний блок данных, в функции CryptEncrypt используется третий параметр Final . Четвертый параметр служит указателем на массив входных/выходных данных. Здесь нужно сразу отметить некоторую общую схему работы с данными в Crypto API. Если возвращаемые данные могут быть любого размера (а это возможно, ведь, скажем, в алгоритме может происходить простая замена, когда одна буква кодируется четырьмя цифрами), то работа с функцией состоит из двух этапов. На первом этапе в функцию передается общий размер входных данных и NULL в качестве ссылки на сам массив выходных данных. Функция возвращает длину выходного массива данных, пользователь инициализирует память необходимого размера и лишь затем заново передает функции ссылку на этот массив. Такая же схема используется и в работе с функцией CryptEncrypt . Параметр pdwDataLen служит для возврата размера данных, возвращаемых функцией. Параметр dwBufLen служит для указания длины входного буфера данных. Параметр dwFlags обычно не используется и устанавливается в 0.
Пример использования функции CryptEncrypt приведен ниже:
Экспорт сессионных ключей
После выполнения операции шифрования встает проблема передачи шифрованных данных. Сами по себе данные, конечно, передавать можно, вследствие их защищенности. Но напомним еще раз, что в Crypto API используются симметричные алгоритмы шифрования, и если на принимающей стороне не будет использован тот же самый сессионный ключ, который был использован для шифрования, то расшифровать данные на принимающей стороне не удастся. В самих шифрованных данных Crypto API самостоятельно сессионные ключи также не передает. Вместо этого Crypto API предоставляет развитые механизмы экспорта значения сессионного ключа во внешний массив данных.
Базовая функция экспорта ключей имеет следующее описание:
Первым параметром данной функции передается хендл ключа, который будет экспортирован. Фактически, экспорт ключа можно представить как отдельную операцию шифрования ключа. Следовательно, для такой операции необходим еще один ключ шифрования. Обычно в Crypto API сессионный ключ шифруют с помощью асимметричного алгоритма. Параметр hExpKey в большинстве случаев инициализируют контекстом публичного ключа получателя. Параметр dwBlobType определяет формат получаемого блока экспорта. Возможно, скажем, указать, что экспорту будет подлежать только лишь публичный ключ. В этом случае параметр hExpKey должен быть равен 0 (шифрование публичного ключа не нужно) и на выходе функции получается простое значение публичного ключа. Для такого случая параметр dwBlobType должен быть равен PUBLICKEYBLOB. Обычно же, при экспорте сессионного ключа используется значение SIMPLEBLOB. Остальные значения данного параметра достаточно специфичны и применяются редко. Параметры pbData и pdwDataLen указывают на массив, выделенный для получения экспортируемого ключа, и на его размер.
СОВЕТ Хотелось бы также обратить внимание читателя на достаточно важный момент: иногда для обмена ключами используются несколько более сложные схемы, чем просто шифрование данных сессионного ключа публичным ключем. Примером подобной усложненной схемы обмена может служить алгоритм обмена ключами по методу Диффи-Хеллмана. В данном алгоритме используются оба публичных ключа – как отправителя, так и получателя. Более подробную информацию о данном алгоритме читатель может найти в специализированной литературе. Пример использования этой функции приведен ниже: Импорт сессионных ключейБазовая функция импорта ключей имеет следующее описание: В качестве первого параметра в данную функцию передается инициализированный контекст криптопровайдера. Должен отметить, что для успешного завершения работы функции CryptImportKey необходимо, чтобы при инициализации криптопровайдера был указан контейнер ключей. В частности, это необходимо для успешного импорта секретных ключей в контейнер ключей. Параметр pbData представляет собой ссылку на импортируемые данные, параметр dwDataLen – длину этих данных. В параметре hPubKey указывают хендл ключа, применяемого при импорте (для расшифровывания сессионного ключа). Параметр dwFlags обычно не применяется и может быть установлен в 0. В параметре phKey возвращается импортированный ключ. Пример использования данной функции приведен ниже: РасшифровываниеБазовая функция расшифровывания имеет следующее описание: Первым параметром данной функции передается инициализированный контекст сессионного ключа, применяемого для расшифровывания данных. Второй параметр, как и в предыдущем примере, связан, по большей части, с функцией получения и проверки цифровой подписи. Обычно он не используется и устанавливается в 0. Параметр dwFlags чаще всего не используется и также устанавливается в 0. Параметры pbData и pdwDataLen используются точно так же, как и у CryptEncrypt и представляют собой ссылку на входной/выходной массив данных и длину этого массива данных. Пример использования функции CryptDecrypt приведен ниже: ХешированиеПод хешированием понимают применение некоторой математической функции (называемой хеш-функцией) к некоторым данным. При применении хеш-функции к произвольному объему данных всегда получается массив данных фиксированного размера. К хеш-значению предъявляется требование «устойчивости к коллизиям». Это значит, что хеш-функция тем лучше, чем труднее найти два таких случайных входных массива данных, для которых совпадали бы генерируемые хеш-значения. При обработке одних и тех же данных хеш-функция обязана возвращать одно и то же хеш-значение. Это свойство хеш-функций используется, прежде всего, для контроля над целостностью данных. Ведь если мы изменим хоть бит во входном массиве информации, то результат работы хеш-функции (с высокой вероятностью) будет другим. В Crypto API для манипуляции с хэшем используется специальный хэш-объект. Взаимодействие с этим объектом осуществляется с помощью следующих трех функций:
Для первичной инициализации хэш-объекта применяют функцию CryptCreateHash . Данная функция имеет следующее описание: В качестве первого параметра данной функции передается инициализированный контекст криптопровайдера. Вторым параметром указывается алгоритм получения значения хеша. Параметр hKey необходим лишь в случае применения специализированных алгоритмов типа MAC и HMAC .
|