Declare Function CryptDecryptMessage Lib “crypt32.dll” (TODO) As TODO
User-Defined Types:
None.
Notes:
None.
Tips & Tricks:
Please add some!
Sample Code:
Please add some!
Alternative Managed API:
Do you know one? Please contribute it!
Введение
Эта статья основана на моем личном опыте в деле написания программных продуктов криптографической направленности. Несмотря на данный, прежде всего коммерческий, опыт, здесь я постараюсь абстрагироваться от какого-то конкретного направления в Crypto API, и рассмотреть общий случай его применения.
Предполагается, что читатель знаком с некоторыми общими для криптографии понятиями: ключ шифрования, симметричные/ассиметричные алгоритмы шифрования, понятия протоколов шифрования и т.п. Также предполагается, что читатель имеет доступ к MSDN как можно более новой редакции.
cryptoPro
Единое, асинхронное API для взаимодействия с КриптоПРО ЭЦП Browser Plug-In
cryptoPro
Тем, кто хочет помочь
Полезная информация
Лицензия
Зачем мне этот пакет?
КриптоПРО ЭЦП Browser Plug-In доступен в разных браузерах в двух версиях. Асинхронной (в современных браузерах) и синхронной (в браузерах постарше). С помощью этого пакета можно не писать реализацию под каждую версию плагина дважды. И вместо этого и этого написать это (UMD):
или это (ES Modules + Typescript):
Установка
Подключение пакета как UMD модуля через тэг script:
Результат методов сертификата getOwnerInfo и getIssuerInfo изменился с { descr, title, translated } на { description, title, isTranslated }
Принципиальная реализация методов, обращающихся к Крипто ПРО не изменилась. Получение сертификатов, создание подписи, проверка корректности настроек работают по-прежнему.
Убрана поддержка IE8 (Крипто ПРО его больше не поддерживает)
Убрана поддержка КриптоПРО CSP версий ниже 4.0
Убрана поддержка КриптоПРО ЭЦП browser plug-in версий ниже 2.0
Доработана обработка ошибок, выбрасываемых из Крипто ПРО
При написании кода будут работать автодополнения и подсказки
Исправлена проблема работы библиотеки с UglifyJs
Методы API доступны напрямую:
В версии 1:
В версии 2 (UMD):
В версии 2 (ES Modules):
Тем, кто хочет помочь
Буду благодарен за расширение/улучшение/доработку API. Вам будут полезны примеры, предоставляемые Крипто ПРО.
Запуск режима разработки
Во время работы с кодом необходим запущенный сборщик:
И пример, на котором можно тестировать изменения. Удобнее всего тестировать на примере с тэгом script, тк он отвязан от фреймворков и использует сборку в формате UMD из папки dist/, постоянно обновляемую пока работает сборщик. Запускаем его таким образом:
examples/script-tag
npm i
npm link ../../
npm start
После выполнения npm link ../../ в директории examples/script-tag/node_modules папка crypto-pro станет ярлыком, указывающим на папку содержащую локально собранный пакет.
Запуск тестов
Тесты написаны с использованием Jest:
Проверка работы примеров с React и Angular
React и Angular используют версию сборки пакета в формате ES модулей из директории lib/. Для их запуска необходимо сначала собрать пакет выполнив:
После этого из папки examples/angular или examples/react залинковать пакет:
examples/angular
npm i
npm link ../../
И запустить пример в одном из двух режимов. В режиме разработки:
или в режиме продакшн:
npm run build
npm run serve
Проверка пакета перед публикацией в NPM
Необходимо протестировать работу в заявленных браузерах, сделав это на локально запакованной версии пакета. Для этого собираем пакет:
npm run package
mv package ..
Важно переместить папку package куда-нибудь выше для избежания конфликтов при линковке с текущим package.json.
Переходим в любую директорию с примером и создаем там ссылку на только что собранный пакет:
examples/script-tag
npm link ../../../package
Проверяем работу примеров в режимах разработки и продакшн.
После завершения экспериментов можно удалить глобальную ссылку из директории ../../../package таким образом:
../../../package
npm unlink
Полезная информация
Установка КриптоПРО CSP в Linux / OSX
Процесс установки в OSX незначительно отличается от Linux, поэтому описание приведено на примере дистрибутива семейства Debian (x64).
Некоторые команды могут потребовать запуска с sudo. Названия файлов и директорий могут отличаться из-за различий в версиях.
После загрузки КриптоПРО CSP для нужной платформы, распакуйте архив:
tar -xzvf linux-amd64_deb.tgz
chmod 777 -R linux-amd64_deb/
После настройки плагина на страницах, запрашивающих работу с ЭП в панели навигации, рядом с url будет кнопка, позволяющая “разрешить и запомнить” использование установленного плагина.
Select “Edit This Page” on the right hand toolbar and edit it! Or add new pages containing supporting types needed for this API (structures, delegates, and more).
Высокоуровневые функции обработки сообщений
Введение
В рассмотренных выше базовых функциях работы с криптографическими сообщениями все выглядит достаточно хорошо. За исключением работы на уровне общепринятых в криптографии форматов данных. То есть выходные данные, полученные с помощью базовых функций Crypto API, можно обработать только этими же базовыми функциями Crypto API. Этот недостаток устраняется путем применения высокоуровневых функций для работы с криптографическими приложениями.
В основе работы данных функций лежит стандарт PKCS #7 (RFC 2315). Более подробно об этом стандарте будет рассказано несколько позднее, а здесь будет сказано лишь о его основных особенностях.
Основу стандарта PKCS #7 составляют способы кодирования и описания различных данных, используемых в криптографических приложениях. Так, предоставляются стандарты по кодированию шифрованных и подписанных сообщений, стандарт кодирования сессионного ключа, стандарт кодирования информации о сертификате и многое другое. Работа со стандартом PKCS #7 реализована на многих платформах, отличных от MS Windows, что позволяет создавать кроссплатформенные приложения. Высокоуровневые функции скрывают многие не очень существенные моменты использования стандарта PKCS #7, благодаря чему упрощается работа с криптографическими данными.
Между тем, одним из ограничений в работе высокоуровневых функций следует признать недопустимость поблочной загрузки входных данных – эти функции работают только с одним, загруженным в память блоком. Для работы с большими объемами данных и более тонкого использования всех возможностей Crypto API в работе со стандартом PKCS предназначены низкоуровневые функции обработки сообщений, о которых будет рассказано позднее.
Шифрование
Для шифрования используется функция CryptEncryptMessage. Данная функция имеет следующее описание:
В качестве первого параметра данной функции передается указатель на структуру CRYPT_ENCRYPT_MESSAGE_PARA. В полях данной структуры передается информация об используемом для шифрования криптопровайдере, используемом алгоритме и вспомогательная информация, нужная для правильной работы выбранного алгоритма. Параметр cRecipientCert передает количество используемых сертификатов получателей. Сам массив используемых сертификатов получателей передается в параметре rgpRecipientCert.
СОВЕТ
Собственно сертификаты в данных функциях используются, в основном, для экспорта сессионного ключа, сформированного при шифровании. Того, что сертификаты сами по себе хранят публичные ключи получателей, вполне должно хватить для экспорта сессионного ключа. В случае нескольких получателей данных для каждого получателя формируется свой массив экспортированного ключа. Кроме того, используется также другое свойство сертификатов: каждый из них имеет некий уникальный идентификационный номер. Вставляя этот номер в полученный массив экспортированных сессионных ключей, мы получаем возможность на стороне получателя найти необходимый для корректного импорта сессионного ключа элемент данного массива.
Параметры pbToBeEncrypted и cbToBeEncrypted идентифицируют область обрабатываемых данных. Зашифрованный контент и его размер возвращается через параметры pbEncryptedBlob и pcbEncryptedBlob соответственно.
Пример использования данной функции приведен ниже:
В качестве первого параметра данной функции передается указатель на структуру типа CRYPT_DECRYPT_MESSAGE_PARA. В полях данной структуры передается список хранилищ сертификатов, в которых будет производиться поиск сертификата для импорта сессионного ключа (сертификата обмена). В параметрах pbEncryptedBlob и cbEncryptedBlob передается информация о блоке входных данных, подлежащих расшифровке. В параметрах pbDecrypted и pcbDecrypted передаются принимающий буфер и его размер соответственно. В этот буфер будут помещены расшифровываемые данные. В параметре ppXchgCert возвращается ссылка на контекст сертификата, который был использован для обмена (если эта информация не нужна, то данный параметр должен быть установлен в NULL).
ПРЕДУПРЕЖДЕНИЕ
Необходимо отметить, что сертификат, используемый для импорта сессионного ключа (сертификат обмена) на стороне получателя должен быть связан с локальным контейнером ключей. Иначе не будет найден секретный ключ пары ключей, и функция будет выполнена с ошибкой (никаких расшифрованных данных получить не удастся).
В отличие от простейшего случая формирования цифровой подписи базовыми функциями в стандарте PKCS предусмотрено существование двух видов цифровой подписи: подпись, совмещенная с подписываемыми данными (attached signature) и подпись, отдельная от данных (detached signature). Функция CryptSignMessage, формирующая оба эти вида подписей, имеет следующее описание:
В качестве первого параметра данной функции передается указатель на структуру типа CRYPT_SIGN_MESSAGE_PARA. В полях данной структуры передается информация о сертификате, с помощью которого будет производиться подпись (сертификат, заверяющий подписчика), алгоритм формирования хеш-значения переданных данных, массив дополнительных сертификатов, которые необходимо включить в состав цифровой подписи, и некоторые вспомогательные величины. Параметр fDetachedSignature задает тип получаемой цифровой подписи (отделенная или совмещенная с данными). Параметр cToBeSigned указывает на количество элементов массива подписываемых данных.
ПРЕДУПРЕЖДЕНИЕ
Если флаг fDetachedSignature установлен в false, параметр cToBeSigned всегда должен быть равен 1. Это связано с особенностями реализации низкоуровневых функций работы с криптографическими сообщениями, особенности которых будут рассмотрены позднее.
Параметр rgpbToBeSigned представляет собой массив данных, передаваемых для формирования цифровой подписи. Параметр rgcbToBeSigned представляет собой массив размеров элементов переданного массива данных. Выходное значение функции (цифровая подпись) формируется в параметрах pbSignedBlob и pcbSignedBlob.
Пример использования данной функции приведен ниже:
Для проверки цифровой подписи в состав высокоуровневых функций работы с сообщениями входят функции CryptVerifyMessageSignature и CrypVerifyDetachedMessageSignature. Первая функция предназначена для проверки цифровой подписи, совмещенной с данными. Результат проверки (правильна или неправильна цифровая подпись) можно узнать, проанализировав возвращаемое значение этой функции. Вторая функция предназначена для проверки цифровой подписи, не содержащей сами подписываемые данные. Первая из этих функций имеет следующее описание:
В качестве первого параметра данной функции передается указатель на структуру типа CRYPT_VERIFY_MESSAGE_PARA. В полях данной структуры передается информация о контексте криптопровайдера, применяемом для проверки подписи, и ссылке на функцию, с помощью которой находится сертификат подписчика в локальных хранилищах данных. В случае, когда ссылка на данную функцию равна NULL, функция CryptVerifyMessageSignature ищет данный сертификат внутри самой цифровой подписи. Параметр dwSignerIndex задает номер подписчика, для которого необходимо проверить подпись (в одном файле подписи потенциально может быть несколько цифровых подписей от различных подписчиков). Для первого подписчика параметр dwSignerIndex должен быть равным 0. В параметрах pbSignedBlob и cbSignedBlob передается информация о входном блоке данных, подлежащем проверке. В параметрах pbDecoded и pcbDecoded может быть передана информация о блоке памяти, в который помещается раскодированное проверяемое сообщение (для которого, собственно, и была сформирована цифровая подпись). В случае, когда данная информация не нужна, параметры pbDecoded и pcbDecoded должны быть установлены в NULL. В параметре ppSignerCert возвращается двойной указатель на контекст сертификата подписчика.
Пример использования этой функции примерно соответствует примеру для функции CryptVerifyDetachedMessageSignature, приведенному ниже.
Функция, проверяющая отсоединенную от данных цифровую подпись, имеет следующее описание:
Параметры pVerifyPara и dwSignerIndex имеют точно такой же смысл, что и соответствующие параметры функции CryptVerifyMessageSignature. Параметры pbDetachedSignedBlob и cbDetachedSignedBlob описывают область памяти, которая хранит собственно проверяемые данные. Параметр cToBeSigned описывает количество элементов в массивах, передаваемых в параметрах rgpbToBeSigned и rgcbToBeSigned. Параметр rgpbToBeSigned представляет собой массив областей памяти, содержащий в себе данные, для которых проверяется цифровая подпись. Параметр rgcbToBeSigned содержит массив размеров блоков памяти, указанных в параметре rgpbToBeSigned. В параметре ppSignerCert возвращается двойной указатель на контекст сертификата подписчика. Результат проверки (правильна или неправильна цифровая подпись) возвращается как результат выполнения функции CryptVerifyDetachedMessageSignature.
Кроме применения формирования отдельно шифрованного и отдельно подписанного контентов в стандарте PKCS #7 предусмотрено получение контента, который представляет собой цифровую подпись, совмещенную с зашифрованными данными (сначала формируется цифровая подпись открытых данных, затем данные шифруются). Таким образом, собственно проверка данных может быть осуществлена получателем шифрованных данных, для которого они предназначались. Такой способ передачи данных хорош, прежде всего, отсутствием передачи проверяемых данных в открытом виде.
Функция CryptSignAndEncryptMessage, осуществляющая подобную работу в Crypto API, имеет следующее описание:
Так как, по сути, выполнение данной функции состоит из последовательного применения функций для получения цифровой подписи и функции шифрования, то параметры у функции CryptSignAndEncryptMessage точно совпадают с параметрами составляющих ее функций. Значение всех этих параметров было объяснено ранее в соответствующих разделах.
Пример использования данной функции приведен ниже:
Расшифровывание и проверка совмещенной цифровой подписи и шифрованных данных
Для расшифровывания и проверки совмещенных цифровой подписи и шифрованных данных применяют специальную функцию CryptDecryptAndVerifyMesageSignature, имеющую следующее описание:
Значения параметров данной функции полностью аналогичны значениям параметров функций CryptDecryptMessage и CryptVerifyMessageSignature. Результат проверки (правильна или неправильна цифровая подпись) получается как результат функции CryptDecryptAndVerifyMessageSignature.
Пример использования данной функции приведен ниже:
Кроме стандарта PKCS #7 достаточно часто можно встретить употребление другого стандарта – PEM (Privacy-Exchanged Mail). Фактически же в данном стандарте применяются два последовательных кодирования: первичное в PKCS #7 и вторичное в Base64. То есть если мы после завершения шифрования высокоуровневой функцией CryptEncryptMessage закодируем полученный результат в кодировке Base64, то полученный результат можно принять за образец применения стандарта PEM.
Работа с Base64 крайне проста и реализована во многих библиотеках. В частности, я бы хотел порекомендовать читателям средства, предоставляемые функциями Base64Encode и Base64Decode. Данные функции объявлены в заголовочном файле библиотеки ATL “atlenc.h”. Работа с данными функциями достаточно проста. Ниже приведен пример использования данных функций.
Зачастую применение непосредственно функций Crypto API достаточно проблематично. Например, в Web-клиентах, где вызовы процедур напрямую невозможны. Для подобных целей, а также для упрощения работы с Crypto API был создан тип объектов CAPICOM (Crypto API COM-object). В своей реализации данный объект почти полностью охватывает все то, о чем говорилось выше в данной статье: от шифрования до работы с сертификатами. Благодаря использованию дуальных интерфейсов, доступ к данному объекту возможен как из клиентов с ранним связыванием (C++), так и с поздним (VBscript).
В основе работы всех функций CAPICOM лежит использование высокоуровневых функций работы с криптографическими сообщениями, которые были рассмотрены ранее. Таким образом, базовым стандартом для выходных данных является стандарт PKCS #7, вторично кодированный Bas64. Так же, как и в случае высокоуровневых функций, работа ведется только с относительно небольшим участком данных, загруженных в память. Работа с данными большого объема или работа с поблочной загрузкой данных в объекте не предусмотрена.
ПРЕДУПРЕЖДЕНИЕ
Несмотря на то, что объект CAPICOM в качестве выходных данных использует общепринятый стандарт PKCS #7, используемый в функциях Crypto API, полной прямой совместимости между функциями Crypto API и CAPICOM нет. То есть выходная информация объекта CAPICOM не может быть использована в качестве входной для функций Crypto API. Дело в том, что в объекте CAPICOM происходит некоторое предварительное изменение входных данных перед выполнениями функций. То есть алгоритм выполнения, например, функции подписи, выглядит так:
1. Получить входные данные.
2. Изменить их (для внутреннего использования).
3. Вызвать стандартные функции Crypto API.
В качестве «изменения» входных данных используется простое дополнение к каждому символу исходной информации символа с кодом 0x00.
Подробно работа с объектом типа CAPICOM в данной статье рассматриваться не будет, так как сам по себе объект не входит в состав Crypto API и рассказ о нем несколько выходит за рамки этой статьи.
Эта статья опубликована в журнале RSDN Magazine
#5-2004. Информацию о журнале можно найти здесь
Базовые функции
Шифрование
Базовая функция шифрования данных имеет следующее объявление:
Первым параметром данной функции передается хендл сессионного ключа, применяемого для шифрования. Второй параметр достаточно редко используется и предназначен для получения хеша данных одновременно с их шифрованием. Такая возможность достаточно полезна при формировании одновременно как шифрованных данных, так и цифровой подписи этих же данных.
Эта функция может обрабатывать данные блоками. То есть нет необходимости сразу загружать в память целиком весь массив данных, а лишь потом передавать ссылку на него криптографической функции. Достаточно передавать массив данных поблочно, специальным образом отметив лишь последний блок данных (это обычно нужно, чтобы криптопровайдер провел некоторые действия после использования сессионного ключа). Для указания того, что это последний блок данных, в функции 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;
CryptHashData;
CryptGetHashParam.
Для первичной инициализации хэш-объекта применяют функцию CryptCreateHash. Данная функция имеет следующее описание:
В качестве первого параметра данной функции передается инициализированный контекст криптопровайдера. Вторым параметром указывается алгоритм получения значения хеша. Параметр hKey необходим лишь в случае применения специализированных алгоритмов типа MAC и HMAC.
СОВЕТ
MAC (Message Authentication Code, русский термин – «имитовставка»), переводится как «код проверки подлинности сообщения». Фактически, MAC предназначен для проверки значения хеш-значения только людьми, имеющими необходимый ключ. Можно воспринимать это как дополнительное шифрование значения, полученного с помощью хеш-функции (хотя это и не совсем так). Также MAC можно использовать в качестве простейшей цифровой подписи. HMAC (Hash-based Message Authentication Code) является разновидностью MAC.
Параметр dwFlags зарезервирован под возможное будущее использование и должен быть всегда равен 0. Через параметр phHash функция возвращает хендл созданного ей хеш-объекта. После того, как хеш-объект станет ненужным, нужно освободить хеш-объект с помощью вызова функции CryptDestroyHash.
После инициализации хеш-объекта можно начать передачу данных хеш-функции с помощью вызова CryptHashData. Данная функция имеет следующее описание:
В качестве первого параметра данной функции передается ранее инициализированный хендл хеш-объекта. Вторым параметром передается порция данных для хеш-функции. Параметр dwDataLen представляет собой длину передаваемых данных. Параметр dwFlags обычно равен нулю.
После полной передачи всего массива входных данных функции CryptHashData возникает необходимость в получении значения хеш-функции. Данная задача решается с применением функции CryptGetHashParam. Данная функция имеет следующее описание:
В качестве первого параметра данной функции передается ранее инициализированный хендл хеш-объекта. Второй параметр, dwParam, функции определяет тип запрашиваемого значения. Для получения хеш-значения необходимо передать вторым аргументом значение HP_HASHVAL. Параметры pdData и pdwDataLen отвечают за блок памяти, используемый под возвращаемое значение. Параметр dwFlags зарезервирован для будущего использования и должен быть равен нулю.
Для проверки правильности хеш-значения нужно получить хэш-значение данных и сверить его с проверяемым хэш-значением.
Под цифровой подписью понимают некую производную данных, по которой однозначно можно определить целостность и отправителя присланных данных. В простейшем случае под цифровой подписью можно понимать даже собственно шифрованный контент в случае, когда ключ шифрования не скомпрометирован и однозначно принадлежит известному отправителю информации. На практике же используют гораздо более интересный метод: первично используют получение хеша данных, а затем шифруют полученное хеш- значение с помощью алгоритма с открытым ключом. Таким образом, по полученной цифровой подписи можно судить как о целостности данных (расшифровав цифровую подпись, мы можем затем проверить полученное значение хеша), так и об отправителе данных (для получения цифровой подписи используется не публичный ключ отправителя, а секретный, который может быть использован только самим отправителем).
Именно такой подход к формированию цифровой подписи используется в базовых функциях Crypto API для работы с подписью. Базовая функция получения подписи хеша данных имеет следующее описание:
В качестве первого параметра используется значение хендла хеш-объекта, уже инициализированного данными (с помощью функции CryptHashData). Параметр dwKeySpec определяет, какая именно пара ключей будет использована для формирования подписи (AT_KEYEXCHANGE (пара для обмена ключами) или AT_SIGNATURE (пара для формирования цифровой подписи)). Еще раз хочется обратить внимание читателя, что во многих криптопровайдерах пара ключей, предназначенная для обмена ключами, может также использоваться и для формирования цифровой подписи (но не во всех криптопровайдерах). Параметр sDescription более не используется в данной функции и его значение должно всегда быть установлено в NULL. Параметр dwFlags обычно устанавливают также в 0. Параметры pbSignature и pdwSigLen используют для корректного указания ссылки на массив выходных данных и его размера.
Пример использования данной функции приведен ниже:
В качестве первого параметра в функцию передается хендл хеш-объекта, предварительно инициализированный данными посредством функции CryptHashData. Второй и третий параметры отвечают за передачу значения проверяемой подписи. Параметр hPubKey используется для указания хендла публичного ключа отправителя подписи (того, кто собственно сформировал цифровую подпись). Параметр sDescription в настоящее время более не используется и его значение должно быть установлено в NULL. Параметр dwFlags также обычно не несет полезной нагрузки и устанавливается в 0.
Пример использования данной функции приведен ниже: