Входящие:
Windows XP SP3
КриптоПро CSP:
Версия ядра СКЗИ 3.6.5359 КС1
Версия продукта 3.6.6497
Алгоритм работы:
1) Есть токен с контейнером закрытого ключа сертификат на токене в личном хранилище сертификатов в Windows ничего нет,
Нижеприведенный алгоритм работает нормально.
2) Ставим сертификат в личное хранилище (без привязки к закрытому ключу средствами Windows) и удаляем его оттуда через консоль с оснасткой сертификатов.
3) Шифруем для этого получателя (сертификата) некий файл
PCCERT_CONTEXT RecipientCertArray[1];
DWORD EncryptAlgSize;
CRYPT_ALGORITHM_IDENTIFIER EncryptAlgorithm;
CRYPT_ENCRYPT_MESSAGE_PARA EncryptParams;
DWORD EncryptParamsSize;
BYTE* pbEncryptedBlob;
DWORD cbEncryptedBlob;
RecipientCertArray[0] = pCertContext;
EncryptAlgSize = sizeof(EncryptAlgorithm);
memset(&EncryptAlgorithm, 0, EncryptAlgSize);
EncryptAlgorithm.pszObjId = OID_CipherVar_Default;
EncryptParamsSize = sizeof(EncryptParams);
memset(&EncryptParams, 0, EncryptParamsSize);
EncryptParams.cbSize = EncryptParamsSize;
EncryptParams.dwMsgEncodingType = MY_ENCODING_TYPE;
EncryptParams.hCryptProv = hCryptProv;
EncryptParams.ContentEncryptionAlgorithm = EncryptAlgorithm;
printf("Encrypting...\n");
if(!CryptEncryptMessage(
&EncryptParams,
1,
RecipientCertArray,
pbContent,
cbContent,
NULL,
&cbEncryptedBlob))
....
2) пытаемся расшифровать
a) Для этого создаем хранилище сертификатов в памяти
HANDLE hStore = CertOpenStore(
CERT_STORE_PROV_MEMORY,
MY_ENCODING_TYPE,
hCryptProv,
0,
NULL);
b) Получаем контекст сертификата с токена, связываем с закрытым ключом и добавляем в наше временное хранилище
HCRYPTPROV hCP;
if(!CryptAcquireContext(
&hCP,
containerName,
NULL,
75,
0))
{
return FALSE;
}
HCRYPTKEY hKey = NULL;
CryptGetUserKey(hCP, AT_SIGNATURE, &hKey);
if(hKey==NULL)
CryptGetUserKey(hCP, AT_KEYEXCHANGE, &hKey);
if(hKey==NULL)
{
CryptReleaseContext(hCP, 0);
return FALSE;
}
DWORD certSize = 0;
BYTE *pCert;
if(!CryptGetKeyParam(hKey, KP_CERTIFICATE, NULL, &certSize, NULL))
{
CryptReleaseContext(hCP, 0);
return TRUE;
}
pCert = (BYTE *)malloc(certSize);
if(!CryptGetKeyParam(hKey, KP_CERTIFICATE, pCert, &certSize, NULL))
{
CryptReleaseContext(hCP, 0);
return TRUE;
}
PCCERT_CONTEXT pCertContext = CertCreateCertificateContext(MY_ENCODING_TYPE, pCert, certSize);
CRYPT_KEY_PROV_INFO provInfo;
ZeroMemory(&provInfo, sizeof(CRYPT_KEY_PROV_INFO));
provInfo.dwProvType = 75;
provInfo.pwszContainerName = containerName;
provInfo.pwszProvName=L"Crypto-Pro GOST R 34.10-94 Cryptographic Service Provider";
if(!CertSetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, 0, &provInfo))
{
CryptReleaseContext(hCP, 0);
return FALSE;
}
if(!CertAddCertificateContextToStore(hStore, pCertContext, CERT_STORE_ADD_REPLACE_EXISTING, NULL))
{
CryptReleaseContext(hCP, 0);
return FALSE;
}
CertFreeCertificateContext(pCertContext);
free(pCert);
с) Далее пытаемся расшифровать
HCERTSTORE CertStoreArray[] = {hStoreHandle};
CRYPT_DECRYPT_MESSAGE_PARA DecryptParams;
DWORD DecryptParamsSize = sizeof(DecryptParams);
ZeroMemory(&DecryptParams, DecryptParamsSize);
DecryptParams.cbSize = DecryptParamsSize;
DecryptParams.dwMsgAndCertEncodingType = MY_ENCODING_TYPE;
DecryptParams.cCertStore = 1;
DecryptParams.rghCertStore = CertStoreArray;
BYTE *pDecBuffer = NULL;
DWORD sizeDec = 0;
if(CryptDecryptMessage(
&DecryptParams,
pEncBuffer,
sizeEnc,
NULL,
&sizeDec,
NULL))
{
...
Получаем размер расшифрованных данных
и после
if(CryptDecryptMessage(
&DecryptParams,
pEncBuffer,
sizeEnc,
pDecBuffer,
&sizeDec,
NULL))
{
}
Ошибку 0x000057
Лечиться повторной установкой в личное хранилище Windows средствами КриптоПРО и удалением сертификата.
Это некая фича системы или я что-то не так делаю?
Спрашиваю не из праздного интереса, будет использоваться в крупной промышленной среде с поддержкой локальных админов,
хотелось бы избежать данной ситуации.