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

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

Пример:

C++

void signHash(HCRYPTHASH hash)

{

  DWORD size;

  ::CryptSignHash(hash, AT_SIGNATURE, 0, 0, 0, &size);

  BYTE * signature = reinterpret_cast<BYTE*>(

    ::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, size)

  );

  ::CryptSignHash(hash, AT_SIGNATURE, 0, 0, signature, &size);

  // ... Используем буфер, сохраняем в файл, отправляем по сети ...

  ::HeapFree(::GetProcessHeap(), 0, signature);

}

Delphi

procedure SignHash(hash: HCRYPTHASH);

var

  size      : integer;

  signature : PByte;

begin

  CryptSignHash(hash, AT_SIGNATURE, nil, 0, nil, @size);

  signature := SysGetMem(size);

  CryptSignHash(hash, AT_SIGNATURE, nil, 0, signature, @size);

  { ... Используем буфер, сохраняем в файл, отправляем по сети ... }

  SysFreeMem(signature);

end;

Проверить подпись можно при наличии открытого ключа, который соответствует закрытому использовавшемуся при создании подписи. Такой ключ (открытый) экспортируется с параметром PUBLICKEYBLOB. Функция проверки подписи имеет вид:

BOOL WINAPI CryptVerifySignature(

  HCRYPTHASH hHash,

  BYTE *pbSignature,

  DWORD dwSigLen,

  HCRYPTKEY hPubKey,

  LPCTSTR sDescription,

  DWORD dwFlags

);

Всё так же первым параметром (hHash) передаётся идентификатор объекта «хэш», содержащий хэш-значение проверяемого документа (файла). Указатель на буфер, содержащий строку байтов цифровой подписи, передают вторым параметром (pbSignature). Размер буфера — третьим параметром (dwSigLen). Открытый ключ подписавшего документ — четвёртым (hPubKey). Два последних параметра имеют такое же назначение, что и в случае функции CryptSignHash.

Функция возвращает TRUE, если подпись верна, и FALSE — если вызов функции был неудачным. В последнем случае системная функция

DWORD GetLastError(VOID);

вернёт NTE_BAD_SIGNATURE, если подпись неверна (например, документ был изменён, подпись была изменена, открытый ключ не соответствует закрытому, который был использован для подписи и/или использованы разные алгоритмы для подписи и/или нахождения хэш-значения).

Пример:

C++

void verifySignature(HCRYPTHASH hash, HCRYPTKEY publicKey)

{

  BYTE * signature;

  DWORD  size;

  // ... Получили строку байтов цифровой подписи и её размер ...

  if (::CryptVerifySignature(hash, signature, size, publicKey, 0, 0)) {

    // Подпись верна

  }

  else if (::GetLastError() == NTE_BAD_SIGNATURE) {

    // Подпись не верна

  }

  else {

    // Другая ошибка (см. MSDN)

  }

}

Delphi

procedure VerifySignature(hash: HCRYPTHASH; publicKey: HCRYPTKEY);

var

  size      : integer;

  signature : PByte;

begin

  { ... Получили строку байтов цифровой подписи и её размер ... }

  if CryptVerifySignature(hash, signature, size, publicKey, nil, 0) then

    { Подпись верна }

  else if GetLastError = NTE_BAD_SIGNATURE then

    { Подпись не верна }

  else

    { Другая ошибка (см. MSDN) }

end;


Задание

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

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

Например, передавать в программу следующие параметры из командной строки:

-s my.private document.doc document.signature {for sign}

-v my.public document.doc document.signature {for verify}

-g my.private my.public {for generating keys}

-a RSA_SIGN {for signing algorithm}

-k 1024 {for size of signing key}

-h MD5 {for hash algorithm}

-l {for list of available signing algorithms and hash algorithms}

-? {for help}

Вызов программы может быть такой: