Hcryptkey что это
Перейти к содержимому

Hcryptkey что это

  • автор:

On-line справка по Win32 API

[New — Windows 95, OEM Service Release 2]
The CryptGetUserKey function retrieves a handle to a permanent user key pair, such as the user’s signature key pair.

BOOL CRYPTFUNC CryptGetUserKey(

HCRYPTPROV hProv,
DWORD dwKeySpec,
HCRYPTKEY *phUserKey
);

[in] A handle to the application’s CSP. An application obtains this handle using the CryptAcquireContext function.

[in] The specification of the key to retrieve. The following keys are retrievable from almost all providers:

· AT_KEYEXCHANGE ѕ Exchange public key
· AT_SIGNATURE ѕ Signature public key

Additionally, some providers allow access to other user specific keys through this function. See the documentation on the specific provider for details.

[out] The address that the function copies the handle of the retrieved key to.

If the function succeeds, the return value is nonzero.
If the function fails, the return value is zero. To retrieve extended error information, use the GetLastError function.
The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by «NTE» are generated by the particular CSP you are using.

Error Description
ERROR_INVALID_HANDLE One of the parameters specifies an invalid handle.
ERROR_INVALID_PARAMETER One of the parameters contains an invalid value. This is most often an illegal pointer.
NTE_BAD_KEY The dwKeySpec parameter contains an invalid value.
NTE_BAD_UID The hProv parameter does not contain a valid context handle.
NTE_NO_KEY The key requested by the dwKeySpec parameter does not exist.

HCRYPTPROV hProv = 0;
HCRYPTKEY hSignKey = 0;
HCRYPTKEY hXchgKey = 0;

// Do something with ‘hSignKey’ and ‘hXchgKey’.
.

// Destroy signature key handle.
if(hSignKey != 0) CryptDestroyKey(hSignKey);

// Destroy key exchange key handle.
if(hXchgKey != 0) CryptDestroyKey(hXchgKey);

// Release provider handle.
if(hProv != 0) CryptReleaseContext(hProv, 0);

CryptAcquireContext, CryptDestroyKey, CryptGenKey

CryptGetUserKey

[Новый — Windows NT]

[Новый — Окно 95, Выпуск Услуги OEM 2]
Функция CryptGetUserKey извлекает ручку в ключевую пару постоянного потребителя, как например, подпись потребителя ключевой пары.

BOOL CRYPTFUNC CryptGetUserKey(

HCRYPTPROV hProv, DWORD dwKeySpec, HCRYPTKEY *phUserKey
);

[in] ручка на прикладной CSP. Приложение получает эту ручку, использовавшую функцию CryptAcquireContext.

[in] спецификация ключа, чтобы извлекаться. Следующие ключи — retrievable из почти всех поставщиков:

AT_KEYEXCHANGE U Биржевой общественный ключ AT_SIGNATURE U общественный ключ Подписи

К тому же, некоторые поставщики допускают доступ к другим специфическим ключам потребителя через эту функцию. Смотри документацию на специфическом поставщике относительно деталей.

[out] адрес, что функция копирует ручку извлеченного ключа, чтобы.

Если функция добивается успеха, обратная величина ненулевая.
Если функция терпит неудачу, обратная величина нулевая. Для того, чтобы извлекать расширенную информацию ошибки, используйте функцию GetLastError.
Следующая таблица включает коды наиболее общей ошибки возвращанные функцией GetLastError. Ошибка кодирует prefaced «NTE» сгенерированы конкретным CSP, которое Вы используете.

Описание Ошибки
ERROR_INVALID_HANDLE Один из параметров определяет неправильную ручку.
ERROR_INVALID_PARAMETER Один из параметров содержит неправильную величину. Это — чаще всего незаконный указатель.
NTE_BAD_KEY параметр dwKeySpec содержит неправильную величину.
NTE_BAD_UID параметр hProv не содержит правильную контекстную ручку.
NTE_NO_KEY клавиша запрашивалась параметром dwKeySpec не существует.

HCRYPTPROV hProv = 0;
HCRYPTKEY hSignKey = 0;
HCRYPTKEY hXchgKey = 0;

// Сделайте что-то с ‘hSignKey и ‘hXchgKey.
.

// Уничтожьте ключевая ручка сигнатуры.
если(hSignKey != 0) CryptDestroyKey(hSignKey);

