Лабораторная работа №1. Работа с криптопровайдерами Microsoft CryptoAPI. Цель работы Получить основные навыки инициализации, запроса параметров и завершения работы с криптопровайдерами Microsoft CryptoAPI. Ход работы Изучить основные функции инициализации и получения параметров при работе с криптопровайдерами Microsoft CryptoAPI. Перенести пример программы, использующий основные функции в среду программирования, запустить на выполнение и проанализировать его работу. Сравнить результаты работы программы с примером результатов, приведенным в лабораторной работе. Перенести задание к лабораторной работе в среду программирования. Восстановить вырезанные фрагменты программы по описаниям и отладить полученную программу. Добавление кода осуществляется непосредственно в месте расположения комментария с описанием действия! Проанализировать работу полученной программы и сравнить результаты работы программы с примером результатов, приведенным в лабораторной работе. Описание основных используемых в лабораторной работе функций Microsoft Crypto API (функции определены в файле wincrypt.h, полное описание находится в MSDN, security.chm, .chi, в разделе Cryptography\CryptoAPI\Using CryptoAPI\CryptoAPI Reference\CryptoAPI Functions\Base CryptoAPI Functions\Service Provider Functions) CryptEnumProviderTypes получает первый или следующий тип поддерживаемых системой криптопровайдеров. Используя ее в цикле можно получить список всех доступных типов криптопровайдеров. BOOL WINAPI CryptEnumProviderTypes( DWORD dwIndex, // [вх] номер следующего перечисляемого типа. DWORD *pdwReserved, //[вх] должен быть NULL. Оставлен для использования в будущем. DWORD dwFlags, //[вх] должен быть 0. Оставлен для использования в будущем. DWORD *pdwProvType, //[вых] адрес значения содержащего перечисляемый тип. LPTSTR pszTypeName, //[вых] указатель на место, куда будет помещена строка с именем типа. Параметр может быть NULL для получения размера памяти необходимого для выделения. DWORD *pcbTypeName //[вх/вых] размер строки, записанной в предыдущий параметр. ); Возвращаемые значения: если все прошло нормально, ненулевое (TRUE), если произошла ошибка, то возвращается нуль (FALSE). Для анализа ошибки нужно вызвать GetLastError. Если она вернула значение ERROR_NO_MORE_ITEMS, то это не ошибка, а сигнал окончания списка типов криптопровайдеров. Таблица кодов остальных ошибок находится в MSDN. CryptEnumProviders получает первый или следующий из поддерживаемых системой криптопровайдеров. Используя ее в цикле можно получить список всех доступных криптопровайдеров. BOOL WINAPI CryptEnumProviders( DWORD dwIndex, // [вх] номер следующего перечисляемого провайдера. DWORD *pdwReserved, //[вх] должен быть NULL. Оставлен для использования в будущем. DWORD dwFlags, //[вх] должен быть 0. Оставлен для использования в будущем. DWORD *pdwProvType, //[вых] адрес значения содержащего тип перечисляемого провайдера. LPTSTR pszProvName, //[вых] указатель на место, куда будет помещена строка с именем провайдера. Параметр может быть NULL для получения размера памяти необходимого для выделения. DWORD *pcbProvName //[вх/вых] размер строки, записанной в предыдущий параметр. ); Возвращаемые значения: если все прошло нормально, ненулевое (TRUE), если произошла ошибка, то возвращается нуль (FALSE). Для анализа ошибки нужно вызвать GetLastError. Если она вернула значение ERROR_NO_MORE_ITEMS, то это не ошибка, а сигнал окончания списка типов криптопровайдеров. Если она вернула ERROR_MORE_DATA, то буфер pszProvName недостаточен для размещения в нем имени. Таблица кодов остальных ошибок находится в MSDN. CryptGetDefaultProvider получает криптопровайдер определенного типа, заданный в системе по умолчанию. BOOL WINAPI CryptGetDefaultProvider( DWORD dwProvType, //[вх] тип провайдера по умолчанию. Может быть одним из следующих: PROV_RSA_FULL, PROV_RSA_SIG, PROV_DSS, PROV_DSS_DH, PROV_DH_SCHANNEL, PROV_FORTEZZA, PROV_MS_EXCHANGE, PROV_RSA_SCHANNEL, PROV_SSL DWORD *pdwReserved, //[вх] должен быть NULL. Оставлен для использования в будущем DWORD dwFlags, //[вх] CRYPT_USER_DEFAULT ищет провайдер по умолчанию для данного пользователя. CRYPT_MACHINE_DEFAULT ищет провайдер по умолчанию системы. LPTSTR pszProvName, //[вых] указатель на место, куда будет помещена строка с именем провайдера. Параметр может быть NULL для получения размера памяти необходимого для выделения DWORD *pcbProvName //[вх/вых] размер строки, записанной в предыдущий параметр. ); Возвращаемые значения: если все прошло нормально, ненулевое (TRUE), если произошла ошибка, то возвращается нуль (FALSE). Для анализа ошибки нужно вызвать GetLastError. Если она вернула ERROR_MORE_DATA, то буфер pszProvName недостаточен для размещения в нем имени. Если она вернула ERROR_INVALID_PARAMETER, значит один из параметров является неправильным. Таблица кодов остальных ошибок находится в MSDN. CryptAcquireContext используется для получения дескриптора некоторого контейнера ключей в некотором криптопровайдере. Полученный дескриптор используется в вызовах функций CryptoAPI использующих выбранный криптопровайдер. Сначала функция пытается найти криптопровайдер с параметрами, описанными в dwProvType и pszProvider. Если криптопровайдер найден, функция пытается найти в нем контейнер ключей с именем, указанным в pszContainer. При заданных настройках dwFlags эта функция может создавать и уничтожать контейнеры ключей, а также обеспечивать доступ к криптопровайдеру с временным контейнером ключей если не требуется доступ к секретному ключу. BOOL WINAPI CryptAcquireContext( HCRYPTPROV *phProv, //[вых] указатель на дескриптор криптопровайдера. LPCTSTR pszContainer, //[вх] заканчивающаяся нулем строка с именем контейнера ключей. Если равен NULL, то используется контейнер по умолчанию. Когда dwFlags установлен в CRYPT_VERIFYCONTEXT, pszContainer должен быть NULL. LPCTSTR pszProvider, //[вх] заканчивающаяся нулем строка с именем криптопровайдера. Если равен NULL, то используется криптопровайдер по умолчанию. DWORD dwProvType, //[вх] задает тип получаемого криптопровайдера. DWORD dwFlags //[вх] значения флагов. Обычно этот параметр равен нулю, но приложения могут устанавливать один или несколько флагов, описанных ниже. ); Значения параметра dwFlags: CRYPT_VERIFYCONTEXT предназначен для приложений не использующих асимметричные ключевые пары, например приложений хеширования или симметричного шифрования. К секретному ключу должны иметь доступ только приложения расшифрования сообщений или создания подписей. Всем остальным приложениям желательно устанавливать этот флаг. В этом случае приложение не имеет доступа к парам открытых/секретных ключей, и pszContainer должен быть установлен в NULL. CRYPT_NEWKEYSET создает новый контейнер ключей с именем заданным в pszContainer. Если последний равен NULL, то создается контейнер с именем по умолчанию. CRYPT_MACHINE_KEYSET может совмещаться с остальными флагами для указания, что контейнер не пользовательский, а системный. По умолчанию же используются пользовательские ключи и контейнеры, а это значит, что доступ к ним может получить только пользователь создавший их или пользователь с администраторскими привилегиями. Права для доступа к системному контейнеру могут быть заданы с использованием CryptSetProvParam. Системные контейнеры полезны, если пользователь работает с ними из службы или не загрузился интерактивно. После создания контейнера большинством криптопровайдеров ключи автоматически не создаются. Их необходимо создать отдельно вызовом CryptGenKey. CRYPT_DELETEKEYSET уничтожает указанный в pszContainer контейнер ключей. Если pszContainer равен NULL, то удаляется контейнер ключей по умолчанию. Все ключевые пары в контейнере также уничтожаются. Если установлен этот флаг, то значение phProv не определено, и вызывать CryptReleaseContext не нужно. CRYPT_SILENT означает требование приложения, чтобы криптопровайдер не выводил ничего для этого контекста на экран. Если криптопровайдер должен выводить информацию для своей работы на экран, то выдается ошибка NTE_SILENT_CONTEXT. Возвращаемые значения: если все прошло нормально, ненулевое (TRUE), если произошла ошибка, то возвращается нуль (FALSE). Для анализа ошибки нужно вызвать GetLastError. Некоторые из возможных значений ошибок (таблица кодов остальных ошибок находится в MSDN): ERROR_BUSY: если установлен CRYPT_DELETEKEYSET а другой процесс использует этот контейнер. ERROR_INVALID_PARAMETER: один из параметров является неправильным. NTE_BAD_KEYSET: невозможно открыть контейнер. Скорее всего нет контейнера с таким именем. NTE_SIGNATURE_FILE_BAD, NTE_BAD_SIGNATURE: не прошла проверка подписи DLL провайдера. Либо подпись, либо DLL были подменены. NTE_EXISTS: если установлен CRYPT_NEWKEYSET, а контейнер с таким именем уже существует. NTE_KEYSET_ENTRY_BAD: контейнер найден, но поврежден. NTE_KEYSET_NOT_DEF: не найден провайдер или контейнер с заданным именем. NTE_PROV_TYPE_NO_MATCH: тип провайдера не соответствует найденному криптопровайдеру. Эта ошибка возможна, если pszProvider задает имя конкретного криптопровайдера. CryptGetProvParam получает параметры, управляющие работой криптопровайдера. BOOL WINAPI CryptGetProvParam( HCRYPTPROV hProv, DWORD dwParam, //[вх] дескриптор криптопровайдера, созданный вызовом CryptAcquireContext. //[вх] обозначает предмет запроса (см. ниже) BYTE *pbData, //[вых] указатель на место, куда будет помещена строка с именем провайдера. Параметр может быть NULL для получения размера памяти необходимого для выделения. DWORD *pdwDataLen, //[вх/вых] указатель на размер строки, записанной в предыдущий параметр. Если pdbData равен NULL и запрос PP_ENUMALGS или PP_ENUMALGS_EX, параметр содержит размер максимальной записи из списка. DWORD dwFlags //[вх] флаги (см. ниже). ); Возможные значения dwParam: PP_CONTAINER, PP_UNIQUE_CONTAINER: имя текущего контейнера ключа. PP_ENUMALGS: структура PROV_ENUMALGS, содержащая сокращенную информацию об одном алгоритме, поддерживаемом криптопровайдером. Значения должны запрашиваться последовательно чтобы получить все поддерживаемые алгоритмы. При первом вызове должен быть установлен флаг CRYPT_FIRST в dwFlags. При следующих вызовах dwFlags должен быть установлен в 0. Список окончился, если выдан код ошибки ERROR_NO_MORE_ITEMS. typedef struct _PROV_ENUMALGS { ALG_ID aiAlgid; // идентификатор алгоритма DWORD dwBitLen; // длина ключа DWORD dwNameLen; // длина имени алгоритма CHAR szName[20];// имя алгоритма } PROV_ENUMALGS; PP_ENUMALGS_EX: расширенная информация об алгоритме (вариант PP_ENUMALGS). typedef struct _PROV_ENUMALGS_EX { ALG_ID aiAlgid; // идентификатор алгоритма DWORD dwDefaultLen; // длина ключа по умолчанию DWORD dwMinLen; // минимальная длина ключа DWORD dwMaxLen; // максимальная длина ключа DWORD dwProtocols; // количество поддерживаемых протоколов DWORD dwNameLen; // длина короткого имени протокола CHAR DWORD CHAR szName[20];// строка с именем поддерживаемого протокола dwLongNameLen; // длина полного имени протокола szLongName[40]; // строка с длинным именем протокола } PROV_ENUMALGS_EX; PP_ENUMCONTAINERS: строка с именем одного из контейнеров ключей поддерживаемого криптопровайдером. Список получается так же как и с помощью PP_ENUMALGS. PP_IMPTYPE: значение DWORD, означающее вид реализации криптопровайдера. CRYPT_IMPL_HARDWARE – аппаратный, CRYPT_IMPL_SOFTWARE – программный, CRYPT_IMPL_MIXED аппаратно-программный, CRYPT_IMPL_UNKNOWN – неизвестный. PP_NAME: строка с именем криптопровайдера. PP_VERSION: номер версии криптопровайдера. Два младших байта содержат номер версии. PP_SIG_KEYSIZE_INC и PP_KEYX_KEYSIZE_INC: шаг изменения длины ключей подписи и обмена. PP_KEYSET_SEC_DESCR: указатель на дескриптор безопасности контейнера ключей. PP_PROVTYPE: значение DWORD, соответствующее типу криптопровайдера. PP_USE_HARDWARE_RNG: проверяет поддержку аппаратного генератора случайных чисел. Если поддерживается, то функция возвращает TRUE, если нет – FALSE. При использовании этого значения параметр pbData должен быть равен NULL, а dwFlags – 0. PP_KEYSPEC: возвращает информацию о поддерживаемых криптопровайдером спецификаторах ключа. Некоторые возможные значения dwFlags: CRYPT_FIRST используется при получении списка для выдачи первого значения. CRYPT_MACHINE_KEYSET может использоваться совместно с PP_ENUMCONTAINERS для получения списка системных (а не пользовательских) контейнеров ключей. Возвращаемые значения: если все прошло нормально, ненулевое (TRUE), если произошла ошибка, то возвращается нуль (FALSE). Для анализа ошибки нужно вызвать GetLastError. Если она вернула значение ERROR_NO_MORE_ITEMS, то это не ошибка, а сигнал окончания списка. Если она вернула ERROR_MORE_DATA, то буфер pbData недостаточен для размещения в нем информации. Если она вернула ERROR_INVALID_PARAMETER, ERROR_INVALID_HANDLE, NTE_BAD_FLAGS или NTE_BAD_UID, значит один из параметров является неправильным. Таблица кодов остальных ошибок находится в MSDN. CryptReleaseContext освобождает дескриптор криптопровайдера и контейнера ключей. При каждом вызове этой функции счетчик подключений уменьшается на единицу. Когда он достигает нуля, контекст полностью освобождается и не может использоваться никакой функцией приложения. Приложение вызывает эту функцию после окончания использования криптопровайдера. После ее вызова дескриптор провайдера более недействителен. Функция не уничтожает контейнеры ключей или ключевые пары. BOOL WINAPI CryptReleaseContext( HCRYPTPROV hProv, //[вх] дескриптор криптопровайдера, созданный вызовом CryptAcquireContext. DWORD dwFlags //[вх] должен быть 0. Оставлен для использования в будущем. ); Возвращаемые значения: если все прошло нормально, ненулевое (TRUE), если произошла ошибка, то возвращается нуль (FALSE). Для анализа ошибки нужно вызвать GetLastError. Если она вернула ERROR_BUSY, то контекст криптопровайдера в данный момент используется другим процессом. Если она вернула ERROR_INVALID_PARAMETER, ERROR_INVALID_HANDLE, NTE_BAD_FLAGS или NTE_BAD_UID, значит один из параметров является неправильным. Таблица кодов остальных ошибок находится в MSDN. Примечания. После вызова функции сеанс работы криптопровайдера заканчивается и все существующие сеансовые ключи и хеш-объекты созданные с использованием дескриптора hProv становятся недействительными. В практике все эти объекты должны быть уничтожены вызовами CryptDestroyKey и CryptDestroyHash до вызова CryptReleaseContext. Пример программы, использующей основные функции #include "stdafx.h" #define _WIN32_WINNT 0x0500 #define WINVER 0x0500 #include <stdio.h> #include <windows.h> #include <wincrypt.h> void HandleError(char *s) { printf("An error occurred in running the program.\n"); printf("%s\n",s); printf("Error number %x\n.",GetLastError()); printf("Program terminating.\n"); exit(1); } void main() { HCRYPTPROV hProv; // Дескриптор криптопровайдера LPTSTR pszName; DWORD dwType; DWORD cbName; DWORD dwIndex=0; BYTE *ptr; ALG_ID aiAlgid; DWORD dwBits; DWORD dwNameLen; CHAR szName[100]; // Часто выделяется динамически BYTE pbData[1024];// Часто выделяется динамически DWORD cbData=1024; DWORD dwIncrement = sizeof(DWORD); DWORD dwFlags=CRYPT_FIRST; DWORD dwParam = PP_CLIENT_HWND; CHAR *pszAlgType = NULL; BOOL fMore=TRUE; LPTSTR pbProvName; DWORD cbProvName; //-------------------------------------------------------------// Печать заголовка таблицы типов криптопровайдеров. printf("\n Listing Available Provider Types.\n"); printf("Type Provider Type Name\n"); printf("____ ________________________________\n"); // Цикл перечисления типов криптопровайдеров. dwIndex = 0; while(CryptEnumProviderTypes( dwIndex, // вх -- dwIndex NULL, // вх -- pdwReserved- установить NULL 0, // вх -- dwFlags – установить 0 &dwType, // вых -- pdwProvType NULL, // вых -- pszProvName -- NULL при первом вызове &cbName // вх, вых -- pcbProvName )) { //-------------------------------------------------------------------// cbName — длина имени следующего типа криптопровайдеров. // Выделяем участок памяти для размещения этого имени. if (!(pszName = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, cbName))) { HandleError("ERROR - LocalAlloc failed!"); } //-------------------------------------------------------------------// Получаем название типа криптопровайдера. if (CryptEnumProviderTypes( dwIndex++, NULL, NULL, &dwType, pszName, &cbName)) { printf ("%4.0d %s\n",dwType, pszName); } else { HandleError("ERROR - CryptEnumProviders"); } LocalFree(pszName); } //-------------------------------------------------------------// Печать заголовка списка криптопровайдеров. printf("\n\n Listing Available Providers.\n"); printf("Type Provider Name\n"); printf("____ ________________________________\n"); //---------------------------------------------------------------// Цикл перечисления криптопровайдеров. dwIndex = 0; while(CryptEnumProviders( dwIndex, // in -- dwIndex NULL, // in -- pdwReserved- установить NULL 0, // in -- dwFlags – установить 0 &dwType, // out -- pdwProvType NULL, // out -- pszProvName -- NULL при первом вызове &cbName // in, out -- pcbProvName )) { //-------------------------------------------------------------------// cbName — длина имени следующего криптопровайдера. // Выделяем участок памяти для размещения этого имени. if (!(pszName = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, cbName))) { HandleError("ERROR - LocalAlloc failed!"); } //-------------------------------------------------------------------// Получаем название криптопровайдера. if (CryptEnumProviders( dwIndex++, NULL, 0, &dwType, pszName, &cbName // pcbProvName – размер pszName )) { printf ("%4.0d %s\n",dwType, pszName); } else { HandleError("ERROR - CryptEnumProviders"); } LocalFree(pszName); } // Конец цикла while //----------------------------------------------------------------// Получаем имя провайдера по умолчанию относящегося к PROV_RSA_FULL // //--------------------------------------------------------------// Получаем длину его имени. if (!(CryptGetDefaultProvider( PROV_RSA_FULL, NULL, CRYPT_MACHINE_DEFAULT, NULL, &cbProvName))) { HandleError("Error getting the length of the default provider name."); } //--------------------------------------------------------------// Выделяем память для размещения имени криптопровайдера по умолчанию if (!(pbProvName = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, cbProvName))) { HandleError("Error during memory allocation for provider name."); } //--------------------------------------------------------------// Получаем имя криптопровайдера типа PROV_RSA_FULL. if (CryptGetDefaultProvider( PROV_RSA_FULL, NULL, CRYPT_MACHINE_DEFAULT, pbProvName, &cbProvName)) { printf("\n\nThe default provider name is %s\n\n",pbProvName); } else { HandleError("Getting the name of the provider failed."); } //----------------------------------------------------// Получаем криптографический контекст (инициализируем криптопровайдер). if(!CryptAcquireContext( &hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT )) { HandleError("Error during CryptAcquireContext!"); } //-----------------------------------------------------// Получаем список поддерживаемых алгоритмов. //-----------------------------------------------------// Печать заголовка таблицы информации об алгоритмах printf(" Enumerating the supported algorithms\n\n"); printf(" Algid Bits Type printf(" printf(" Name Algorithm\n"); Length Name\n"); ________________________________________________________\n"); while(fMore) { //-----------------------------------------------------// Получение информации об очередном алгоритме. if(CryptGetProvParam(hProv, PP_ENUMALGS, pbData, &cbData, dwFlags)) { //----------------------------------------------------------// Достаем информацию из буфера 'pbData'. dwFlags=0; ptr = pbData; aiAlgid = *(ALG_ID *)ptr; ptr += sizeof(ALG_ID); dwBits = *(DWORD *)ptr; ptr += dwIncrement; dwNameLen = *(DWORD *)ptr; ptr += dwIncrement; strncpy(szName,(char *) ptr, dwNameLen); //-------------------------------------------------------// Определяем тип алгоритма. switch(GET_ALG_CLASS(aiAlgid)) { case ALG_CLASS_DATA_ENCRYPT: pszAlgType = "Encrypt "; break; case ALG_CLASS_HASH: pszAlgType = "Hash "; break; case ALG_CLASS_KEY_EXCHANGE: pszAlgType = "Exchange "; break; case ALG_CLASS_SIGNATURE: pszAlgType = "Signature"; break; default: pszAlgType = "Unknown "; } //-----------------------------------------------------------// Печатаем информацию об алгоритме. printf(" %8.8xh %-4d %s %-2d %s\n", aiAlgid, dwBits, pszAlgType, dwNameLen, szName ); } else fMore=FALSE; } if(GetLastError() == ERROR_NO_MORE_ITEMS) { printf("\nThe program completed without error.\n"); } else { HandleError("Error reading algorithm!"); } } Пример результата работы программы Listing Available Provider Types. Type Provider Type Name ____ ________________________________ 1 RSA Full (Signature and Key Exchange) 3 DSS Signature 12 RSA SChannel 13 DSS Signature with Diffie-Hellman Key Exchange 18 Diffie-Hellman SChannel Listing Available Providers. Type Provider Name ____ ________________________________ 1 Gemplus GemSAFE Card CSP v1.0 1 Microsoft Base Cryptographic Provider v1.0 13 3 18 1 Microsoft Base DSS and Diffie-Hellman Cryptographic Provider Microsoft Base DSS Cryptographic Provider Microsoft DH SChannel Cryptographic Provider Microsoft Enhanced Cryptographic Provider v1.0 13 Microsoft Enhanced DSS and Diffie-Hellman Cryptographic Provider 12 Microsoft RSA SChannel Cryptographic Provider 1 Microsoft Strong Cryptographic Provider 1 Schlumberger Cryptographic Service Provider The default provider name is Microsoft Strong Cryptographic Provider Enumerating the supported algorithms Algid Bits Type Name Algorithm Length Name ________________________________________________________ 00006602h 40 Encrypt 4 RC2 00006801h 40 Encrypt 4 RC4 00006601h 56 Encrypt 4 DES 00006609h 112 Encrypt 13 3DES TWO KEY 00006603h 168 Encrypt 5 3DES 00008004h 160 Hash 6 SHA-1 00008001h 128 Hash 4 MD2 00008002h 128 Hash 4 MD4 00008003h 128 Hash 4 MD5 00008008h 288 Hash 12 SSL3 SHAMD5 00008005h 64 Hash 4 MAC 00002400h 512 Signature 9 RSA_SIGN 0000a400h 512 Exchange 9 RSA_KEYX 00008009h 0 Hash 5 HMAC The program completed without error. Задание к лабораторной работе Заполнить указанные пропуски в программе вывода списка криптопровайдеров с параметрами реализуемых в них алгоритмов. #include "stdafx.h" #define _WIN32_WINNT 0x0500 #define WINVER 0x0500 #include <windows.h> #include <stdio.h> /* 1. Вставить заголовочный файл для работы с Microsoft CryptoAPI */ // Определение массива имен типов криптопровайдеров LPTSTR szProvType[]={ NULL, "RSA Full (Signature and Key Exchange)", "RSA Signature", "DSS Signature", "PROV_FORTEZZA", "PROV_MS_EXCHANGE", "PROV_SSL", NULL, NULL, NULL, NULL, NULL, "RSA SChannel", "DSS Signature with Diffie-Hellman Key Exchange", "PROV_EC_ECDSA_SIG", "PROV_EC_ECNRA_SIG", "PROV_EC_ECDSA_FULL", "PROV_EC_ECNRA_FULL", "Diffie-Hellman SChannel", NULL, "PROV_SPYRUS_LYNKS", "PROV_RNG", "PROV_INTEL_SEC"}; // Определение массива имен типов исполнения криптопровайдеров LPTSTR szImpType[]={ NULL, "Hardware", "Software", "Mixed", "Unknown", "Not define", "Not define", "Not define", "Removable", "Type 9", "Type 10", "Type 11"}; // Определение массива имен классов алгоритмов LPTSTR szAlgClass[]={ NULL, "Signature", "Encrypt ", "Encrypt ", "Hash ", "Exchange ", "All "}; // Определение и инициализация переменных HMODULE hDll=0; DWORD dwCount, cbName; DWORD dwDataLen, dwIndex=0; WCHAR swzProvName[100]; CHAR szName[100]; PROV_ENUMALGS AlgInfo; PROV_ENUMALGS_EX CHAR AlgInfoEx; *pszAlgType = NULL; LPWSTR pswzProvName=NULL; LPWSTR pszProvName=NULL; DWORD dwProvType, dwCryptError, dwVersion, dwImpType; DWORD dwFlags=0; HCRYPTPROV DWORD hProv = 0; dwSigKeySizeInc, dwXchKeySizeInc; void main(void) { // Цикл перечисления криптопровайдеров. while (/* 2. Имя функции? */(dwIndex, NULL,0, &dwProvType, NULL, &cbName)){ if (/* 3. Имя функции? */(dwIndex++,NULL,0,&dwProvType,szName, &cbName)){ // Открываем контекст криптопровайдера if (! /* 4. Открыть контекст криптопровайдера не подключаясь к контейнерам ключей. Дескриптор – hProv, имя и тип криптопровайдера получаем из вызова предыдущей функции перечисления криптопровайдеров */ ) { printf("Error:CryptAcquireContext=0x%X.\n",GetLastError()); break; } // Получаем версию криптопровайдера dwDataLen = sizeof(DWORD); if (!CryptGetProvParam( hProv, PP_VERSION, (PBYTE)&dwVersion, &dwDataLen, 0)) { printf("Error:CryptGetProvParam=0x%X.\n",GetLastError()); goto ReleaseResource; } // Получаем тип исполнения криптопровайдера dwDataLen = sizeof(DWORD); if (! /* 5. В переменную dwImpType получить вид реализации криптопровайдера с дескриптором hProv (аппаратный, программный или аппаратно-программный) */ ) { printf("Error:CryptGetProvParam=0x%X.\n",GetLastError()); goto ReleaseResource; } // Распечатываем полученную информацию printf("\n\n\nProvider name: %s\n", szName); printf("Provider version: %d.%d\n", HIBYTE(LOWORD(dwVersion)), LOBYTE(LOWORD(dwVersion))); printf("Provider type: %s\n", szProvType[dwProvType]); printf("Provider implementation type: %s\n", szImpType[dwImpType]); // Распечатываем заголовок таблицы алгоритмов printf("\n printf("AlgId|Type |Length info (bits)|\n"); |Def |Max |Min |Name \n"); printf("-----+---------+-----+------+-----+----------------\n"); // Перечисляем алгоритмы криптопровайдера for (dwCount=0 ; ; dwCount++) { // Устанавливаем флаг CRYPT_FIRST // при первом обращении в цикле. if (dwCount == 0) dwFlags = CRYPT_FIRST; else dwFlags = 0; // Получаем информацию об алгоритмах dwDataLen = sizeof(PROV_ENUMALGS_EX); dwCryptError=ERROR_SUCCESS; // Запрашиваем расширенную информацию об алгоритмах if (! /* 6. В переменную AlgInfoEx получить расширенную информацию об алгоритмах криптопровайдера с дескриптором hProv. В переменную dwDataLen получить длину AlgInfoEx. Необходимые значения флагов уже записаны в переменную dwFlags */ ) { dwCryptError=GetLastError(); if (dwCryptError == ERROR_NO_MORE_ITEMS) break; if (dwCryptError == NTE_BAD_FLAGS || dwCryptError== NTE_BAD_TYPE) { dwDataLen = sizeof(PROV_ENUMALGS); // Если криптопровайдер не поддерживает расширенный запрос, то // запрашиваем сокращенную информацию об алгоритмах if (! /* 7. В переменную AlgInfo получить сокращенную информацию об алгоритмах криптопровайдера с дескриптором hProv. В переменную dwDataLen получить длину AlgInfo. Необходимые значения флагов уже записаны в переменную dwFlags */ ) { /* 8. Проанализировать код возникшей ошибки. Если возникла ошибка, показывающая конец списка алгоритмов, то прервать цикл */ printf("Error %x reading algorithm!\n",GetLastError()); goto ReleaseResource; } AlgInfoEx.aiAlgid=AlgInfo.aiAlgid; AlgInfoEx.dwDefaultLen=AlgInfo.dwBitLen; AlgInfoEx.dwMaxLen=0; AlgInfoEx.dwMinLen=0; lstrcpy(AlgInfoEx.szLongName,AlgInfo.szName); } else { printf("Error %x reading algorithm!\n",GetLastError()); goto ReleaseResource; } } // Распечатываем полученную информацию printf( "%4.4xh|%s|%-4d |%-5d |%-4d |%s \n", AlgInfoEx.aiAlgid, szAlgClass[GET_ALG_CLASS(AlgInfoEx.aiAlgid) >> 13], AlgInfoEx.dwDefaultLen, AlgInfoEx.dwMaxLen, AlgInfoEx.dwMinLen, AlgInfoEx.szLongName); } // Окончание работы с криптопровайдером /* 9. Освободить дескриптор криптопровайдера hProv */ hProv=0; } } // Аварийное завершение работы с криптопровайдером ReleaseResource: if (hProv)/* 10. Освободить дескриптор криптопровайдера hProv */ ; return; } Пример результата работы программы Provider name: Gemplus GemSAFE Card CSP v1.0 Provider version: 0.0 Provider type: RSA Full (Signature and Key Exchange) Provider implementation type: Type 11 |Length info (bits)| AlgId|Type |Def |Max |Min |Name -----+---------+-----+------+-----+---------------6602h|Encrypt |40 |128 |40 |RSA Data Security's RC2 6801h|Encrypt |40 |128 |40 |RSA Data Security's RC4 6601h|Encrypt |56 |56 |56 |Data Encryption Standard (DES) 6609h|Encrypt |112 |112 |112 |Two Key Triple DES 6603h|Encrypt |168 |168 |168 |Three Key Triple DES 8004h|Hash |160 |160 |160 |Secure Hash Algorithm (SHA-1) 8001h|Hash |128 |128 |128 |Message Digest 2 (MD2) 8002h|Hash |128 |128 |128 |Message Digest 4 (MD4) 8003h|Hash |128 |128 |128 |Message Digest 5 (MD5) 8008h|Hash |288 |288 |288 |SSL3 SHAMD5 8005h|Hash |0 |0 |0 |Message Authentication Code 2400h|Signature|1024 |1024 |512 |RSA Signature a400h|Exchange |512 |512 |512 |RSA Key Exchange 8009h|Hash |0 |0 |Hugo's MAC (HMAC) |0 Provider name: Microsoft Base Cryptographic Provider v1.0 Provider version: 2.0 Provider type: RSA Full (Signature and Key Exchange) Provider implementation type: Software |Length info (bits)| AlgId|Type |Def |Max |Min |Name -----+---------+-----+------+-----+---------------6602h|Encrypt |40 |56 |40 |RSA Data Security's RC2 6801h|Encrypt |40 |56 |40 |RSA Data Security's RC4 6601h|Encrypt |56 |56 |56 |Data Encryption Standard (DES) 8004h|Hash |160 |160 |160 |Secure Hash Algorithm (SHA-1) 8001h|Hash |128 |128 |128 |Message Digest 2 (MD2) 8002h|Hash |128 |128 |128 |Message Digest 4 (MD4) 8003h|Hash |128 |128 |128 |Message Digest 5 (MD5) 8008h|Hash |288 |288 |288 |SSL3 SHAMD5 8005h|Hash |0 |0 |0 |Message Authentication Code 2400h|Signature|512 |16384 |384 |RSA Signature a400h|Exchange |512 |1024 |384 |RSA Key Exchange 8009h|Hash |0 |0 |Hugo's MAC (HMAC) |0 Provider name: Microsoft Base DSS and Diffie-Hellman Cryptographic Provider Provider version: 1.0 Provider type: DSS Signature with Diffie-Hellman Key Exchange Provider implementation type: Software |Length info (bits)| AlgId|Type |Def |Max |Min |Name -----+---------+-----+------+-----+---------------660ch|Encrypt |40 |40 |40 |CYLINK Message Encryption Algorithm 6602h|Encrypt |40 |56 |40 |RSA Data Security's RC2 6801h|Encrypt |40 |56 |40 |RSA Data Security's RC4 6601h|Encrypt |56 |56 |56 |Data Encryption Standard (DES) 8004h|Hash |160 |160 |160 |Secure Hash Algorithm (SHA-1) 8003h|Hash |128 |128 |128 |Message Digest 5 (MD5) 2200h|Signature|1024 |1024 |512 |Digital Signature Algorithm aa01h|Exchange |512 |1024 |512 |Diffie-Hellman Key Exchange Algorithm aa02h|Exchange |512 |1024 |512 |Diffie-Hellman Ephemeral Algorithm Provider name: Microsoft Base DSS Cryptographic Provider Provider version: 1.0 Provider type: DSS Signature Provider implementation type: Software |Length info (bits)| AlgId|Type |Def |Max |Min |Name -----+---------+-----+------+-----+---------------8004h|Hash |160 |160 |160 |Secure Hash Algorithm (SHA-1) 8003h|Hash |128 |128 2200h|Signature|1024 |1024 |128 |Message Digest 5 (MD5) |512 |Digital Signature Algorithm Provider name: Microsoft DH SChannel Cryptographic Provider Provider version: 1.0 Provider type: Diffie-Hellman SChannel Provider implementation type: Software |Length info (bits)| AlgId|Type |Def |Max |Min |Name -----+---------+-----+------+-----+---------------660ch|Encrypt |40 |40 |40 |CYLINK Message Encryption Algorithm 6602h|Encrypt |40 |128 |40 |RSA Data Security's RC2 6801h|Encrypt |40 |128 |40 |RSA Data Security's RC4 6601h|Encrypt |56 |56 |56 |Data Encryption Standard (DES) 6609h|Encrypt |112 |112 |112 |Two Key Triple DES 6603h|Encrypt |168 |168 |168 |Three Key Triple DES 8004h|Hash |160 |160 |160 |Secure Hash Algorithm (SHA-1) 8003h|Hash |128 |128 |128 |Message Digest 5 (MD5) 2200h|Signature|1024 |1024 |1024 |Digital Signature Algorithm aa01h|Exchange |512 |4096 |512 |Diffie-Hellman Key Exchange Algorithm aa02h|Exchange |512 |4096 |512 |Diffie-Hellman Ephemeral Algorithm Provider name: Microsoft Enhanced Cryptographic Provider v1.0 Provider version: 2.0 Provider type: RSA Full (Signature and Key Exchange) Provider implementation type: Software |Length info (bits)| AlgId|Type |Def |Max |Min |Name -----+---------+-----+------+-----+---------------6602h|Encrypt |128 |128 |40 |RSA Data Security's RC2 6801h|Encrypt |128 |128 |40 |RSA Data Security's RC4 6601h|Encrypt |56 |56 |56 |Data Encryption Standard (DES) 6609h|Encrypt |112 |112 |112 |Two Key Triple DES 6603h|Encrypt |168 |168 |168 |Three Key Triple DES 8004h|Hash |160 |160 |160 |Secure Hash Algorithm (SHA-1) 8001h|Hash |128 |128 |128 |Message Digest 2 (MD2) 8002h|Hash |128 |128 |128 |Message Digest 4 (MD4) 8003h|Hash |128 |128 |128 |Message Digest 5 (MD5) 8008h|Hash |288 |288 |288 |SSL3 SHAMD5 8005h|Hash |0 |0 |0 |Message Authentication Code 2400h|Signature|1024 |16384 |384 |RSA Signature a400h|Exchange |1024 |16384 |384 |RSA Key Exchange 8009h|Hash |Hugo's MAC (HMAC) |0 |0 |0 Provider name: Microsoft Enhanced DSS and Diffie-Hellman Cryptographic Provider Provider version: 1.0 Provider type: DSS Signature with Diffie-Hellman Key Exchange Provider implementation type: Software |Length info (bits)| AlgId|Type |Def |Max |Min |Name -----+---------+-----+------+-----+---------------660ch|Encrypt |40 |40 |40 |CYLINK Message Encryption Algorithm 6602h|Encrypt |40 |128 |40 |RSA Data Security's RC2 6801h|Encrypt |40 |128 |40 |RSA Data Security's RC4 6601h|Encrypt |56 |56 |56 |Data Encryption Standard (DES) 6609h|Encrypt |112 |112 |112 |Two Key Triple DES 6603h|Encrypt |168 |168 |168 |Three Key Triple DES 8004h|Hash |160 |160 |160 |Secure Hash Algorithm (SHA-1) 8003h|Hash |128 |128 |128 |Message Digest 5 (MD5) 2200h|Signature|1024 |1024 |512 |Digital Signature Algorithm aa01h|Exchange |512 |4096 |512 |Diffie-Hellman Key Exchange Algorithm aa02h|Exchange |512 |4096 |512 |Diffie-Hellman Ephemeral Algorithm Provider name: Microsoft RSA SChannel Cryptographic Provider Provider version: 2.0 Provider type: RSA SChannel Provider implementation type: Software |Length info (bits)| AlgId|Type |Def |Max |Min |Name -----+---------+-----+------+-----+---------------6602h|Encrypt |128 |128 |40 |RSA Data Security's RC2 6801h|Encrypt |128 |128 |40 |RSA Data Security's RC4 6601h|Encrypt |56 |56 |56 |Data Encryption Standard (DES) 6609h|Encrypt |112 |112 |112 |Two Key Triple DES 6603h|Encrypt |168 |168 |168 |Three Key Triple DES 8004h|Hash |160 |160 |160 |Secure Hash Algorithm (SHA-1) 8003h|Hash |128 |128 |128 |Message Digest 5 (MD5) 8008h|Hash |288 |288 |288 |SSL3 SHAMD5 8005h|Hash |0 |0 |0 |Message Authentication Code 2400h|Signature|1024 |16384 |384 |RSA Signature a400h|Exchange |1024 |16384 |384 |RSA Key Exchange 8009h|Hash |Hugo's MAC (HMAC) |0 |0 |0 Provider name: Microsoft Strong Cryptographic Provider Provider version: 2.0 Provider type: RSA Full (Signature and Key Exchange) Provider implementation type: Software |Length info (bits)| AlgId|Type |Def |Max |Min |Name -----+---------+-----+------+-----+---------------6602h|Encrypt |40 |128 |40 |RSA Data Security's RC2 6801h|Encrypt |40 |128 |40 |RSA Data Security's RC4 6601h|Encrypt |56 |56 |56 |Data Encryption Standard (DES) 6609h|Encrypt |112 |112 |112 |Two Key Triple DES 6603h|Encrypt |168 |168 |168 |Three Key Triple DES 8004h|Hash |160 |160 |160 |Secure Hash Algorithm (SHA-1) 8001h|Hash |128 |128 |128 |Message Digest 2 (MD2) 8002h|Hash |128 |128 |128 |Message Digest 4 (MD4) 8003h|Hash |128 |128 |128 |Message Digest 5 (MD5) 8008h|Hash |288 |288 |288 |SSL3 SHAMD5 8005h|Hash |0 |0 |0 |Message Authentication Code 2400h|Signature|512 |16384 |384 |RSA Signature a400h|Exchange |512 |16384 |384 |RSA Key Exchange 8009h|Hash |0 |Hugo's MAC (HMAC) |0 |0 Provider name: Schlumberger Cryptographic Service Provider Provider version: 5.0 Provider type: RSA Full (Signature and Key Exchange) Provider implementation type: Type 11 |Length info (bits)| AlgId|Type |Def |Max |Min |Name -----+---------+-----+------+-----+---------------6602h|Encrypt |40 |128 |40 |RSA Data Security's RC2 6801h|Encrypt |40 |128 |40 |RSA Data Security's RC4 6601h|Encrypt |56 |56 |56 |Data Encryption Standard (DES) 6609h|Encrypt |112 |112 |112 |Two Key Triple DES 6603h|Encrypt |168 |168 |168 |Three Key Triple DES 8004h|Hash |160 |160 |160 |Secure Hash Algorithm (SHA-1) 8001h|Hash |128 |128 |128 |Message Digest 2 (MD2) 8002h|Hash |128 |128 |128 |Message Digest 4 (MD4) 8003h|Hash |128 |128 |128 |Message Digest 5 (MD5) 8008h|Hash |288 |288 |288 |SSL3 SHAMD5 8005h|Hash |0 |0 |0 |Message Authentication Code 2400h|Signature|1024 |1024 |1024 |RSA Signature a400h|Exchange |1024 |1024 |1024 |RSA Key Exchange 8009h|Hash |0 |0 |0 |Hugo's MAC (HMAC)