//-------------------------------------------------------------------- // В данном примере реализовано шифрование закрытого ключа AT_KEYEXCHANGE // на открытом ключе получателя. // // Следует сделить за тем, чтобы контейнеры "Sender" и "Responder", // используемые в программах ExportInFile, EncryptKey и DecryptKey на момент // выполнения этих программ существовали. //-------------------------------------------------------------------- #pragma region vars #define BLOCK_LENGTH 4096 #define SALT_LENGTH 16 static void WriteBlobToFile(BYTE *pbData, DWORD cbData,char *FName); static void HandleError(const char *s); static void CleanUp(void); static HCRYPTPROV hProv = 0; // Дескриптор CSP static HCRYPTKEY hKey = 0; // Дескриптор копируемого закрытого Ключа отправителя AT_EXCHANGE static HCRYPTKEY hDerivedKey = 0; // Дескриптор сессионного ключа static HCRYPTHASH hHash = 0; // Дескриптор хэша пароля static BYTE *pbKeyBlobExport = NULL; // Указатель на BLOB копирумого закрытого Ключа отправителя AT_EXCHANGE static BYTE *pbIV = NULL; // Вектор инициализации закрытого Ключа static CRYPT_DATA_BLOB salt = {0, NULL}; // Структура CRYPT_DATA_BLOB для хранения соли #pragma endregion #define MAX_PUBLICKEYBLOB_SIZE 200 int main(void) { DWORD dwKeyBlobExportLen; // Длина BLOBа передаваемого ключа DWORD dwIV = 0; // Длина вектора инициализации ALG_ID ke_alg = CALG_PRO12_EXPORT; // Алгоритм сессионного ключа char password[] = "password"; // Пароль CRYPT_DATA_BLOB password_blob; // Структура CRYPT_DATA_BLOB для хранения пароля password_blob.cbData = (DWORD)strlen(password); password_blob.pbData = (BYTE*)password; // Получение дескриптора контейнера получателя с именем "Sender" if(CryptAcquireContext( &hProv, _TEXT("Sender"), NULL, PROV_GOST_2012_256, 0)) { printf("The key container \"Sender\" has been acquired. \n"); } else { HandleError("Error during CryptAcquireContext."); } // Заполнение соли случайными байтами. salt.cbData = SALT_LENGTH; salt.pbData = (BYTE*)malloc(salt.cbData); if (!salt.pbData) HandleError("Out of memory."); CryptGenRandom(hProv, salt.cbData, salt.pbData); // Запись соли в файл. WriteBlobToFile(salt.pbData, salt.cbData, "salt.bin"); //---------------------------------------------------------------------------- // Хэширование пароля. //---------------------------------------------------------------------------- // Создание пустого объекта хэширования. if (!CryptCreateHash( hProv, CALG_PBKDF2_2012_512, 0, 0, &hHash)) { HandleError("CryptCreateHash failed."); } // Задание соли. if (!CryptSetHashParam( hHash, HP_PBKDF2_SALT, (BYTE*)&salt, 0)) { HandleError("CryptSetHashParam HP_PBKDF2_SALT failed."); } // Задание строки пароля. if (!CryptSetHashParam( hHash, HP_PBKDF2_PASSWORD, (BYTE*)&password_blob, 0)) { HandleError("CryptSetHashParam HP_PBKDF2_PASSWORD failed."); } //-------------------------------------------------------------------- // Создание сессионного ключа, основанного на хэше, полученном из пароля. if(CryptDeriveKey( hProv, CALG_G28147, hHash, CRYPT_EXPORTABLE, &hDerivedKey)) { printf("The key has been derived. \n"); } else { HandleError("Error during CryptDeriveKey!"); } // Установление PRO12_EXPORT алгоритма сессионного ключа if(CryptSetKeyParam( hDerivedKey, KP_ALGID, (LPBYTE)&ke_alg, 0)) { printf("PRO12_EXPORT agree key algorithm has been set. \n"); } else { HandleError("Error during CryptSetKeyParam agree key."); } //-------------------------------------------------------------------- // Зашифрование закрытого Ключа. //-------------------------------------------------------------------- // Получение дескриптора закрытого Ключа, который будет скопирован. if(CryptGetUserKey( hProv, AT_KEYEXCHANGE, &hKey)) { printf("The sender private key has been acquired. \n"); } else { HandleError("Error during CryptGetUserKey private key."); } //-------------------------------------------------------------------- // Определение размера вектора инициализации Ключа. if(CryptGetKeyParam( hDerivedKey, KP_SV, NULL, &dwIV, 0)) { printf("Size of the IV for the sender secret Key determined. \n"); } else { HandleError("Error computing IV length."); } pbIV = (BYTE*)malloc(dwIV); if (!pbIV) HandleError("Out of memory. \n"); // Определение вектора инициализации Ключа. if(CryptGetKeyParam( hDerivedKey, KP_IV, pbIV, &dwIV, 0)) { printf( "CryptGetKeyParam succeeded. \n"); } else { HandleError("Error during CryptGetKeyParam."); } // Запись вектора инициализации в файл. WriteBlobToFile(pbIV, dwIV, "vector.bin"); //-------------------------------------------------------------------- // Определение размера BLOBа Ключа и распределение памяти. if(CryptExportKey( hKey, hDerivedKey, PRIVATEKEYBLOB, 0, NULL, &dwKeyBlobExportLen)) { printf("Size of the BLOB for the sender secret Key determined. \n"); } else { HandleError("Error computing BLOB length."); } pbKeyBlobExport = (BYTE*)malloc(dwKeyBlobExportLen); if(!pbKeyBlobExport) HandleError("Out of memory. \n"); // Зашифрование Ключа на ключе Derived. if(CryptExportKey( hKey, hDerivedKey, PRIVATEKEYBLOB, 0, pbKeyBlobExport, &dwKeyBlobExportLen)) { printf("Contents have been written to the BLOB. \n"); } else { HandleError("Error during CryptExportKey."); } // запись блоба зашифрованного ключа WriteBlobToFile(pbKeyBlobExport, dwKeyBlobExportLen, "EncryptedKeyBlob.enc"); return 0; } void WriteBlobToFile(BYTE *pbData, DWORD cbData, char *FName ) { FILE *file; // Открытие файла на запись в него BLOB-а if((file = fopen(FName, "wb"))) { printf("The file '%s' was opened\n", FName); } else { fclose(file); HandleError("Problem opening the file\n"); } // Запись BLOB-а в файл if(fwrite(pbData, 1, cbData, file)) { printf("The blob was written to the '%s'\n", FName); } else { fclose(file); HandleError("The blob can not be written to file."); } fclose(file); } void CleanUp(void) { // Уничтожение дескриптора копируемого закрытого ключа. if(hKey) CryptDestroyKey(hKey); // Уничтожение дескриптора сессионного ключа. if(hDerivedKey) CryptDestroyKey(hDerivedKey); // Уничтожение дескриптора хэша. if(hHash) CryptDestroyHash(hHash); // Освобождение дескриптора провайдера. if(hProv) CryptReleaseContext(hProv, 0); free(pbKeyBlobExport); free(pbIV); free(salt.pbData); } // Конец примера
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.