Какую роль играет библиотека crypt32 dll в работе криптопровайдера

Обновлено: 06.07.2024

В сфере защиты компьютерной информации криптография применяется в основном для: шифрования и дешифровки данных; а также создания и проверки цифровых подписей. (Прим. автора: в русскоязычной литературе применяется термин «ЭЦП» - электронно-цифровая подпись. В этой статье для краткости используется термин «цифровая подпись».)

Шифрование данных позволяет ограничить доступ к конфиденциальной информации, сделать ее нечитаемой и непонятной для посторонних. Применение цифровых подписей оставляет данные открытыми, но дает возможность верифицировать отправителя и проверять целостность полученных данных.

Для защиты информации специалистами Microsoft был разработан интерфейс CryptoAPI, который позволяет создавать приложения, использующие криптографические методы.

Структура CryptoAPI

В Crypto API существует понятие «криптопровайдер» (Cryptography Service Provider, CSP). Криптопровайдер - это независимый модуль, содержащий библиотеку криптографических функций со стандартизованным интерфейсом. Криптопровайдер отвечает за реализацию функций интерфейса, а также играет роль хранилища для ключей всех типов. Подобная архитектура позволяет переходить от одного провайдера к другому с минимальными изменениями исходного кода, так как интерфейс (т. е. сами функции) не меняется.

В операционную систему Windows включен криптопровайдер Microsoft RSA Base Provider.

Криптографические ключи

