02.11.2004 20:25:37CryptDecryptMessage, CryptFindCertificateKeyProvInfo и сертификаты Ответов: 2
Боженов Артём
Добрый день.
Столкнулся со следующей проблемой. CryptDecryptMessage срабатывает только после вызова CryptFindCertificateKeyProvInfo для соответствующего сертификата.

Я генерирую ключ (CryptGenKey), создаю для него сертификат (CertCreateSelfSignCertificate), создаю хранилище сетрификатов на памяти (CertOpenStore( CERT_STORE_PROV_MEMORY...), добавляю сертификат в хранилище (CertAddCertificateContextToStore), экспортирую его в файл (PFXExportCertStoreEx). Всё проходит замечательно, создаётся файл с сертификатом.
Передаю данный файл другому пользователю. Он шифрует при помощи данного сертификата некоторый текст (CryptEncryptMessage). Тоже всё проходит успешно.

Проблемы начинаются, когда я пытаюсь его дешифровать.
Я вызываю PFXImportCertStore, т.е. импортирую хранилище с данным сертификатом, (содержащим только открытый ключ) на машину получателя, затем CryptDecryptMessage и получаю CRYPT_E_NO_DECRYPT_CERT в GetLastError, несмотря на то, что ключевая дискета (на которой хранится сгенеренный закрытый ключ) установлена в дисковод.
Но. Если между PFXImportCertStore и CryptDecryptMessage вызвать CryptFindCertificateKeyProvInfo для единственного ключа, содержащегося в импортированном хранилище, то выскакивает череда диалоговых окошек, спрашивающих пароли для всех контейнеров, наличиствующих в системе, функция возвращает true (т.е. что ключ есть). И последующий вызов CryptDecryptMessage приводит к повторному запросу пароля к контейнеру, содержащему ключ и успешной дешифрации.

Отсюда вопрос - как добиться дешифровки без промежуточного вызова CryptFindCertificateKeyProvInfo?

Пример кода:
//publicPFX содержит ранее экспортированное хранилище с единственным сертификатом
HCERTSTORE hStore=PFXImportCertStore(&publicPFX,0,0);
CertStoreArray[certStoresCount]=hStore;
certStoresCount++;

//Вот этот кусок позволяет успешно декодировать
BOOL certFound=FALSE;
for (PCCERT_CONTEXT pCertContext = CertFindCertificateInStore(hStore,X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_ANY,0,0);
pCertContext!=NULL;
pCertContext = CertFindCertificateInStore(hStore,X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_ANY,0,pCertContext))
{
BOOL t=CryptFindCertificateKeyProvInfo(pCertContext,0,0);
}

//Пытаемся декодировать
CRYPT_DECRYPT_MESSAGE_PARA DecryptParams;
memset(&DecryptParams, 0, sizeof (DecryptParams));
DecryptParams.cbSize = sizeof (DecryptParams);
DecryptParams.dwMsgAndCertEncodingType = X509_ASN_ENCODING|PKCS_7_ASN_ENCODING;
DecryptParams.cCertStore = certStoresCount;
DecryptParams.rghCertStore = CertStoreArray;

DWORD cbDecryptedMessage;

//Выясняем размер - эта функция работает всегда успешно
CryptDecryptMessage(&DecryptParams, pbEncryptedBlob, cbEncryptedBlob, NULL, &cbDecryptedMessage, NULL)ж
BYTE* pbDecryptedMessage = (BYTE*)malloc(cbDecryptedMessage);

//Декодируем - а вот это работает только при наличии CryptFindCertificateKeyProvInfo
if(!CryptDecryptMessage(&DecryptParams, pbEncryptedBlob, cbEncryptedBlob, pbDecryptedMessage, &cbDecryptedMessage, NULL))
{
free(pbEncryptedBlob);
switch (GetLastError())
{
//Если не вызывали CryptFindCertificateKeyProvInfo - попадаем сюда
case CRYPT_E_NO_DECRYPT_CERT:
HandleError("Ошибка при декодировании. Указан неверный секретный ключ.");
break;
default:
HandleError("Ошибка при декодировании");
break;
}
}

 
Ответы:
03.11.2004 1:39:25Serge3leo
Надо установить в PCCERT_CONTEXT свойство CERT_KEY_CONTEXT_PROP_ID

Это обсуждалось в темах "Вопрос про АРМ разбора конфликтов" <http://www.cryptopro.ru/CryptoPro/forum/myforum.asp?q=1258> и "Функция CryptEncodeObject" <https://www.cryptopro.ru:9443/CryptoPro/forum/myforum.asp?q=1277> или поищите по CertSetCertificateContextProperty
03.11.2004 13:30:10Боженов Артём
Большое спасибо