//-------------------------------------------------------------------- // Данный пример демонстрирует импорт закрытого ключа из блоба. // Блоб импортируемого закрытого Ключа хранится в файле EncryptedKeyBlob.enc. // Для корректной работы этого примера передаваемые ему входные данные // должны являться результатом работы примера EncryptKey. // Для корректной расшифровки импортируемого блоба закрытого ключа // необходимы вектор инициализации и соль, которые хранятся // в файлах "vector.bin" и "salt.bin". // Следует сделить за тем, чтобы контейнеры "Sender" и "Responder", // используемые в программах ExportInFile, EncryptKey и DecryptKey на момент // выполнения этих программ существовали. // Замечание: под win32 рекомендуется использовать _s аналоги CRT функций. //-------------------------------------------------------------------- #ifdef _WIN32 # define CONTAINER_COPY _TEXT("\\\\.\\registry\\SenderCopy") #else # define CONTAINER_COPY _TEXT("\\\\.\\hdimage\\SenderCopy") #endif #define CONTAINER_COPY_PIN "111" #pragma region Объявление переменных #define BLOCK_LENGTH 4096 #define SALT_LENGTH 16 static void HandleError(char *s); static void CleanUp(void); static HCRYPTPROV hProv = 0; // Дескриптор CSP для получения переданного ключа static HCRYPTKEY hKey = 0; // Дескриптор переданного закрытого Ключа отправителя AT_EXCHANGE static HCRYPTKEY hDerivedKey = 0; // Дескриптор сессионного ключа в hProv static HCRYPTHASH hHash = 0; // Дескриптор хэша пароля static FILE *vectorf=NULL; // Файл для хранения вектора инициализации static FILE *saltf = NULL; // Файл для хранения соли static FILE *EncryptedKeyBlob = NULL; // Файл блоба зашифрованного закрытого Ключа static CRYPT_DATA_BLOB salt = {0, NULL}; // Структура CRYPT_DATA_BLOB для хранения соли //#define PROVIDER_NAME NULL //#define PROVIDER_NAME "CP2001KC1" #pragma endregion int main(void) { BYTE *pbKeyBlobExport = NULL; // Указатель на BLOB переданного закрытого Ключа DWORD dwKeyBlobExportLen; // Длина блоба переданного закрытого Ключа BYTE pbIV[100]; // Вектор инициализации сессионного ключа DWORD dwIV = 0; // Длина вектора инициализации DWORD szf; BOOL bContExists = FALSE; ALG_ID ke_alg = CALG_PRO12_EXPORT; // Алгоритм сессионного ключа char password[] = "password"; // Пароль CRYPT_DATA_BLOB password_blob; // Структура CRYPT_DATA_BLOB для хранения пароля password_blob.pbData = (BYTE*)password; password_blob.cbData = (DWORD)strlen(password); // Выделение памяти под соль. salt.cbData = SALT_LENGTH; salt.pbData = (BYTE*)malloc(salt.cbData); if (!salt.pbData) HandleError("Out of memory."); // Открытие файла, в котором хранится соль. if(!(saltf = fopen("salt.bin", "r+b"))) HandleError( "Problem opening file 'salt.bin'\n" ); printf( "File 'salt.bin' was opened\n" ); // Чтение соли из файла. salt.cbData = (DWORD)fread(salt.pbData, 1, salt.cbData, saltf); if(!salt.cbData) HandleError( "Failed to read salt from 'salt.bin'\n" ); printf( "Salt was read from 'salt.bin'\n" ); // Открытие файла, в котором хранится вектор инициализации. if(!(vectorf = fopen("vector.bin", "r+b"))) HandleError( "Problem opening the file 'vector.bin'\n" ); printf( "The file 'vector.bin' was opened\n" ); // Чтение вектора инициализации из файла. dwIV = (DWORD)fread(pbIV, 1, 100, vectorf); if(!dwIV) HandleError( "The IV can not be reading from the 'vector.bin'\n" ); printf( "The IV was read from the 'vector.bin'\n" ); //Открытие Файла блоба зашифрованного закрытого Ключа if(!(EncryptedKeyBlob = fopen("EncryptedKeyBlob.enc", "r+b"))) HandleError( "Problem opening the file 'EncryptedKeyBlob.enc'\n" ); printf( "The file 'EncryptedKeyBlob.enc' was opened\n" ); //------------------------------------------------------------------ // получение зашифрованного закрытого Ключа //------------------------------------------------------------------ // находим размер файла EncryptedKeyBlob.enc, записываем его в szfile fseek(EncryptedKeyBlob, 0, SEEK_END); szf = ftell(EncryptedKeyBlob); fseek(EncryptedKeyBlob, 0, SEEK_SET); // выделение памяти pbKeyBlobExport = (BYTE*)malloc(szf); if (!pbKeyBlobExport) HandleError("Out of memory."); // чтение зашифрованного закрытого Ключа из файла EncryptedKeyBlob.enc dwKeyBlobExportLen = (DWORD)fread(pbKeyBlobExport, 1, szf, EncryptedKeyBlob); if(!dwKeyBlobExportLen) HandleError( "The private Key can not be reading from the 'EncryptedKeyBlob.enc'\n" ); printf( "The private Key was read from the 'EncryptedKeyBlob.enc'\n" ); //------------------------------------------------------------------ //------------------------------------------------------------------ // Получение дескриптора контейнера с именем "SenderCopy", // для хранения переданного закрытого Ключа. bContExists = CryptAcquireContext( &hProv, CONTAINER_COPY, NULL, PROV_GOST_2012_256, CRYPT_SILENT); if (bContExists) { if (!CryptSetProvParam( hProv, PP_DELETE_KEYSET, NULL, 0)) { HandleError("Error during CryptSetProvParam CRYPT_DELETEKEYSET"); } if (!CryptReleaseContext(hProv, 0)) { HandleError("Error during CryptReleaseContext"); } } if (!CryptAcquireContext( &hProv, CONTAINER_COPY, NULL, PROV_GOST_2012_256, CRYPT_NEWKEYSET | CRYPT_SILENT)) { HandleError("Error during CryptAcquireContext CRYPT_NEWKEYSET"); } if (!CryptSetProvParam( hProv, PP_KEYEXCHANGE_PIN, (BYTE*)CONTAINER_COPY_PIN, 0)) { HandleError("Failed to set PIN"); } printf("The key container \"SenderCopy\" has been acquired. \n"); //----------------------------------------------------------------- // Хэширование пароля //----------------------------------------------------------------- // Создание пустого объекта хэширования. 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."); } //----------------------------------------------------------------- // Расшифрование закрытого переданного Ключа //----------------------------------------------------------------- // Установка вектора инициализации - без него первые 8 байт // расшифруются неправильно. if(!CryptSetKeyParam( hDerivedKey, KP_SV, pbIV, 0)) { HandleError("Error during CryptSetKeyParam."); } printf( "CryptSetKeyParam succeeded. \n"); // Получение закрытого Ключа импортом зашифрованного закрытого Ключа // на ключе Derived в контейнер if(CryptImportKey( hProv, pbKeyBlobExport, dwKeyBlobExportLen, hDerivedKey, 0, &hKey)) { printf("The private Key has been imported. \n"); } else { HandleError("Error during CryptImportKey private Key."); } CleanUp(); printf("The program ran to completion without error. \n"); free(pbKeyBlobExport); return 0; }// Конец main void CleanUp(void) { if (EncryptedKeyBlob) fclose (EncryptedKeyBlob); if(vectorf) fclose (vectorf); if(saltf) fclose(saltf); // Уничтожение дескриптора переданного закрытого ключа. if(hKey) CryptDestroyKey(hKey); // Уничтожение дескриптора сессионного ключа. if(hDerivedKey) CryptDestroyKey(hDerivedKey); // Уничтожение дескриптора хэша. if(hHash) CryptDestroyHash(hHash); if (hProv) { // Удаление контейнера SenderCopy. CryptSetProvParam( hProv, PP_DELETE_KEYSET, NULL, 0); // Освобождение дескриптора провайдера. CryptReleaseContext(hProv, 0); } free(salt.pbData); } // Конец примера
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: не поддерживает.