//-------------------------------------------------------------------- // В этом примере реализованы создание подписи объекта функции хеширования // и проверка этой электронно-цифровой подписи. // Замечание: под win32 рекомендуется использовать _s аналоги CRT функций. //-------------------------------------------------------------------- #define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING) #ifdef _WIN32 #define CONTAINER "test" #else #define CONTAINER "\\\\.\\HDIMAGE\\test" #endif static void HandleError(char *s); static void CleanUp(void); static HCRYPTPROV hProv = 0; static HCRYPTHASH hHash = 0; static HCRYPTKEY hKey = 0; static HCRYPTKEY hPubKey = 0; static BYTE *pbHash = NULL; static BYTE *pbSignature = NULL; static BYTE *pbKeyBlob = NULL; int main(void) { //------------------------------------------------------------- // Объявление и инициализация переменных. BYTE *pbBuffer= (BYTE *)"The data that is to be hashed and signed."; DWORD dwBufferLen = (DWORD)(strlen((char *)pbBuffer)+1); DWORD dwSigLen; DWORD dwBlobLen; DWORD cbHash; FILE *signature; // Получение дескриптора контекста криптографического провайдера. if(CryptAcquireContext( &hProv, CONTAINER, NULL, PROV_GOST_2001_DH, 0)) { printf("CSP context acquired.\n"); } else { HandleError("Error during CryptAcquireContext."); } //-------------------------------------------------------------------- // Получение открытого ключа подписи. Этот открытый ключ будет // использоваться получателем хеша для проверки подписи. // В случае, когда получатель имеет доступ к открытому ключю // отправителя с помощью сертификата, этот шаг не нужен. if(CryptGetUserKey( hProv, AT_SIGNATURE, &hKey)) { printf("The signature key has been acquired. \n"); } else { HandleError("Error during CryptGetUserKey for signkey."); } //-------------------------------------------------------------------- // Экпорт открытого ключа. Здесь открытый ключ экспортируется в // PUBLICKEYBOLB для того, чтобы получатель подписанного хеша мог // проверить подпись. Этот BLOB может быть записан в файл и передан // другому пользователю. if(CryptExportKey( hKey, 0, PUBLICKEYBLOB, 0, NULL, &dwBlobLen)) { printf("Size of the BLOB for the public key determined. \n"); } else { HandleError("Error computing BLOB length."); } //-------------------------------------------------------------------- // Распределение памяти под pbKeyBlob. pbKeyBlob = (BYTE*)malloc(dwBlobLen); if(!pbKeyBlob) HandleError("Out of memory. \n"); // Сам экспорт в ключевой BLOB. if(CryptExportKey( hKey, 0, PUBLICKEYBLOB, 0, pbKeyBlob, &dwBlobLen)) { printf("Contents have been written to the BLOB. \n"); } else { HandleError("Error during CryptExportKey."); } //-------------------------------------------------------------------- // Создание объекта функции хеширования. if(CryptCreateHash( hProv, CALG_GR3411, 0, 0, &hHash)) { printf("Hash object created. \n"); } else { HandleError("Error during CryptCreateHash."); } //-------------------------------------------------------------------- // Передача параметра HP_OID объекта функции хеширования. //-------------------------------------------------------------------- //-------------------------------------------------------------------- // Определение размера BLOBа и распределение памяти. if(CryptGetHashParam(hHash, HP_OID, NULL, &cbHash, 0)) { printf("Size of the BLOB determined. \n"); } else { HandleError("Error computing BLOB length."); } pbHash = (BYTE*)malloc(cbHash); if(!pbHash) HandleError("Out of memory. \n"); // Копирование параметра HP_OID в pbHash. if(CryptGetHashParam(hHash, HP_OID, pbHash, &cbHash, 0)) { printf("Parameters have been written to the pbHash. \n"); } else { HandleError("Error during CryptGetHashParam."); } //-------------------------------------------------------------------- // Вычисление криптографического хеша буфера. if(CryptHashData( hHash, pbBuffer, dwBufferLen, 0)) { printf("The data buffer has been hashed.\n"); } else { HandleError("Error during CryptHashData."); } // Определение размера подписи и распределение памяти. dwSigLen = 0; if(CryptSignHash( hHash, AT_SIGNATURE, NULL, 0, NULL, &dwSigLen)) { printf("Signature length %d found.\n",dwSigLen); } else { HandleError("Error during CryptSignHash."); } //-------------------------------------------------------------------- // Распределение памяти под буфер подписи. pbSignature = (BYTE *)malloc(dwSigLen); if(!pbSignature) HandleError("Out of memory."); // Подпись объекта функции хеширования. if(CryptSignHash( hHash, AT_SIGNATURE, NULL, 0, pbSignature, &dwSigLen)) { printf("pbSignature is the hash signature.\n"); } else { HandleError("Error during CryptSignHash."); } //if(!fopen_s(&signature, "signature.txt", "w+b" )) if(!(signature = fopen("signature.txt", "w+b"))) HandleError( "Problem opening the file signature.txt\n" ); fwrite(pbSignature, 1, dwSigLen, signature); // Уничтожение объекта функции хеширования. if(hHash) CryptDestroyHash(hHash); printf("The hash object has been destroyed.\n"); printf("The signing phase of this program is completed.\n\n"); //-------------------------------------------------------------------- // Во второй части программы проверяется подпись. // Чаще всего проверка осуществляется в случае, когда различные // пользователи используют одну и ту же программу. Хеш, подпись, // а также PUBLICKEYBLOB могут быть прочитаны из файла, e-mail сообщения // или из другого источника. // Здесь используюся определенные ранее pbBuffer, pbSignature, // szDescription, pbKeyBlob и их длины. // Содержимое буфера pbBuffer представляет из себя некоторые // подписанные ранее данные. // Указатель szDescription на текст, описывающий данные, подписывается. // Это тот же самый текст описания, который был ранее передан // функции CryptSignHash. //-------------------------------------------------------------------- // Получение откытого ключа пользователя, который создал цифровую подпись, // и импортирование его в CSP с помощью функции CryptImportKey. Она // возвращает дескриптор открытого ключа в hPubKey. if(CryptImportKey( hProv, pbKeyBlob, dwBlobLen, 0, 0, &hPubKey)) { printf("The key has been imported.\n"); } else { HandleError("Public key import failed."); } //-------------------------------------------------------------------- // Создание нового объекта функции хеширования. if(CryptCreateHash( hProv, CALG_GR3411, 0, 0, &hHash)) { printf("The hash object has been recreated. \n"); } else { HandleError("Error during CryptCreateHash."); } //-------------------------------------------------------------------- // Установка параметра HP_OID. // По умолчанию провайдер работает на наборе параметров 1.2.643.2.2.30.1. // Без установки параметра HP_OID программа будет неверно работать, // если параметры хеширования не будут являться параметрами // по умолчанию. if(CryptSetHashParam( hHash, HP_OID, pbHash, 0)) { printf("The parameters have been set. \n"); } else { HandleError("Error during SetHashParam."); } //-------------------------------------------------------------------- // Вычисление криптографического хеша буфера. if(CryptHashData( hHash, pbBuffer, dwBufferLen, 0)) { printf("The new has been created.\n"); } else { HandleError("Error during CryptHashData."); } //-------------------------------------------------------------------- // Проверка цифровой подписи. if(CryptVerifySignature( hHash, pbSignature, dwSigLen, hPubKey, NULL, 0)) { printf("The signature has been verified.\n"); } else { printf("Signature not validated!\n"); } CleanUp(); return 0; } void CleanUp(void) { if(pbSignature) free(pbSignature); if(pbHash) free(pbHash); if(pbKeyBlob) free(pbKeyBlob); // Уничтожение объекта функции хеширования. if(hHash) CryptDestroyHash(hHash); if(hKey) CryptDestroyKey(hKey); if(hPubKey) CryptDestroyKey(hPubKey); // Освобождение дескриптора провайдера. if(hProv) CryptReleaseContext(hProv, 0); } // Конец примера
AIX: 5/6/7 или выше.
FreeBSD: 7/8/9 или выше.
Linux: LSB 3.1 (RHEL 4, SuSE 10) или выше.
Solaris: 10 или выше.
Mac OSX: 10.7/8 или выше.
iOS: 6/7 или выше.
Windows 2000 или выше: Необходимо Windows 2000 SP4 или старше с Internet Explorer 6.0 или старше.
Ядро Windows NT: не поддерживает.