//-------------------------------------------------------------------- // В этом примере реализованы создание подписи объекта функции хэширования // и проверка этой электронно-цифровой подписи. // Замечание: под win32 рекомендуется использовать _s аналоги CRT функций. //-------------------------------------------------------------------- #define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING) #ifdef _WIN32 #define CONTAINER _TEXT("test") #else #define CONTAINER _TEXT("\\\\.\\HDIMAGE\\test") #endif static void HandleError(char *s); static void CleanUp(void); static HCRYPTPROV hProv = 0; static HCRYPTHASH hHash = 0; static HCRYPTKEY hPubKey = 0; static BYTE *pbHash = NULL; static BYTE *pbSignature = NULL; static PCERT_PUBLIC_KEY_INFO pPubKeyInfo = 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 dwInfoLen; DWORD cbHash; FILE *signature; // Получение дескриптора контекста криптографического провайдера. if(CryptAcquireContext( &hProv, CONTAINER, NULL, PROV_GOST_2012_256, 0)) { printf("CSP context acquired.\n"); } else { HandleError("Error during CryptAcquireContext."); } //-------------------------------------------------------------------- //-------------------------------------------------------------------- // Экпорт открытого ключа. Здесь открытый ключ экспортируется в // CERT_PUBLIC_KEY_INFO для того, чтобы получатель подписанного хэша // мог проверить подпись. Содержимое этой структуры может быть // записано в файл и передано другому пользователю. if (CryptExportPublicKeyInfo( hProv, AT_SIGNATURE, MY_ENCODING_TYPE, NULL, &dwInfoLen)) { printf("Size of the CERT_PUBLIC_KEY_INFO determined.\n"); } else { HandleError("Error during CryptExportPublicKeyInfo for signkey."); } //-------------------------------------------------------------------- // Распределение памяти под pInfo. pPubKeyInfo = (PCERT_PUBLIC_KEY_INFO)malloc(dwInfoLen); if (!pPubKeyInfo) HandleError("Out of memory.\n"); // Экспорт ключевой информации в CERT_PUBLIC_KEY_INFO. if (CryptExportPublicKeyInfo( hProv, AT_SIGNATURE, MY_ENCODING_TYPE, pPubKeyInfo, &dwInfoLen)) { printf("Contents have been written to the CERT_PUBLIC_KEY_INFO.\n"); } else { HandleError("Error during CryptExportPublicKeyInfo for signkey."); } // Создание объекта функции хэширования. if(CryptCreateHash( hProv, CALG_GR3411_2012_256, 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); fclose(signature); // Уничтожение объекта функции хэширования. if(hHash) CryptDestroyHash(hHash); printf("The hash object has been destroyed.\n"); printf("The signing phase of this program is completed.\n\n"); //-------------------------------------------------------------------- // Во второй части программы проверяется подпись. // Чаще всего проверка осуществляется в случае, когда различные // пользователи используют одну и ту же программу. Хэш, подпись, // а также CERT_PUBLIC_KEY_INFO могут быть прочитаны из файла, e-mail // сообщения или из другого источника. // Здесь используюся определенные ранее pbBuffer, pbSignature, // pPubKeyInfo и их длины. // Содержимое буфера pbBuffer представляет из себя некоторые // подписанные ранее данные. //-------------------------------------------------------------------- // Импортирование откытого ключа пользователя, который создал цифровую // подпись, в CSP с помощью функции CryptImportPublicKeyInfo. // Она возвращает дескриптор открытого ключа в hPubKey. if(CryptImportPublicKeyInfo( hProv, MY_ENCODING_TYPE, pPubKeyInfo, &hPubKey )) { printf("The key has been imported.\n"); } else { HandleError("Public key import failed."); } //-------------------------------------------------------------------- // Создание нового объекта функции хэширования. if(CryptCreateHash( hProv, CALG_GR3411_2012_256, 0, 0, &hHash)) { printf("The hash object has been recreated. \n"); } else { HandleError("Error during CryptCreateHash."); } //-------------------------------------------------------------------- // Вычисление криптографического хэша буфера. 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 { HandleError("Signature not validated!\n"); } CleanUp(); return 0; } void CleanUp(void) { if(pbSignature) free(pbSignature); if(pbHash) free(pbHash); if (pPubKeyInfo) free(pPubKeyInfo); // Уничтожение объекта функции хэширования. if(hHash) CryptDestroyHash(hHash); 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: не поддерживает.