Цифровая подпись в проектах на CryptoAPI (Лабораторная работа № 3), страница 3

Первый параметр (hProv) это уже инициализированный контекст провайдера, в контейнер которого мы хотим импортировать ключ. Важно, чтобы это провайдер имел алгоритм, с помощью которого мы создавали ключ. Во втором параметре (pbData) передаётся указатель на буфер, содержащий блоб ключа. Размер этого буфера передаётся третьим параметром (dwDataLen). Четвёртый параметр (hPubKey) это ключ, соответствующий ключу который мы передавали во втором параметре функции CryptExportKey. Это закрытый ключ, соответствующий открытому, тот же самый симметричный ключ, или ключ на основе строки пароля. Если блоб ключа не был зашифрован (CryptExportKey получила нулевое значение во втором параметре) сюда следует передать также нулевое значение. Параметр dwFlags имеет схожее назначение с младшим словом параметра dwFlags функции CryptGenKey при импортировании ключевой пары (открытый и закрытый ключи). Сюда можно передать значение CRYPT_EXPORTABLE, чтобы иметь возможность экспортировать ключ из контейнера. Однако в случае одноразового использования ключа (например, для однократной подписи) если он уже существует в виде фала лучше передать сюда нулевое значение. Хотя это и не критично. Последний параметр (phKey) — это указатель на переменную, которая примет идентификатор объекта «ключ».

Пример.

C++

void importKey(HCRYPTPROV prov)

{

  HCRYPTKEY key;

  BYTE * keyBlob;

  DWORD size;

  // ... Загрузили или экспортировали блоб ключа ...

  ::CryptImportKey(prov, keyBlob, size, 0, CRYPT_EXPORTABLE, &key);

  // ... Используем ключ ...

}

Delphi

procedure ImportKey(prov: HCRYPTPROV);

var

  key     : HCRYPTKEY;

  size    : integer;

  keyBlob : PByte;

begin

  { ... Загрузили или экспортировали блоб ключа ... }

  CryptImportKey(prov, keyBlob, size, 0, CRYPT_EXPORTABLE, @key);

  { ... Используем ключ ... }

end;

Подпись и проверка подписи документов

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

Как уже было сказано в одной из предыдущих лабораторных работ, процесс подписи очень трудоёмок и подпись больших документов (файлов) может очень затянуться. Поэтому на практике обычно подписывают хэш документа. Алгоритм нахождения хэш-значения очень быстро работает, поэтому большие документы он «проглатывает» почти моментально. В CryptoAPI даже нет функций подписывающих какие-то данные, вместо них есть функции манипулирующие объектами «хэш» CryptSignHash и CryptVerifySignature.

После того, как мы создали в контейнере провайдера ключ подписи или импортировали его туда, создали объект «хэш» и нашли хэш значение документа, можно подписать его (хэш):

BOOL WINAPI CryptSignHash(

  HCRYPTHASH hHash,

  DWORD dwKeySpec,

  LPCTSTR sDescription,

  DWORD dwFlags,

  BYTE *pbSignature,

  DWORD *pdwSigLen

);

Первый параметр (hHash) — это идентификатор объекта «хэш» подписываемых данных. Второй параметр (dwKeySpec) — это идентификатор закрытого ключа в контейнере провайдера. Он может принимать значение AT_SIGNATURE непосредственно для подписи данных или AT_KEYEXCHANGE для обмена ключами. За дополнительной информацией об обмене ключами обращайтесь в MSDN. Для выполнения лабораторной работы передавайте сюда AT_SIGNATURE.

Третий параметр (sDescription) — это описание подписи, однако он оставлен для совместимости со старыми версиями функции и поэтому не должен быть использован. Передавайте сюда нулевое значение. Значение флагов четвёртого параметра (defrags) смотрите в MSDN. Обычно достаточно нулевого значения в данном параметре.

Указатель на буфер, куда будет записана строка байтов цифровой подписи, передаётся пятым параметром (pbSignature). Размер данного буфера — шестым (pdwSigLen). Используется уже знакомая технология получения размера буфера, передавая первый раз в качестве pbSignature нулевое значение.