22.10.2004 20:46:51Проблемы с CryptAcquireContext Ответов: 4
Артём Боженов
Возникла странная проблема при использовании функции CryptAcquireContext. С её помошью на дискете был создан контейнер, в нём создана пара ключей, для данных ключей создан сертификат в хранилище сертификатов в реестре. После этого дискету отформатировали. Теперь при вызове CryptAcquireContext с тем же именем контейнера и флагом CRYPT_NEWKEYSET возвращается NTE_EXISTS, несмотря на то, что установлена чистая дискета. Если же пытаться открыть контейнер без этого флага, либо с флагом CRYPT_DELETEKEYSET, выскакивает окошко "Вставьте ключевой носитель" с состоянием "Набор ключей не существует". Как быть в данной ситуации? Хотелось бы использовать данный контейнер повторно для создания другого ключа. Версия криптопровайдера - 2.0
Пример кода:
//Пытаемся создать
string conatinerName="\\\\.\\fat12_a\\abc";
if(!CryptAcquireContext(&m_hCryptProvCP,conatinerName.c_str(),CP_DEF_PROV,PROV_GOST_DH,CRYPT_NEWKEYSET/*CRYPT_SILENT*/))
{
//Если уже есть
if (GetLastError()==NTE_EXISTS)
{
if (::MessageBox(0,"Криптоконтейнер для хранения закрытого ключа КриптоПро для указанного конкурса уже существует.\n"
"Хотите ли Вы удалить существующий контейнер (и хранящиеся в нем ключ) и создать новый?",0,MB_ICONQUESTION|MB_YESNO)==IDYES)
{
//Пытаемся удалить
if(!CryptAcquireContext(&m_hCryptProvCP,/*"\\\\.\\fat12_a"*/conatinerName.c_str(),CP_DEF_PROV,PROV_GOST_DH,CRYPT_DELETEKEYSET/*|CRYPT_SILENT*/))
{
HandleError("Невозможно удалить криптоконтейнер для хранения закрытого ключа КриптоПро\n");
return CCryptoService::csNotInitializedCantCreateKeyContainer;
}
//Пытаемся создать ещё раз
if(!CryptAcquireContext(&m_hCryptProvCP,/*"\\\\.\\fat12_a"*/conatinerName.c_str(),CP_DEF_PROV,PROV_GOST_DH,CRYPT_NEWKEYSET/*|CRYPT_SILENT*/))
{
HandleError("Невозможно создать новый криптоконтейнер для хранения закрытого ключа КриптоПро\n");
return CCryptoService::csNotInitializedCantCreateKeyContainer;
}
}
else
{
HandleError("Невозможно создать новый криптоконтейнер для хранения закрытого ключа КриптоПро\n");
return CCryptoService::csNotInitializedCantCreateKeyContainer;
}
}
else
{
HandleError("Невозможно создать новый криптоконтейнер для хранения закрытого ключа КриптоПро\n");
return CCryptoService::csNotInitializedCantCreateKeyContainer;
}
}
 
Ответы:
25.10.2004 9:53:24Василий
Конечно, так и будет.
Потому что удалять контейнер надо стандартными средствами - CryptAcquireContext(..CRYPT_DELETEKEYSET).
Если же всё же хотите использовать то же имя повторно, то в разделе Сервис нашей контрольной панели (в версии 2.0) есть кнопочка "Удалить запомненные пароли", которая, в т.ч., очищает ссылки на существующие на съёмных носителях контейнеры.
25.10.2004 13:39:59Артём Боженов
Если вы могли заметить, то в 13 строчке приведенного листига и вызывается CryptAcquireContext(..CRYPT_DELETEKEYSET). При этом на экран выводится окошко "Вставьте ключевой носитель" с состоянием "Набор ключей не существует". Поскольку данного носителя у меня нет (ну отформатировали его, испортили или потеряли), то и удалить контейнер не получается. Просто у меня имя контейнера привязано (содержит) к идентификатору пользователя. И новый ключ для него хотелось бы завести в контейнере со старым именем.
А вот "удаление запомненных паролей" помогло. Отсюда вопрос - можно ли это сделать программным образом, чтобы не гонять пользователя в Контрол панель?
25.10.2004 15:24:55Василий
1. Ну разумеется, удалить CryptAcquireContext-ом можно только при наличии носителя.
2. Очистить ссылку на конкретный контейнер пользователя можно, удалив раздел реестра, содержащий её, например, HKEY_LOCAL_MACHINE\SOFTWARE\Crypto Pro\Settings\USERS\S-1-5-21-1993962763-492894223-1202660629-2126\KeyDevices\passwords\b912cceb-5104-4949-b300-a9560174120c,
где b912cceb-5104-4949-b300-a9560174120c - это имя контейнера.
Алгоритм действий будет таким:
поискать в HKEY_LOCAL_MACHINE\SOFTWARE\Crypto Pro\Settings\USERS подраздел с названием, равным имени контейнера и удалить его.
25.10.2004 15:33:49Боженов Артём
Большое спасибо