MS Crypto API Lab1

advertisement
Лабораторная работа №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)
Download