//-------------------------------------------------------------------- // Пример кода для работы в режиме SILENT, без окон. // В данном примере осуществляется подпись строки. // Для корректной работы этой программы необходимо создать контейнер с // именем "test" ключом подписи и без пароля. // В примере также демонстрируется предъявление неверного PIN-а. // Замечание: под win32 рекомендуется использовать _s аналоги CRT функций. //-------------------------------------------------------------------- static void HandleError(const char *s); static void CleanUp(void); static HCRYPTPROV hProv = 0; // Дескриптор CSP static HCRYPTKEY hKey = 0; // Дескриптор ключа static HCRYPTHASH hHash = 0; static BYTE *pbHash = NULL; static BYTE *pbKeyBlob = NULL; static BYTE *pbSignature = NULL; #define WRONG_PIN "1234" #define RIGHT_PIN NULL #ifdef _WIN32 #define CONTAINER _TEXT("\\\\.\\Registry\\test") #else #define CONTAINER _TEXT("\\\\.\\HDIMAGE\\test") #endif int main(void) { BYTE *pbBuffer = (BYTE *)"The data that is to be hashed and signed."; DWORD dwBufferLen = (DWORD)(strlen((char *)pbBuffer)+1); DWORD cbHash; DWORD dwSigLen; DWORD dwBlobLen; FILE *signature; // Получение дескриптора провайдера. if(CryptAcquireContext( &hProv, CONTAINER, NULL, PROV_GOST_2012_256, CRYPT_SILENT)) { printf("CryptAcquireContext succeeded.\n"); } else { if(GetLastError() == (DWORD)NTE_BAD_KEYSET || GetLastError() == (DWORD)NTE_KEYSET_NOT_DEF) { printf(" The key container with name \"Source\" does not exist.\n"); printf(" Create a container and generate keys \n"); exit(1); } else { HandleError("A general error occurred in CryptAcquireContext."); } } //-------------------------------------------------------------------- // Установка параметров в соответствии с паролем. if(!CryptSetProvParam( hProv, PP_KEYEXCHANGE_PIN, (BYTE*)WRONG_PIN, 0)) { printf("CryptSetProvParam failed (correct).\n"); } else { HandleError("Error: setting pin on container without password."); } if(CryptSetProvParam( hProv, PP_KEYEXCHANGE_PIN, (BYTE*)RIGHT_PIN, 0)) { printf("CryptSetProvParam succeeded.\n"); } else { HandleError("Error during CryptSetProvParam."); } //-------------------------------------------------------------------- // Получение ключа пользователя. if(CryptGetUserKey( hProv, AT_SIGNATURE, &hKey)) { printf("CryptGetUserKey succeeded.\n"); } else { HandleError("Error during CryptGetUserKey."); } //-------------------------------------------------------------------- // Экпорт открытого ключа. Здесь открытый ключ экспортируется в // PUBLICKEYBLOB для того, чтобы получатель подписанного хэша мог // проверить подпись. Этот BLOB может быть записан в файл и передан // другому пользователю. if(CryptExportKey( hKey, 0, PUBLICKEYBLOB, 0, NULL, &dwBlobLen)) { printf("Size of the BLOB for the public key determined. \n"); } else { if(GetLastError() == (DWORD)SCARD_W_WRONG_CHV) { HandleError("Bad password."); } 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_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\n" ); fwrite (pbSignature, 1, dwSigLen, signature); fclose(signature); CleanUp(); printf("The program ran to completion without error. \n"); return 0; } void CleanUp(void) { free(pbHash); free(pbKeyBlob); free(pbSignature); // Уничтожение объекта функции хэширования. if(hHash) CryptDestroyHash(hHash); printf("The hash object has been destroyed.\n"); printf("The signature is created.\n\n"); // Уничтожение дескриптора ключа пользователя. if(hKey) CryptDestroyKey(hKey); // Освобождение дескриптора провайдера. if(hProv) CryptReleaseContext(hProv, 0); } // Конец примера
AIX: 6/7.
FreeBSD: 11/12, pfSense 2.x.
Linux: LSB 4.x (RHEL 5/6/7/8, SuSE 11SP4/12/15, Oracle Linux 5/6/7/8, CentOS 6/7/8, Ubuntu 14.04/16.04/18.04/19.10, Linux Mint 18/19, Fedora 28/29/30/31, Debian 8/9/10 и др.).
Solaris: 10/11.
Mac OS X: 10.9/10.10/10.11/10.12/10.13/10.14/10.15.
iOS: 8/9/10/11/12/13.
Sailfish: 2/3.
Windows: 7/8/8.1/10, Server 2008/2008R2/2012/2012R2/2016/2019.