05.04.2005 9:22:10Симметричные ключи Ответов: 11
Иван
На сколько я понимаю, симметричные ключи в КриптоПро - это временные ключи, которые нельзя сохранить для последующего использования, например, на токене.

В частности, у меня есть задача шифрования/расшифрования файлов с даными, используемых моей программой. Эти файлы должны храниться неопределённо долго. Если я не могу сохранить (экспортировать) сессионный ключ, то эта задача невыполнима. Конечно, можно воспользоваться двумя парами ключей для схемы Д-Х для экспорта, но это как-то некрасиво...

PS.
Как, в таком случае, работает аладиновский SecretDisk совместно с CryptoPro CSP ?

 
Ответы:
05.04.2005 10:16:01uri
Экспорт сессионного ключа в КриптоПро CSP возможен.
Т.е. сделав сессионный ключ (например, CryptGenKey (hProv, CALG_G28147, CRYPT_EXPORTABLE, &hSessionKey)), пошифровав на нем, его можно экспортировать (CryptExportKey) в ключевой блоб. А дальше уже сами работайте с этим блобом (передавайте, сохраняйте и т.д.)
Про аладиновский SecretDisk нуно спрашивать у его производителя.
05.04.2005 19:45:29Иван
если порыться в этом форуме, то неоднократно писалось, что экспорт сессионного ключа реализуется только по схеме DH.

В любом случае, этот код возвращает при экспорте ошибку NTE_BAD_KEY_STATE :

// создание ключевого контейнера CPAcquireContext(
&crtmgr_win->prov,
asCont1.c_str(),
CRYPT_NEWKEYSET + CRYPT_MACHINE_KEYSET,
&crtmgr_win->pTable);

// генерируем сессионный ключ
CPGenKey(
crtmgr_win->prov,
CALG_G28147, CRYPT_EXPORTABLE,
&crtmgr_win->key_sess );



CPExportKey( crtmgr_win->prov,
crtmgr_win->key_sess,
0/*crtmgr_win->key_agree*/,
SIMPLEBLOB,
0,
pbSessionKey,
&cbSessionKey );

Подскажите, где ошибка ?
06.04.2005 10:24:35Юрий
Вот готовая работающая процедура по простоту экспорту сессионного ключа:

//***************************************************************************
// Простой экспорт сессионного ключа
//
void Base_ExportKey()
{
std::cout<<std::endl;
std::cout<<" Simple export and import key "<<std::endl;
std::cout<<"================================"<<std::endl;

HCRYPTPROV hProv;
HCRYPTKEY hKey,hPublicKey,hNewKey;

// Инициализация контекста криптопровайдера (с указанием имени ключевого контейнера)
if(!CryptAcquireContext(&hProv,
"{EB57ED8A-CCCC-4bf5-8659-9DF2F05F24AD}",
NULL,
PROV_RSA_FULL,
0))
return;

std::cout<<"Cryptographic provider initialized"<<std::endl;

// Генарация ключа для тестирования
if(!CryptGenKey(hProv,
CALG_RC4,
CRYPT_EXPORTABLE | CRYPT_ENCRYPT | CRYPT_DECRYPT,
&hKey))
return;

std::cout<<"Session key generated"<<std::endl;

// Данные для тестирования
char string[]="Test";
DWORD count=strlen(string);

// Пробное шифрование данных
if(!CryptEncrypt(hKey,0,true,0,(BYTE*)string,&count,strlen(string)))
return;

std::cout<<"Encryption completed"<<std::endl;

// Получение ключа для экспорта ключа шифрования
if(!CryptGetUserKey(hProv,AT_KEYEXCHANGE ,&hPublicKey))
return;

std::cout<<"Public key is received"<<std::endl;

count=0;

// Первичное получение размера массива для экспорта ключа
if(!CryptExportKey(hKey,hPublicKey,SIMPLEBLOB,0,NULL,&count))
return;

// Инициализация массива для экспорта ключа
BYTE* data=static_cast<BYTE*>(malloc(count));
ZeroMemory(data,count);

// Окончательный экспорт ключа шифрования
if(!CryptExportKey(hKey,hPublicKey,SIMPLEBLOB,0,data,&count))
return;

std::cout<<"Key&rsquo;s export completed"<<std::endl;

// Импорт ключа шифрования из полученного массива данных
if(!CryptImportKey(hProv,data,count,hPublicKey,0,&hNewKey))
return;

std::cout<<"Key&rsquo;s import completed"<<std::endl;

// Проверочное расшифрование на полученном ключе
count=strlen(string);

if(!CryptDecrypt(hNewKey,0,true,0,(BYTE*)string,&count))
return;

std::cout<<"Decryption completed"<<std::endl;

// Тестовый вывод на экран
std::cout<<"Result string: "<<string<<std::endl;

// Освобождение контекстов локальных переменных
free(data);

CryptDestroyKey(hKey);
CryptDestroyKey(hPublicKey);
CryptDestroyKey(hNewKey);
CryptReleaseContext(hProv,0);
}
//***************************************************************************
06.04.2005 10:27:08Юрий
Кстати, в приведенном коде (не моем) используется алгоритм SIMPLEBLOB, который предполагает использование публичного ключа для шифрования сессионного. А самого публичного ключа нет. Если хочеться не использовать публичный ключ можно посоветовать использование типа PUBLICKEYBLOB.
06.04.2005 11:16:26Иван
> Кстати, в приведенном коде (не моем) используется алгоритм SIMPLEBLOB, который предполагает использование публичного ключа для шифрования сессионного. А самого публичного ключа нет. Если хочеться не использовать публичный ключ можно посоветовать использование типа PUBLICKEYBLOB.