// Уничтожьте ключевую биржевую ключевую ручку.
если(hXchgKey != 0) CryptDestroyKey(hXchgKey);

// Ручка поставщика Версии.
если(hProv != 0) CryptReleaseContext(hProv, 0);

CryptAcquireContext, CryptDestroyKey, CryptGenKey

Как передать сессионный ключ для дешифровки в cryptoapi

Необходимо шифровать строки в файле при помощи CryptoAPI, а потом расшифровывать его и читать данные. Начальный ключ генерирую так:

 HCRYPTPROV hProv; HCRYPTKEY hSessionKey; if(!CryptAcquireContext(&hProv, nullptr, nullptr, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) < cout cout cout  

После этого передаю в функцию сохранения файла, которая для каждой строки вызывает функцию шифрования:

Crypto* CWEncrypt(const char* toEncode, HCRYPTKEY hSessionKey) < char *tempString; tempString = new char[strlen(toEncode)]; strcpy_s(tempString, strlen(tempString), toEncode); DWORD count = strlen(tempString); if(!CryptEncrypt(hSessionKey, NULL, true, NULL, reinterpret_cast(tempString), &count, count)) < cout auto response = new Crypto(tempString, hSessionKey); //Crypto is a struct with fields with types string and HCRYPTKEY return response; > 

После сохранения hSessionKey выводится пользователю на экран. Потом при попытке загрузиться из файла у человека спрашивают hSessionKey, который он вводит через cin. Этот же ключ отправляется в функцию дешифрования:

 char* CWDecrypt(const char* toDecode, HCRYPTKEY hSessionKey) < char *tempString; tempString = new char[strlen(toDecode)]; strcpy_s(tempString, strlen(tempString), toDecode); DWORD count = strlen(tempString); if(!CryptDecrypt(hSessionKey, NULL, true, NULL, reinterpret_cast(tempString), &count)) < cout return tempString; > 

И вот тут уже возникает ошибка - отрабатывает if и выдаёт Error, decrypting provided data . При этом сами функции рабочие, и такой код в мэйне работает:

 string ss = "String to encrypt and decrypt"; Crypto cr = *CWEncrypt(ss.c_str()); ss = cr.getValue(); cout  

Судя по всему, просто передать ключ не достаточно, и его нужно заново сгенерировать по какому-то другому ключу. hPov для этого не подходит, так как hSessionKey генерируется другой и расшифровать данные не получается. Среди функций нашёл CryptExportKey, но он в качестве параметра принимает ещё какой-то ключ, который я без понятия где взять. И очень большая просьба знатокам, даже если вопрос кажется глупым и простым, не молча минусить его, а хотя бы перед выставлением минуса ответить, как это реализовать, раз уж это так просто, а я дурак не догадался. Спасибо. UPD: Попытка сохранить hSessionKey в файл тоже успехом не увенчалась. UPD 2: Нашёл хоть какую-то информацию о CryptExportKey. В некоторых источниках написано, что второй ключ, который туда нужно передавать - это открытый ключ, который потом при дешифровании нужно будет ввести, но если он не нужен, то можно ввести NULL. При этом изначально нужно получать длину итогового экспортируемого ключа, и для этого нужно запустить CryptExportKey, и в качестве адреса, куда ключ записывать, передавать NULL:

 DWORD dwPublicKeyLen; if (!CryptExportKey( hSessionKey, hUserKey, SIMPLEBLOB, NULL, NULL /* Also I tried to use nullptr here, and it didn't help */, &dwPublicKeyLen)) < cout BYTE* hPublicKey = static_cast(malloc(dwPublicKeyLen)); if (!CryptExportKey( hSessionKey, NULL, SIMPLEBLOB, NULL, hPublicKey, &dwPublicKeyLen))

И на этом моменте отрабатывает первый if и выдаёт ошибку. Подумал, что, может, там ошиблись, и без открытого ключа экспортировать сессионный ключ нельзя, так что стал пробовать перед этим генерировать его, опять же по примерам, которые смог найти:

HCRYPTKEY hUserKey; if (!CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hUserKey))

Здесь ошибка (отработка if) начинает возникать уже при генерации этого ключа. Я в ещё большем замешательстве.

CryptoApi и Криптопровайдер VipNet CSP