В CryptoAPI существуют ключи двух типов:

  • сессионные ключи (session keys
  • пары открытый/закрытый ключ (public/private key pairs).

Сессионные ключи. Это симметричные ключи, так как один и тот же ключ применяется и для шифрования, и для расшифровки. Сессионные ключи меняются. Алгоритмы, использующие сессионные ключи (так называемые симметричные алгоритмы), - RC2, RC4, DES. Microsoft RSA Base Provider работает с 40-разрядными сессионными ключами.

Пары ключей используются в так называемых асимметричных алгоритмах шифрования. Если шифрование выполнялось одним ключом из пары, то дешифровка производится другим. Открытые (public) ключи могут передаваться другим лицам для проверки цифровых подписей и шифрования пересылаемых данных. Длина открытого ключа в Microsoft RSA Base Provider составляет 512 разрядов.

Закрытые (private) ключи не могут быть экспортированы; они используются для создания цифровых подписей и дешифровки данных. Закрытый ключ должен быть известен только его владельцу.

Хранение ключей

Криптопровайдер отвечает за хранение и разрушение ключей. Программист не имеет доступа непосредственно к двоичным данным ключа, за исключением операций экспорта открытых ключей. Вся работа с ключами производится через дескрипторы (handle).

В CryptoAPI ключи для шифрования/дешифровки и создания/проверки подписей разделены. Называются они соответственно «пара для обмена ключами» и «пара для подписи».

База данных ключей состоит из контейнеров, в каждом из которых хранятся ключи, принадлежащие определенному пользователю. Контейнер ключей имеет уникальное имя и содержит пару для обмена и пару для подписи. Все ключи хранятся в защищенном виде.

По умолчанию для каждого пользователя создается контейнер с именем этого пользователя. Можно создавать дополнительные контейнеры и назначать им произвольные имена, которые обязательно должны быть уникальными (см. Рисунок 1).

Работа с CryptoAPI

Ниже приводятся примеры работы с некоторыми функциями CryptoAPI. Все примеры написаны на языке С++ в среде MS Visual C++ 6.0. Приведены прототипы наиболее интересных функций с пояснениями. Чтобы не перегружать читателя деталями, обработка ошибок в листинги не включена.

Названия функций CryptoAPI имеют префикс Crypt. Как правило, все они возвращают результат типа BOOL - TRUE при успешном завершении и FALSE, если произошла ошибка. В последнем случае для получения сведений об ошибке необходимо вызвать GetLastError().

Прототипы функций описаны в файле wincrypt.h. Для использования этих функций в свойствах проекта нужно определить константу _WIN32_WINNT и задать ей значение 0x0400 (или больше). Данная константа применяется в файле wincrypt.h для проверки версии Windows.

Для некоторых функций CryptAPI также требуются библиотеки crypt32.lib и advapi32.lib.

Криптопровайдер

Прежде чем использовать какие-либо функции Crypto API, необходимо запустить криптопровайдер. Делается это с помощью функции CryptAc-quireContext:

Кроме инициализации криптопровайдера данную функцию можно использовать для создания и удаления контейнеров ключей. Для этого параметру dwFlags присваивается значение, соответственно, CRYPT_NEW-KEYSET и CRYPT_DELETEKEYSET.

Функция CryptAcquireContext работает в два этапа: сначала она ищет криптопровайдер по имени и типу, указанному в аргументах, а затем контейнер ключей с заданным именем.

По окончании работы с криптопровайдером необходимо вызвать функцию CryptReleaseContext (см. Листинг 1).

Работа с ключами

Генерация ключей. В CryptoAPI имеются функции для генерации ключей любого типа. Функция CryptGenKey генерирует сессионные ключи и пары для обмена и подписи на основе случайного числа.

Сессионные ключи можно сгенерировать также на основе некоторого заданного значения (пароля) при помощи функции CryptDeriveKey. Это стоит делать, например, в том случае, когда нужно избежать пересылки сессионного ключа вместе с зашифрованными данными (см. Рисунок 2). Получатель данных, зная пароль и алгоритм, может сам сгенерировать сессионный ключ и с его помощью расшифровать данные (см. Листинг 2).

Получение дескриптора ключа. Дескриптор открытого ключа можно получить, вызвав функцию CryptGet-UserKey.

Экспорт ключей. Операция экспорта выполняется при сохранении сессионных ключей и при передаче ключей третьим лицам.

Двоичные данные ключа могут быть получены при помощи функции CryptExportKey:

Поясним значения аргументов. Первый аргумент - дескриптор экспортируемого ключа. Второй аргумент - дескриптор ключа, которым шифруется экспортируемый ключ.

Открытые ключи экспортируются в незашифрованном виде. В этом случае hCryptKey = 0.

При экспорте сессионных и закрытых ключей необходимо их предварительно зашифровать. Аргумент hCryptKey должен содержать дескриптор открытого ключа получателя.

При вызове с аргументом pbData = NULL функция вернет необходимую длину буфера по адресу, на который указывает аргумент pdwDataLen (см. Листинг 3).

После успешного завершения переменная dwSessionKeyLen будет содержать действительную длину BLOB-структуры ключа. Это значение необходимо сохранить для обратной операции - импорта ключа в криптопровайдер.

Импорт ключей. Ключи импортируются функцией CryptImportKey:

hCryptKey = 0 в том случае, если импортируемый ключ был зашифрован асимметричным ключом или не был зашифрован вообще.

Если импортируемый ключ шифровали сессионным ключом, то hCryptKey должен содержать дескриптор этого ключа.

По окончании работы с ключом необходимо для его дескриптора вызвать функцию CryptDestroyKey(HCRYPTKEY hKey).

Шифрование и дешифровка данных

В CryptoAPI для шифрования и дешифровки используются и симметричный, и асимметричный алгоритмы.

Симметричный алгоритм менее надежен, но работает намного быстрее, чем асимметричный. Поэтому в CryptoAPI применяется комбинация алгоритмов. Данные шифруются с помощью симметричного алгоритма с сессионным ключом, а сам сессионный ключ шифруется по асимметричному алгоритму открытым ключом получателя. Дешифровка происходит в обратном порядке: сначала закрытым ключом получателя дешифруется сессионный ключ, затем этим сессионным ключом дешифруются сами данные (см. Рисунки 2 и 3).

Таким образом, расшифровать данные можно только, имея закрытый ключ из той же ключевой пары, что и открытый ключ, которым данные были зашифрованы.

Для шифрования и дешифровки применяется функция (см. Листинг 4).

Последний и предпоследний параметры являются одновременно входными и выходными. Это означает, что зашифрованные данные записываются поверх исходных в буфер pbData, а длина данных, соответственно, в dwBufferLen.

Как и в случае с функцией Crypt-ExportKey, CryptEncrypt позволяет предварительно определить необходимый размер буфера под зашифрованные данные. Для этого нужно вызвать функцию с аргументами:

Длину буфера функция вернет по адресу: pdwDataLen.

Дешифровка данных производится аналогично функцией CryptDecrypt.

Цифровые подписи

Цифровая подпись - это двоичные данные небольшого объема, обычно не более 256 байт. Цифровая подпись есть не что иное, как результат работы хеш-алгоритма над исходными данными, зашифрованный закрытым ключем отправителя. Проще говоря, берем исходные данные, получаем из них хеш и шифруем хеш своим закрытым ключом (с помощью асимметричного алгоритма).

Полученные в результате шифрования хеша двоичные данные и есть наша цифровая подпись (см. Рисунок 4).

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

  • получает хеш от данных (данные остались открытыми);
  • расшифровывает нашу цифровую подпись при помощи нашего открытого ключа;
  • сравнивает свой хеш и результат дешифровки. Если они эквивалентны, значит, данные были подписаны именно нами (ну, по крайней мере, нашим закрытым ключом, см. Рисунок 5).

Подобный алгоритм позволяет любому лицу проверить подлинность подписи отправителя. Напомню, что открытый ключ отправителя, с помощью которого собственно и производится проверка, распространяется (как правило) свободно.

Для работы с цифровыми подписями используются функции CryptCreate-Hash, CryptHashData, CryptSignHash, CryptVerifySignature, CryptDestroy-Hash.

Создание цифровой подписи. Процесс создания подписи состоит из следующих этапов:

  • создание хеш-объекта функцией CryptCreateHash;
  • наполнение хеш-объекта данными (CryptHashData);
  • подписание хеша (CryptSignHash);
  • разрушение хеш-объекта (Crypt-DestroyHash).

Аналогично функциям CryptEncrypt, проверка длины буфера для подписи производится вызовом функции CryptSignHash с нулем вместо указателя на данные. Как и у функции CryptEncrypt, указатели на данные и их длину являются параметрами типа [in, out] (см. Листинг 5).

Проверка цифровой подписи. Проверка подписи (см. Листинг 6) выполняется так:

Шифрование данных позволяет ограничить доступ к конфиденциальной информации, сделать ее нечитаемой и непонятной для посторонних. Применение цифровых подписей оставляет данные открытыми, но дает возможность верифицировать отправителя и проверять целостность полученных данных.

Для защиты информации специалистами Microsoft был разработан интерфейс CryptoAPI, который позволяет создавать приложения, использующие криптографические методы.

Структура CryptoAPI

В операционную систему Windows включен криптопровайдер Microsoft RSA Base Provider.

Криптографические ключи

В CryptoAPI существуют ключи двух типов:

  • сессионные ключи (session keys
  • пары открытый / закрытый ключ (public/private key pairs).

Пары ключей используются в так называемых асимметричных алгоритмах шифрования. Если шифрование выполнялось одним ключом из пары, то дешифровка производится другим. Открытые (public) ключи могут передаваться другим лицам для проверки цифровых подписей и шифрования пересылаемых данных. Длина открытого ключа в Microsoft RSA Base Provider составляет 512 разрядов.

Закрытые (private) ключи не могут быть экспортированы; они используются для создания цифровых подписей и дешифровки данных. Закрытый ключ должен быть известен только его владельцу.

Хранение ключей

Криптопровайдер отвечает за хранение и разрушение ключей. Программист не имеет доступа непосредственно к двоичным данным ключа, за исключением операций экспорта открытых ключей. Вся работа с ключами производится через дескрипторы (handle).

В CryptoAPI ключи для шифрования/дешифровки и создания/проверки подписей разделены. Называются они соответственно «пара для обмена ключами» и «пара для подписи».

База данных ключей состоит из контейнеров, в каждом из которых хранятся ключи, принадлежащие определенному пользователю. Контейнер ключей имеет уникальное имя и содержит пару для обмена и пару для подписи. Все ключи хранятся в защищенном виде.

По умолчанию для каждого пользователя создается контейнер с именем этого пользователя. Можно создавать дополнительные контейнеры и назначать им произвольные имена, которые обязательно должны быть уникальными (см. Рисунок 1).


Рисунок 1. База данных криптографических ключей.

Работа с CryptoAPI

Ниже приводятся примеры работы с некоторыми функциями CryptoAPI. Все примеры написаны на языке С++ в среде MS Visual C++ 6.0. Приведены прототипы наиболее интересных функций с пояснениями. Чтобы не перегружать читателя деталями, обработка ошибок в листинги не включена.

Прототипы функций описаны в файле wincrypt.h. Для использования этих функций в свойствах проекта нужно определить константу _WIN32_WINNT и задать ей значение 0x0400 (или больше). Данная константа применяется в файле wincrypt.h для проверки версии Windows.

Для некоторых функций CryptAPI также требуются библиотеки crypt32.lib и advapi32.lib.

Криптопровайдер

Прежде чем использовать какие-либо функции Crypto API, необходимо запустить криптопровайдер. Делается это с помощью функции CryptAc-quireContext:

Кроме инициализации криптопровайдера данную функцию можно использовать для создания и удаления контейнеров ключей. Для этого параметру dwFlags присваивается значение, соответственно, CRYPT_NEW-KEYSET и CRYPT_DELETEKEYSET.

Функция CryptAcquireContext работает в два этапа: сначала она ищет криптопровайдер по имени и типу, указанному в аргументах, а затем контейнер ключей с заданным именем.

По окончании работы с криптопровайдером необходимо вызвать функцию CryptReleaseContext ( см . Листинг 1).

Работа с ключами

Генерация ключей. В CryptoAPI имеются функции для генерации ключей любого типа. Функция CryptGenKey генерирует сессионные ключи и пары для обмена и подписи на основе случайного числа.

Сессионные ключи можно сгенерировать также на основе некоторого заданного значения (пароля) при помощи функции CryptDeriveKey. Это стоит делать, например, в том случае, когда нужно избежать пересылки сессионного ключа вместе с зашифрованными данными (см. Рисунок 2). Получатель данных, зная пароль и алгоритм, может сам сгенерировать сессионный ключ и с его помощью расшифровать данные (см. Листинг 2).


Рисунок 2. Шифрование.

Получение дескриптора ключа. Дескриптор открытого ключа можно получить, вызвав функцию CryptGet-UserKey.

Экспорт ключей. Операция экспорта выполняется при сохранении сессионных ключей и при передаче ключей третьим лицам.

Двоичные данные ключа могут быть получены при помощи функции CryptExportKey:

Открытые ключи экспортируются в незашифрованном виде. В этом случае hCryptKey = 0.

При экспорте сессионных и закрытых ключей необходимо их предварительно зашифровать. Аргумент hCryptKey должен содержать дескриптор открытого ключа получателя.

При вызове с аргументом pbData = NULL функция вернет необходимую длину буфера по адресу, на который указывает аргумент pdwDataLen (см. Листинг 3).

Импорт ключей. Ключи импортируются функцией CryptImportKey:

hCryptKey = 0 в том случае, если импортируемый ключ был зашифрован асимметричным ключом или не был зашифрован вообще.

Если импортируемый ключ шифровали сессионным ключом, то hCryptKey должен содержать дескриптор этого ключа.

По окончании работы с ключом необходимо для его дескриптора вызвать функцию CryptDestroyKey(HCRYPTKEY hKey).

Шифрование и дешифровка данных

В CryptoAPI для шифрования и дешифровки используются и симметричный, и асимметричный алгоритмы.

Симметричный алгоритм менее надежен, но работает намного быстрее, чем асимметричный. Поэтому в CryptoAPI применяется комбинация алгоритмов. Данные шифруются с помощью симметричного алгоритма с сессионным ключом, а сам сессионный ключ шифруется по асимметричному алгоритму открытым ключом получателя. Дешифровка происходит в обратном порядке: сначала закрытым ключом получателя дешифруется сессионный ключ, затем этим сессионным ключом дешифруются сами данные (см. Рисунки 2 и 3).


Рисунок 3. Дешифровка.

Таким образом, расшифровать данные можно только, имея закрытый ключ из той же ключевой пары, что и открытый ключ, которым данные были зашифрованы.

Для шифрования и дешифровки применяется функция (см. Листинг 4).

Последний и предпоследний параметры являются одновременно входными и выходными. Это означает, что зашифрованные данные записываются поверх исходных в буфер pbData, а длина данных, соответственно, в dwBufferLen.

Как и в случае с функцией Crypt-ExportKey, CryptEncrypt позволяет предварительно определить необходимый размер буфера под зашифрованные данные. Для этого нужно вызвать функцию с аргументами:

Длину буфера функция вернет по адресу: pdwDataLen.

Дешифровка данных производится аналогично функцией CryptDecrypt.

Цифровые подписи

Полученные в результате шифрования хеша двоичные данные и есть наша цифровая подпись (см. Рисунок 4).


Рисунок 4. Создание цифровой подписи.

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

  • получает хеш от данных (данные остались открытыми);
  • расшифровывает нашу цифровую подпись при помощи нашего открытого ключа;
  • сравнивает свой хеш и результат дешифровки. Если они эквивалентны, значит, данные были подписаны именно нами (ну, по крайней мере, нашим закрытым ключом, см. Рисунок 5).


Рисунок 5. Проверка цифровой подписи.

Подобный алгоритм позволяет любому лицу проверить подлинность подписи отправителя. Напомню, что открытый ключ отправителя, с помощью которого собственно и производится проверка, распространяется (как правило) свободно.

Для работы с цифровыми подписями используются функции CryptCreate-Hash, CryptHashData, CryptSignHash, CryptVerifySignature, CryptDestroy-Hash.

Создание цифровой подписи. Процесс создания подписи состоит из следующих этапов:

  • создание хеш-объекта функцией CryptCreateHash;
  • наполнение хеш-объекта данными (CryptHashData);
  • подписание хеша (CryptSignHash);
  • разрушение хеш-объекта (Crypt-DestroyHash).

Аналогично функциям CryptEncrypt, проверка длины буфера для подписи производится вызовом функции CryptSignHash с нулем вместо указателя на данные. Как и у функции CryptEncrypt, указатели на данные и их длину являются параметрами типа [in, out] (см. Листинг 5).

Проверка цифровой подписи. Проверка подписи (см. Листинг 6) выполняется так:

  • создается хеш-объект функцией CryptCreateHash;
  • хеш-объект наполняется данными (CryptHashData);
  • подпись расшифровывается и результат сравнивается со «своим» хешем (CryptVerifySignature);
  • хеш-объект разрушается (CryptDes-troyHash).

Криптопровайдер ( Cryptographic Service Provider , CSP ) - это независимый программный модуль , интегрированный в MS Windows и содержащий библиотеку криптографических функций со стандартизованным интерфейсом. Криптопровайдер предназначен для авторизации , обеспечения конфиденциальности и юридической значимости электронных документов при обмене ими между пользователями, контроля целостности информации и др.

Каждый криптопровайдер должен обеспечивать [9.3]:

  • реализацию стандартного интерфейса криптопровайдера ;
  • работу с ключами шифрования , предназначенными для обеспечения работы алгоритмов, специфичных для данного криптопровайдера ;
  • невозможность вмешательства третьих лиц в схему работы алгоритмов.

Криптопровайдеры реализуются в виде динамически загружаемых библиотек ( DLL ). Целостность алгоритмов криптопровайдера обеспечивает отсутствие возможности изменения алгоритма через установку его параметров. Кроме того, DLL криптопровайдера должна иметь цифровую подпись .

Кроме различия в реализуемых стандартах, криптопровайдеры отличаются способом физической организации ключевой базы. С точки зрения программирования, способ физической организации ключевой базы значения не имеет. Однако он весьма важен с точки зрения эксплуатации и безопасности системы . Криптопровайдеры могут хранить свою ключевую базу на жестком диске (в Реестре или в файлах) или на смарт-картах. Тем не менее, логическая структура организации ключевой базы, которая, в отличие от физической, определяется самим интерфейсом, для всех криптопровайдеров одинакова. Ключевая база представляется набором ключевых контейнеров (см. рис. 9.1). Каждый ключевой контейнер имеет имя, которое присваивается ему при создании, а затем используется для работы с ним. В ключевом контейнере сохраняется долговременная ключевая информация . В криптопровайдерах Microsoft долговременными являются ключевые пары цифровой подписи и несимметричного обмена ключами, которые также генерируются функциями CryptoAPI .

Криптопровайдер выполняет следующие криптографические функции:

  • формирование/проверка электронной цифровой подписи ( ЭЦП ),
  • шифрование информации,
  • хранение ключей всех типов.

Каждый криптопровайдер характеризуется собственным именем и типом. Имя - это строка, по которой система распознает криптопровайдер . Тип криптопровайдера - это целое число , значение которого идентифицирует набор поддерживаемых алгоритмов [9.2]. В общем случае, тип криптопровайдера ничего не сигнализирует обычному пользователю и служит лишь для вспомогательной группировки провайдеров . Исключение составляет тип PROV_RSA_FULL (его номер - 1), который присваивают себе только те криптопровайдеры , которые полностью поддерживают работу со стандартом RSA .

В составе ОС Windows пользователь получает несколько CSP , которые реализуют наиболее часто используемые методы шифрования . Наряду со стандартными криптопровайдерами , поставляемыми Microsoft (см. табл. 9.1), можно использовать CSP собственной разработки, предварительно сертифицировав его. Например, согласно действующему на территории России законодательству, если организация использует стандартные криптопровайдеры Windows (несертифицированные в России криптографические алгоритмы шифрования и ЭЦП данных), она не может вести обмен документами с государственными учреждениями. Обеспечить юридическую значимость электронных документов при обмене ими между пользователями позволит использование сертифицированного ФСБ криптопровайдера .

Data Protection API (DPAPI)

. NET 2.0 включает отдельные функции для защиты секретной информации на локальной машине или для каждого пользователя посредством полностью управляемых оболочек программного интерфейса Windows Data Protection API ( DPAPI ).

Любое приложение , работающее под ОС Windows , может защитить свои данные посредством обращения к соответствующим функциям DPAPI . DPAPI - простой в использовании сервис, полезный разработчикам, когда нужно обеспечить защиту секретных данных приложения - например, паролей или ключей.

Схема работы DPAPI

Интерфейс DPAPI является частью crypt32. dll и доступен всем процессам, загрузившим эту библиотеку; crypt32. dll , в свою очередь , является частью CryptoAPI . Приложение либо передает открытый текст DPAPI и получает результат зашифрования, либо передает зашифрованный блок бинарных данных и получает результат расшифрования. Процесс схематически изображен на рис. 9.5 [9.9].

Когда приложение обращается к функциям DPAPI , происходит локальный вызов удаленных процедур ( Remote Procedure Call , RPC ) локального доверенного центра Local Security Authority ( LSA ). LSA - это системный процесс, существующий с момента загрузки системы вплоть до выключения компьютера . Локальные RPC -вызовы никогда не проходят по сети, поэтому все данные остаются на локальной машине. Конечные точки этих RPC -вызовов - это обращение в private -функциям DPAPI для скрытия или раскрытия данных. Непосредственно зашифрование/ расшифрование данных в контексте безопасности LSA эти функции осуществляют посредством обратного вызова CryptoAPI через crypt32. dll .

LSA также включает функции системного уровня для работы с DPAPI . Эти функции доступны любым потокам, запущенным внутри этого LSA , и только им, позволяя LSA -потокам защищать пользовательские данные, которые не должны быть доступны другим потокам, также использующим DPAPI - например, пользовательским приложениям.

Интерфейс DPAPI ориентирован на защиту данных пользователей . Для этого используются учетные записи ( мандаты ) пользователей. Обычно в системе, поддерживающей парольную аутентификацию , мандат представляет собой хеш от пароля пользователя. При использовании смарт-карты способ вычисления мандата другой, но мы для простоты ограничимся рассмотрением первого случая.

Чтобы предотвратить ситуацию, когда каждое приложение имеет доступ не только к своим данным, но и к данным всех других приложений, работающих под учетной записью определенного пользователя, DPAPI позволяет приложениям использовать дополнительный "секрет" для защиты своих данных, знание которого необходимо для их расшифрования. Этот "секрет" можно назвать "вторичной энтропией " ( secondary entropy ): "вторичность" означает, что "секрет" не повышает стойкость ключа шифрования , однако затрудняет доступ к данным для приложений, работающих под той же учетной записью пользователя.

Для защиты данных используется не мастер-ключ в явном виде, а симметричный сеансовый ключ , который создается на основе мастер-ключа, неких случайных данных и, опционально, дополнительной энтропии (если приложение предоставляет это значение ). Сеансовый ключ никогда не сохраняется. Вместо этого в бинарном блоке, содержащем зашифрованные данные, сохраняются случайные данные, использованные при генерации сеансового ключа, что позволяет DPAPI создать его заново при необходимости расшифровать данные.

В целях безопасности каждые три месяца срок действия мастер-ключа истекает, и генерируется новый ключ . DPAPI никогда не удаляет "устаревшие" мастер-ключи, а хранит их в зашифрованном виде с другими параметрами учетной записи пользователя. В бинарном блоке с зашифрованными данными хранится глобально уникальный идентификатор ( Globally Unique Identifier , GUID ), позволяющий однозначно определить мастер-ключ , использованный для защиты данных .

При смене пароля пользователя DPAPI осуществляет два действия. Во-первых, все мастер-ключи зашифровываются ключом, сгенерированным на базе нового пароля. Во-вторых, старый пароль добавляется в файл " Credential History " в директории, используемой для хранения параметров пользователя. Этот файл шифруется с использованием нового ключа. При необходимости DPAPI может использовать текущий ключ для того, чтобы расшифровать " Credential History ", извлечь старый пароль и попытаться с его помощью расшифровать мастер-ключ . Если это не удается, " Credential History " расшифровывается ключом на основе "старого" пароля, извлекается пароль , который ему предшествовал, и т.д., пока не будет найден пароль , позволяющий расшифровать мастер-ключ .

Криптосервисы для устройств под управлением Windows CE и Windows Mobile

Windows Mobile предоставляет криптосервисы, которые позволяют разработчикам внедрять в приложения функции безопасности , в том числе - использовать CrypoAPI , криптопровайдеры , осуществлять выдачу сертификатов и управление ими, реализовывать настраиваемую инфраструктуру открытых ключей , использовать смарт-карты .

Windows CE включает три криптопровайдера :

  • Microsoft RSA Base Provider ;
  • Microsoft Enhanced Cryptographic Provider ;
  • Smart Card CSP .

Подсистема поддержки смарт-карт на устройствах под управлением Windows CE , начиная с версии 5.0., обеспечивает связь между аппаратным обеспечением для чтения смарт-карт и приложениями, работающими с ними. Связь обеспечивается динамическими библиотеками ( DLL ), программным интерфейсом ( API ) для управления ресурсами смарт-карт и драйверами устройств для чтения смарт-карт .

Краткие итоги

В лекции подробно изучены принципы работы и архитектура интерфейса CryptoAPI и его преемника - CNG API . Указаны особенности использования технологии в нашей стране. Помимо этого, рассмотрены функции и механизм работы DPAPI

рис.1


Секреты создания CSP для Windows раскрыты в статье Ю.С.Зырянова.

Российские криптоалгоритмы ГОСТ реализованы в OpenSSL Gost.

Удивлен, что на просторах Интернета не удалось найти подтверждения, что кем-то был создан интерфейс криптопровайдера ГОСТ под Windows с использованием вышеприведенных инструментов.

На первом этапе нам нужно сделать не так чтобы много, а именно, сначала выполнить пункты, описанные в статье Ю.С.Зырянова, далее получить список OID из RFC-4357, скомпилировать библиотеку OpenSSL в части реализации ГОСТ криптоалгоритмов, ну и наконец, подыскать реальные корневые сертификаты УЦ, можно и не только корневые, для проведения тестирования того, что у нас получилось.

Качаем исходники

Для начала потребуется скачать Microsoft Cryptographic Service Provider Development Kit, нажав на зеленую кнопку Download Now.

Далее скачаем библиотеку OpenSSL. На момент написания статьи она имеет версию 1.0.0e

Зарегистрируем криптопровайдер в реестре. Для этого выполним (с правами администратора) нижеприведенный файл командой «regedit xyzcsp.reg»

Библиотека OpenSSL

Сборку OpenSSL из исходников оставим за кадром, заметим только, что это несложно, требуется наличие установленного perl и MS Visual Studio, для компиляции нужно следовать инструкциям в файле Install.W32, после этого получим в директории C:\xyzcsp\openssl-1.0.0e\tmp32dll множество объектных файлов, которые я для простоты собрал в один файл openssl.lib, который и использовал в своем проекте.


Прошу извинить за столь длинный список, но мне неизвестен простой способ, как можно узнать, какие obj файлы из данного lib файла нужны для сборки, а какие нет. Создание map файла не помогает, так что пришлось использовать практически полный список obj файлов из директории tmp32dll.

Создаем openssl.lib при помощи команды make_lib.bat

Приступим к написанию необходимых нам функций хеширования и проверки ЭЦП по ГОСТ.

Назовем их my_hash_gost() и my_verify_gost() соответственно. Чтобы их получить, были использованы готовые куски из текста OpenSSL, но много времени ушло на отладку, в частности на то, чтобы понять, что когда мы делаем «переворот» данных, меняя порядок следования байт, то хеш переворачивать не нужно, а все остальное, включая публичный ключ и ЭЦП — нужно.

Немного истории. Изначально функция my_verify_gost тестировалась с хешем, равным константе во всех 32-х байтах. И это меня спасло. Потому что достаточно быстро функция заработала, но когда был вставлен реальный хеш, состоящий из достаточно случайного набора байт, то сразу после этого ЭЦП перестала проверяться. Я долго не мог понять, что константный хеш является зеркальным, поэтому подходит для работы функции и без переворачивания. Мне повезло, если бы тестирование началось с реального хеша, то библиотеку OpenSSL было бы достаточно тяжело настроить для проверки ЭЦП сертификатов, потому что такое «хитрое» поведение хеша достаточно неочевидно.

Провайдер XYZ Provider

Теперь займемся, наконец, провайдером. Выберем ему имя: «XYZ Provider». Соответственно, основной файл будет называться xyzcsp.c, также нужны файлы xyzcsp.def и xyzcsp.rc

В исходном образце, который можно найти в CSPDK, в файле csp.c, нас интересуют только функции CPAcquireContext, CPHashData, CPGetHashParam, CPVerifySignature. Легко видеть, что это функции для создания хендла провайдера, функции хеширования и проверки ЭЦП. Заменим эти функции на приведенные ниже.

Кроме них, напишем одну замечательную функцию, xyz_ConvertPublicKeyInfo, которая будет заниматься конвертацией публичного ключа ЭЦП. Не забываем добавить xyz_ConvertPublicKeyInfo в файл xyzcsp.def, чтобы линкер экспортировал это имя. Конвертация будет заключаться в игнорировании первых двух байт в записи ASN1 нотации публичного ключа, тем самым получая ключ в чистом виде, две половинки по 32 байта.

Удалим функцию DllMain, а также старые CPAcquireContext, CPHashData, CPGetHashParam, CPVerifySignature из xyzcsp.c, уберем устаревшую команду DESCRIPTION и имена DllRegisterServer и DllUnregisterServer из xyzcsp.def

Добавим в конец файла xyzcsp.c:


Подробно комментировать исходники криптопровайдера, думаю, излишне. Все понятно по тексту.

Пишем тестовую программу

Зачем нужна отдельная тестовая программа? Она, кроме запуска тестов, будет патчить систему, чтобы поменять функции SystemFunction035 в ADVAPI32.dll и I_CryptGetDefaultCryptProv в CRYPT32.dll на их «правильный» вариант. Данная программа будет успешно работать как в Windows XP так и в Windows 7.

В конце статьи показано, как можно пропатчить системные файлы в Windows XP SP3, в этом случае специальная тестовая программа будет не нужна.

Компиляция файлов

Файл компиляции провайдера comp_xyzcsp.bat:

Файл компиляции теста comp_test.bat:

Сертификаты для тестирования

Файл gnivc_2006.cer, в котором лежит корневой сертификат ФНС:

Файл rootsber.cer, в котором лежит корневой сертификат Сбербанка:

Результаты работы


Запустим тестовую программу, получим результат:

Чтобы убрать последнее препятствие, включим сертификат в список доверенных, как рекомендуется. Для этого нажмем кнопку Установить сертификат и несколько раз кнопку Далее. По окончании тестирования нужно удалить тестовый сертификат из хранилища доверенных корневых, чтобы не подвергать возможной опасности свою систему.


После повторного запуска теста наблюдаем уже иную картину:

Что и требовалось получить.

Корневой сертификат Сбербанка


С сертификатом Сбербанка подобное проделать не получается:

Это связано с тем, что в Сбербанке используется константа B из RFC 4357, а именно GostR3410_2001_CryptoPro_B_ParamSet.

Меняем тогда в нашем файле xyzcsp.c в функции CPVerifySignature константу A на B, то есть при вызове my_verify_gost будем использовать следующий параметр: NID_id_GostR3410_2001_CryptoPro_B_ParamSet.

После компиляции провайдера и запуска теста наблюдаем обратную картину, сертификат ФНС не проверяется, а Сбербанковский — работает отлично. Казалось бы, существенный недостаток, но для простейшего криптопровайдера это простительно.

Конечно, возможен такой вариант: проверять сразу две ЭЦП и, если хотя бы одна из них сойдется, объявлять что ЭЦП верна, но это в корне неправильно. Нужно смотреть на OID публичного ключа и уже по нему искать требуемые параметры эллиптической кривой.

В следующей статье, которая сейчас готовится к публикации, мы подробно рассмотрим, как избежать подобной ситуации, а также напишем функцию по созданию ключей ЭЦП с различными параметрами.

Создание универсального патча

В заключение несколько слов о создании универсального патча.

Для Windows XP SP3 достаточно подменить следующие файлы:
c:\windows\system32\advapi32.dll
c:\windows\system32\dllcache\advapi32.dll
c:\windows\system32\crypt32.dll
c:\windows\system32\dllcache\crypt32.dll

Патчить нужно, загрузившись с другого диска, чтобы системный был свободным (можно с загрузочного диска Windows в режиме восстановления), далее заменяем эти два файла как в директории system32 так и в system32\dllcache, где хранятся их копии. Патчить на работающей системе не получится, потому что файлы «залочены» и поменять их не удастся.

После этого не забудьте скопировать файл с криптопровайдером xyzcsp.dll в директорию c:\windows\system32, чтобы система его находила.

Теперь можно кликать мышью на сертификат и он будет проверяться непосредственно в операционной системе, без запуска специальных программ.

Заменить файлы нужно на их пропатченный вариант:


Для Windows 7 также можно создать универсальный патч, желающие могут попробовать сделать это самостоятельно.

В реальной системе, в которой установлен ГОСТ криптопровайдер, проблемы с патчем обычно решаются за счет установки специального драйвера PatchEngine, который наблюдает за загрузкой системных DLL и патчит их «на лету».

Читайте также: