//-------------------------------------------------------------------- // Пример кода, использующего CryptAcquireContext. //-------------------------------------------------------------------- #define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING) static HCRYPTPROV hCryptProv = 0; static HCRYPTKEY hKey = 0; static void CleanUp(void); static void HandleError(const char *s); int main(int argc, char *argv[]) { // Объявление и инициализация переменных. BYTE pbData[MAX_CONTAINER_NAME_LEN+1]; DWORD cbData; BOOL bSilent = FALSE; // Флаг режима без окон if (argc > 1 && strcmp(argv[1], "-silent") == 0) bSilent = TRUE; printf("Mode: %s\n", bSilent ? "SILENT" : "NORMAL"); // Получение дескриптора криптопровайдера. if(!CryptAcquireContext( &hCryptProv, CONTAINER, NULL, PROV_GOST_2012_256, (bSilent ? CRYPT_SILENT : 0))) { if(GetLastError() != (DWORD)NTE_BAD_KEYSET && GetLastError() != (DWORD)NTE_KEYSET_NOT_DEF) { HandleError("A general error occurred running CryptAcquireContext"); } printf(" The default key container does not exist.\n"); printf(" Create a default container and generate keys \n"); printf(" Using the code in \n"); printf(" Example C Program: Creating a Key Container and Generating Keys \n"); printf(" Before running this program. \n"); CleanUp(); exit(1); } printf("CryptAcquireContext succeeded.\n"); // Чтение имени CSP. cbData = MAX_CONTAINER_NAME_LEN; if(!CryptGetProvParam( hCryptProv, PP_NAME, NULL, &cbData, 0)) { HandleError("Error reading CSP name. \n"); } if(cbData > MAX_CONTAINER_NAME_LEN) HandleError("CSP name length is too long"); pbData[MAX_CONTAINER_NAME_LEN] = 0; if(!CryptGetProvParam( hCryptProv, PP_NAME, pbData, &cbData, 0)) { HandleError("Error reading CSP name. \n"); } printf("CryptGetProvParam succeeded.\n"); printf("Provider name: %s\n", pbData); // Чтение имени ключевого контейнера. cbData = MAX_CONTAINER_NAME_LEN; if(!CryptGetProvParam( hCryptProv, PP_CONTAINER, pbData, &cbData, 0)) { HandleError("Error reading key container name. \n"); } if(cbData > MAX_CONTAINER_NAME_LEN) HandleError("Container name length is too long"); if(!CryptGetProvParam( hCryptProv, PP_CONTAINER, pbData, &cbData, 0)) { HandleError("Error reading key container name. \n"); } printf("CryptGetProvParam succeeded. \n"); printf("Key Container name: %s\n", pbData); // Выполнение криптографических операций. // Увеличение счетчика ссылок на криптопровайдер. Когда счетчик ссылок на // криптопровайдер становится больше 1, CryptReleaseContext уменьшает // счетчик ссылок, но не освобождает криптопровайдер. if(!CryptContextAddRef( hCryptProv, NULL, 0)) { HandleError("Error during CryptContextAddRef!\n"); } printf("CryptContextAddRef succeeded. \n"); // Счетчик ссылок на hCryptProv сейчас больше 1. Первый вызов // функции CryptReleaseContext не освободит дескриптор криптопровайдера. // Однократное освобождение контекста. if(!CryptReleaseContext(hCryptProv, 0)) { HandleError("Error during CryptReleaseContext! #1"); } printf("The first call to CryptReleaseContext succeeded. \n"); // Повторное освобождение дескриптора криптопровайдера. if(!CryptReleaseContext(hCryptProv, 0)) { HandleError("Error during CryptReleaseContext! #2"); } printf("The second call to CryptReleaseContext succeeded. \n"); // Получение дескриптора криптопровайдера и // создание ключевого контейнера с именем "KC1_test". if(!CryptAcquireContext( &hCryptProv, #ifdef _WIN32 _TEXT("\\\\.\\REGISTRY\\KC1_test"), #else _TEXT("\\\\.\\HDIMAGE\\KC1_test"), #endif NULL, PROV_GOST_2012_256, CRYPT_NEWKEYSET | (bSilent ? CRYPT_SILENT : 0))) { HandleError("Error during CryptAcquireContext for a new key " "container. A container with this name probably " "already exists"); } printf("CryptAcquireContext (CRYPT_NEWKEYSET) succeeded. \n"); // begin Особенность КриптоПро CSP // Особенностью КриптоПро CSP является то, что криптопровайдер // физически не создает (записывает) контейнер, если в нем // нет закрытых ключей. Поэтому необходимо создать ключ. if(!CryptGenKey( hCryptProv, AT_SIGNATURE, 0, &hKey)) { HandleError("Error occurred creating a signature key.\n"); } printf("Created a signature key pair.\n"); if(!CryptDestroyKey(hKey)) { HandleError("Error occurred destroy a signature key in memory.\n"); } // end Особенность КриптоПро CSP // Выполнение криптографических операций. // Освобождение дескриптора криптопровайдера и ключевого контейнера KC1. if(!CryptReleaseContext(hCryptProv, 0)) { HandleError("Error during CryptReleaseContext!\n"); } printf("CryptReleaseContext succeeded. \n"); hCryptProv = 0; hKey = 0; // Получение дескриптора криптопровайдера, используя новый ключевой контейнер. // Замечание: Этот ключевой контейнер будет пустым до тех пор, пока ключи // не будут явно созданы с помощью функции CryptGenKey. if(!CryptAcquireContext( &hCryptProv, _TEXT("KC1_test"), NULL, PROV_GOST_2012_256, 0)) { HandleError("Error during CryptAcquireContext!\n"); } printf("Acquired the key set just created. \n"); // Выполнение криптографических операций. // Освобождение дескриптора криптопровайдера и ключевого контейнера KC1. if(!CryptReleaseContext(hCryptProv, 0)) { HandleError("Error during CryptReleaseContext!\n"); } printf("CryptReleaseContext succeeded. \n"); hCryptProv = 0; // Для повторного испоьзования этого примера необходимо удалить созданный // ключей контейнер с именем "КС1". Контейнер можно удалить при помощи // контрольной панели КриптоПро CSP или следующим образом: if(!CryptAcquireContext( &hCryptProv, _TEXT("KC1_test"), NULL, PROV_GOST_2012_256, CRYPT_DELETEKEYSET)) { HandleError("Error during CryptAcquireContext(CRYPT_DELETEKEYSET)!\n"); } printf("CryptAcquireContext (CRYPT_DELETEKEYSET) succeeded. \n"); CleanUp(); return 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.