На хабре довольно мало информации о Microsoft CryptoApi и нет упоминания о наших отечественных разработчиках, которые имеют лицензии в области шифрования информации, реализуют интерфейс CryptoApi и позволяют шифровать данные с использованием, например, ГОСТ 28147-89. Так что, если возникла необходимость зашифровать и передать данные, и сделать это с использованием отечественных стандартов, то вовсе необязательно изобретать велосипед, а можно воспользоваться криптопровайдером VipNet CSP.

Вкратце о Microsoft CryptoApi

Итак, CryptoAPI это — интерфейс программирования приложений, который обеспечивает разработчиков Windows-приложений стандартным набором функций для работы с криптопровайдером. Входит в состав операционных систем Microsoft. Большинство функций CryptoAPI поддерживается начиная с Windows 2000.
CryptoAPI поддерживает работу с асимметричными и симметричными ключами, то есть позволяет шифровать и расшифровывать данные, а также работать с электронными сертификатами. Набор поддерживаемых криптографических алгоритмов зависит от конкретного криптопровайдера.
Реализация всех алгоритмов (шифрования, цифровой подписи и т.п.) полностью выведена из состава самого Crypto API и реализуется в отдельных, независимых динамических библиотеках – «криптопровайдерах» (Cryptographic Service Provider – CSP). Сам же Crypto API просто предъявляет определенные требования к набору функций (интерфейсу) криптопровайдера и предоставляет конечному пользователю интерфейс работы с CSP. Для использования всех функций криптопровайдера достаточно знать его строковое имя и номер типа.

ViPNet CSP

VipNet CSP – это программный комплекс, который реализует интерфейс Microsoft CryptoApi.

  • Генерация закрытых и открытых ключей ЭЦП и шифрования в соответствии с алгоритмом ГОСТ Р 34.10 – 2001.
  • Вычисление хеш-функции в соответствии с алгоритмом ГОСТ Р 34.11-94.
  • Вычисление и проверка ЭЦП в соответствии с алгоритмом ГОСТ Р 34.10-2001.
  • Выработка случайных и псевдослучайных чисел, сессионных ключей шифрования.
  • Шифрование и имитозащита данных в соответствии с алгоритмом ГОСТ 28147-89.
  • Аутентификация и шифрование при передаче данных по протоколам SSL/TLS.
  • Операции с сертификатами открытых ключей, соответствующих стандарту X.509 v3.
Совместимость

ViPNet CSP функционирует под управлением ОС Windows 2000 (32 бит)/XP (32 бит)/Server 2003 (32 бит)/Vista (32 бит) /Windows 7 (32/64 бит).

К сожалению VipNet CSP – это платный продукт, но на сайте есть бета-версии, которые отлично функционируют.

Разобраться с криптопровайдером довольно легко, в скачиваемый пакет входит проработанная до мелочей документация, а также множество примеров кода. Скачать последнюю версию можно здесь. Более подробно ознакомиться с описанным выше криптопровайдером можно здесь.

Пример использования

Итак, мы инсталлировали криптопровайдер, можем написать программу, шифрующую данные с использованием ГОСТ 28147-89. В скачиваемом пакете (архиве) есть папка «ViPNet CSP SDK (для разработчиков)», найдем там заголовочный файл importitccsp.h, в нем объявлены необходимые нам константы. Смотрим пример:

HCRYPTPROV hProv;
HCRYPTKEY hSessionKey;

// Получение контекста криптопровайдера
// VPN_DEF_PROV и VPN_PROV_TYPE - указывают на то, что мы используем ViPNet CSP
if (!CryptAcquireContext(&hProv, NULL, VPN_DEF_PROV, VPN_PROV_TYPE, CRYPT_VERIFYCONTEXT))
printf("Error CryptAcquireContext");
return;
>

// Генерация сессионного ключа
// CPCSP_ENCRYPT_ID - используется ГОСТ 28147-89
if (!CryptGenKey(hProv, CPCSP_ENCRYPT_ID, CRYPT_ENCRYPT | CRYPT_DECRYPT, &hSessionKey))
printf("Error CryptGenKey");
return;
>

// Данные для шифрования
char data[]="habrahabr";
DWORD count=strlen(data);

// Тестовый вывод на экран
printf("Encrypted string: %s", data);

// Тестовый вывод на экран
printf("Decrypted string: %s", data);

// Освобождение контекста локальных переменных
CryptDestroyKey(hSessionKey);
CryptReleaseContext(hProv, 0);

Шифрование данных и расшифрование их на другом компьютере — тема отдельной статьи.
Спасибо за внимание.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *