#include "stdio.h"
#include "windows.h"
#include "wincrypt.h"
// Объявление функции CryptAcquireContextEx
BOOL CryptAcquireContextEx(HCRYPTPROV *phProv, //out
LPTSTR pszContainer, //in
LPTSTR pszpRovider, //in
DWORD dwProvType, //in
DWORD dwFlags, //in
DWORD dwKeySpec, //in
DWORD KeyFlags //in
);
void main(int argc, char *argv[])
{
// Объявление и инициализация переменных.
HCRYPTPROV hProv = 0; // Дескриптор провайдер
HCRYPTKEY hKey = 0; // Дескриптор ключа
HCRYPTKEY hPubKey = 0;
HCRYPTHASH hHash = 0;
// Буфер данных для подписи
LPBYTE pbBuffer = (BYTE *)"Ivanov Ivan Ivanovich";
LPTSTR szDescription = (LPTSTR)"Test message";
LPBYTE pbKeyBlob = NULL, pbSignature = NULL, PrivateBlob = NULL;
DWORD dwBufferLen = strlen((char *)pbBuffer)+1;
DWORD dwSigLen = 0, dwBlobLen = 0, dwBlobLen1 = 0;
// ********************************************************************
// Первая фраза. Подпись сообщения.
// ********************************************************************
printf("The message to sign: %s\n", pbBuffer);
printf("The description of message: %s\n", szDescription);
// Получение дискриптора криптопровайдера.
if (!CryptAcquireContextEx(&hProv, NULL, NULL, PROV_RSA_FULL, 0, AT_SIGNATURE, 0))
goto ReleaseResource;
printf("CSP context acquired\n");
// Получение дискриптора ключа подписи.
// AT_SIGNATURE - алгоритма открытых ключей
// являются основой для "Цифровых Подписей" (NIST Digital Signature Algorithm - DSA)
if (!CryptGetUserKey(hProv, AT_SIGNATURE, &hKey))
{
printf("Error: CryptGetUserKey=0x%X.\n",GetLastError());
goto ReleaseResource;
}
printf("The signature key has been acquired\n");
// Для получения необходимого размера памяти параметр pbData равен NULL.
// Размер ключевого блока возвращается в параметре dwBlodLen
// PUBLICKEYBLOB - используется для сохранения открытых ключей.
// Поскольку открытые ключи не являются секретными, они сохраняются в незашифрованном виде;
if (!CryptExportKey(hKey, 0, PUBLICKEYBLOB, 0, NULL, &dwBlobLen))
{
printf("Error: CryptExportKey=0x%X.\n",GetLastError());
goto ReleaseResource;
}
printf("Size of the blob for the public key determined\n");
// Выделение памяти для pbKeyBlob.
pbKeyBlob = (LPBYTE)malloc (dwBlobLen);
if (!pbKeyBlob)
{
printf("Error: Out of memory\n");
goto ReleaseResource;
}
printf("Memory has been allocated for the blob\n");
// Экспорт открытого ключа пары подписи.
if (!CryptExportKey(hKey, 0, PUBLICKEYBLOB, 0, pbKeyBlob, &dwBlobLen))
{
printf("Error: CryptExportKey=0x%X.\n",GetLastError());
goto ReleaseResource;
}
printf("Context have been written to the blob\n");
//выведем ключевой блоб открытого ключа
printf("\n\nPublicKeyBlob = \"");
for (DWORD i = 0; i < dwBlobLen; i++)
printf("%02x",pbKeyBlob);
printf("\"\n\n");
//получим ключевой блоб ключевой пары
// Для получения необходимого размера памяти параметр pbData равен NULL.
// Размер ключевого блоба возвращается в параметре dwBlodLen1
if (!CryptExportKey(hKey, 0, PRIVATEKEYBLOB, 0, NULL, &dwBlobLen1))
{
printf("Error: CryptExportKey=0x%X.\n", GetLastError());
goto ReleaseResource;
}
printf("Size of the blob for the private key pair determined\n");
// Выделение памяти для PrivateBlob
PrivateBlob = (LPBYTE)malloc (dwBlobLen1);
if (!PrivateBlob)
{
printf("Error: Out of memory\n");
goto ReleaseResource;
}
printf("Memory has been allocated for the blob\n");
// Экспорт секретного ключа пары подписи.
if (!CryptExportKey(hKey, 0, PRIVATEKEYBLOB, 0, PrivateBlob, &dwBlobLen1))
{
printf("Error: CryptExportKey=0x%X.\n", GetLastError());
goto ReleaseResource;
}
printf("Context have been written to the blob\n");
//выведем ключевой блоб пары
printf("\n\nPrivateKeyBlob = \"");
for (DWORD i = 0; i < dwBlobLen1; i++)
printf("%02x", PrivateBlob);
printf("\"\n\n");
// Создание объекта хеширования.
// CALG_MD5 - идентификатор алгоритма MD5
if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash))
{
printf("Error: CryptCreateHash=0x%X.\n",GetLastError());
goto ReleaseResource;
}
printf("Hash object created. Using MD5\n");
// Хеширование буфера данных
if (!CryptHashData(hHash, pbBuffer, dwBufferLen, 0))
{
printf("Error: CryptHashData=0x%X.\n",GetLastError());
goto ReleaseResource;
}
printf("The data buffer has been hashed\n");
// Определение необходимого размера памяти для буфера цифровой подписи.
if (!CryptSignHash(hHash, AT_SIGNATURE, szDescription, 0, NULL, &dwSigLen))
{
printf("Error: CryptSignHash=0x%X.\n",GetLastError());
goto ReleaseResource;
}
printf("Signature length %d found.\n", dwSigLen);
// Выделение памяти под буфер цифровой подписи.
pbSignature = (LPBYTE)malloc(dwSigLen);
if (!pbSignature)
{
printf("Error: Out of memory\n");
goto ReleaseResource;
}
printf("Memory allocated for the signature\n");
// Вычисление цифровой подписи
if (!CryptSignHash(hHash, AT_SIGNATURE, szDescription, 0, pbSignature, &dwSigLen))
{
printf("Error: CryptSignHash=0x%X.\n", GetLastError());
goto ReleaseResource;
}
printf("pbSignature is the hash signature\n");
// Уничтожение объекта хеширования
if (hHash)
CryptDestroyHash(hHash);
hHash = 0;
printf("The hash object has been destroyed\n");
printf("The signing phase of this program is completed\n\n");
//***********************************************************
// Вторая фаза. Проверка цифровой подписи сообщения
//***********************************************************
// Импортируем открытый ключ в криптопровайдер
if (!CryptImportKey(hProv, pbKeyBlob, dwBlobLen, 0, 0, &hPubKey))
{
printf("Error: CryptImportKey=0x%X.\n",GetLastError());
goto ReleaseResource;
}
printf("The key has been inported\n");
// Создание нового объекта хеширования.
if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash))
{
printf("Error: CryptCreateHash=0x%X.\n",GetLastError());
goto ReleaseResource;
}
printf("The hash object has been recreated. Using MD5\n");
// Хеширование буфера данных
if (!CryptHashData(hHash, pbBuffer, dwBufferLen, 0))
{
printf("Error: CryptHashData=0x%X.\n",GetLastError());
goto ReleaseResource;
}
printf("The new has been created.\n");
// Проверка цифровой подписи
if (!CryptVerifySignature(hHash, pbSignature, dwSigLen, hPubKey, szDescription, 0))
{
if (GetLastError() == NTE_BAD_SIGNATURE)
printf("SIGNATURE FAILED TO VALIDATED");
else
printf("Error: CryptVerifySignature=0x%X.\n",GetLastError());
}
else
printf("SIGNATURE VALIDATED OK!\n");
ReleaseResource:
// Освобождаем память блоба открытого ключа
if (pbKeyBlob)
free(pbKeyBlob);
// Освобождаем память подписи
if (pbSignature)
free(pbSignature);
// Уничтожаем объект хеширования
if (hHash)
CryptDestroyHash(hHash);
// Освобождаем дескриптор криптопровайдера
if (hProv)
CryptReleaseContext(hProv, 0);
}
BOOL CryptAcquireContextEx(HCRYPTPROV *phProv, //out
LPTSTR pszContainer, //in
LPTSTR pszProvider, //in
DWORD dwProvType, //in
DWORD dwFlags, //in
DWORD dwKeySpec, //in
DWORD KeyFlags //in
)
{
DWORD dwError;
HCRYPTKEY hKey;
// Пытаемся открыть контейнер криптопровайдера
if(!CryptAcquireContext(phProv, pszContainer, pszProvider, dwProvType, dwFlags))
{
dwError = GetLastError();
if (dwError != NTE_BAD_KEYSET)
{
printf("Error: CryptAcquireContext=0x%X.\n", dwError);
return FALSE;
}
else
{
// Если контекст не существует, создаем новый
if (!CryptAcquireContext(phProv, pszContainer, pszProvider, dwProvType, dwFlags|CRYPT_NEWKEYSET))
{
printf("Error: CryptAcquireContext=0x%X.\n", GetLastError());
return FALSE;
}
}
}
// Если ключевая пара в контейнере отсутствует, создаем новую
if (!CryptGetUserKey(*phProv, dwKeySpec, &hKey))
{
if (!CryptGenKey(*phProv, dwKeySpec, CRYPT_EXPORTABLE, &hKey))
{
CryptReleaseContext(*phProv, 0);
printf("Error: CryptGetUserKey=0x%X.\n", GetLastError());
return FALSE;
}
}
// Освобождаем дескриптор ключа
CryptDestroyKey(hKey);
return TRUE;
}
Задача по CryptoAPI
Подписывание сообщение, содержащее ФИО (открытие ключевого контекста, запрос пользовательского ключа подписи, экспорт открытого ключа подписи, создание объекта хеширования, расчёт хеш-функции и подпись хеш значения)
Проверка подписи (импорт открытого ключа в криптопровайдер, создание нового объекта хеша, расчёт хеш-функции и проверка подлинности подписи).
Алгоритм хеширования MD5
А хотел узнать этот код программы для условие этой задачи правелен или надо что-то добавить или убрать?
На то что в коде программы много goto на это можно внимание не обращать хотя я и понимаю что это плохо.
Код вот
Надо было добавить вывод на экран открытого и секретного ключа.
Меня смущате только 1 кусок, это объявление без присваивания LPTSTR szDescription.
Билдеру до фени, а вот Вижуал ругается...
А вообще, тебе сюда.
До встречи ;)
Kirjan, на самом деле просто не правильно приводить всегда не юникодную стргоку к LPTSTR, который может развернуться как в char * так и в wchar_t *.