Т.е. Вы хотите сказать, что публичного ключа в приведенном в примере контейнере нет ? Тогда почему функция не вылетает на этом:
// Получение ключа для экспорта ключа шифрования
if(!CryptGetUserKey(hProv,AT_KEYEXCHANGE ,&hPublicKey))
return;

И я не понял, что означает эта строка: "Если хочеться не использовать публичный ключ можно посоветовать использование типа PUBLICKEYBLOB."

не могли бы Вы пояснить? Спасибо.
06.04.2005 11:43:51Юрий
Хм... Короче, для хранения публичных ключей используется так называемый ключевой контейнер. А его нужно предварительно создать и записать в него собственно ключевую пару (пары). В приведенном коде этот этап опущен (он делается в другом месте). Вот код функции, собственно создающей новый ключевой контейнер и генерирующий ключевую пару:

//******************************************************************************
// Подготовка ключевого контейнера.
//
void FirstAction()
{
HCRYPTPROV hProv;
HCRYPTKEY hExKey, hSignKey;

// Инициализация контекста криптопровайдера (с попыткой создания нового ключевого контейнера)
if(!CryptAcquireContext(&hProv,"{EB57ED8A-CCCC-4bf5-8659-9DF2F05F24AD}",NULL,PROV_RSA_FULL,0))
{
if(!CryptAcquireContext(&hProv,"{EB57ED8A-CCCC-4bf5-8659-9DF2F05F24AD}",NULL,PROV_RSA_FULL,CRYPT_NEWKEYSET))
return;

// Генерация нового публичного ключа, предназначенного для обмена сессионными ключами
if(!CryptGenKey(hProv,AT_KEYEXCHANGE,CRYPT_EXPORTABLE | CRYPT_ENCRYPT | CRYPT_DECRYPT,&hExKey))
return;

// Генерация нового публичного ключа, предназначенного для создания цифровой подписи
if(!CryptGenKey(hProv,AT_SIGNATURE,CRYPT_EXPORTABLE | CRYPT_ENCRYPT | CRYPT_DECRYPT,&hSignKey))
return;

// Освобождение контекстов локальных переменных
CryptDestroyKey(hExKey);
CryptDestroyKey(hSignKey);
}

CryptReleaseContext(hProv,0);
}
//******************************************************************************

То есть просто напросто ключевого контейнера с именем "{EB57ED8A-CCCC-4bf5-8659-9DF2F05F24AD}" нет на исполняемой машине. Его первично нужно создать.
06.04.2005 11:44:49Юрий
А про PUBLICKEYBLOB можно (и нужно) почитать в MSDN.
06.04.2005 11:49:39Юрий
А насчет отсутсвия публичного ключа, то его нет в коде:
CPExportKey( crtmgr_win->prov,
crtmgr_win->key_sess,
0/*crtmgr_win->key_agree*/,
SIMPLEBLOB,
0,
pbSessionKey,
&cbSessionKey );

А должен быть.
06.04.2005 15:04:16Иван
Спасибо, я понял, что Вы имеете ввиду, но всё это мне известно.

Дело в том, что экспорт сессионного ключа в криптопровайдере КриптоПро, возможен лишь по алгоритму D-H. Пример, приводимый Вами, содержит в себе обращение с майкрософтовскими базовыми провайдерами, которые позволяют выполниить экспорт на одной паре ключей - это механизм у меня не вызывает проблем в реализации.

Меня интересует только CryptoPro CSP!
06.04.2005 15:30:05Василий
Да, экспорт сессионного ключа A возможен только на ключе Диффи-Хеллмана К. Но, есть вариант получения ключа К из другого сессионного ключа Б заменой алгоритма на CALG_PRO_EXPORT или CALG_SIMPLE_EXPORT. Теперь вопрос - как сообщить получателю ключ Б для возможности расшифрования ключа А. Вариант - вообще не передавать ключ Б, а генерить его из пароля (или некоторой постоянной последовательности, в качестве которой можно взять значение некоторого открытого ключа)функцией CryptDeriveKey как на стороне отправителя, так и на стороне получателя.
06.04.2005 15:36:22Юрий
...Жалко, нет с собой исходников первой версии "КриптоАРМ"... Там я делал экспорт сессионного ключа в свой формат данных для всех криптопровайдеров. В особенности для криптопровайдера от КриптоПРО :) А вот как делал - уже не помню :)

Возможно, в понедельник смогу предоставить примеры такого кода.