Статус: Сотрудник
Группы: Участники
Зарегистрирован: 11.07.2016(UTC) Сообщений: 10 Откуда: Москва
|
Схема работы поточного расшифрования такая: 1) Открыть сообщение через CryptMsgOpenToDecode 2) Разобрать заголовок через CryptMsgUpdate (с помощью CryptMsgGetParam(CMSG_ENVELOPE_ALGORITHM_PARAM) и ошибки CRYPT_E_STREAM_MSG_NOT_READY можно определить, что заголовок ещё недочитан) 3) Из заголовка прочитать получателей через вызовы CryptMsgGetParam(CMSG_RECIPIENT_COUNT_PARAM) и CryptMsgGetParam(CMSG_RECIPIENT_INFO_PARAM) 4) Заполнить CMSG_CONTROL_DECRYPT_PARA, положить туда хэндл контейнера с ключом, индекс получателя и т.д. 5) Вызвать CryptMsgControl(CMSG_CTRL_DECRYPT) с заполненной CMSG_CONTROL_DECRYPT_PARA, и тем самым "подключить" коллбэк на обработку потока Коллбэк первый раз сработает после CryptMsgControl(CMSG_CTRL_DECRYPT) и обработает накопленную часть данных, после этого коллбэк будет работать при каждом вызове CryptMsgUpdate. Набросал макет кода с примером: Код:
{
if (!CryptAcquireCertificatePrivateKey(Cert,
CRYPT_ACQUIRE_COMPARE_KEY_FLAG | CRYPT_ACQUIRE_CACHE_FLAG,
NULL, &hCryptProv, &keytype, &should_release_ctx))
{
return ErrorHandle(ERR_CERT_PRIVATE_KEY);
}
BYTE tbenc[STREAM_BLOCK_SIZE]; /* Исходные данные для расшифрования*/
FILE *in = ::_tfopen(FilePath, _TEXT("rb"));
if (!in)
return ErrorHandle(ERR_COMMON_FILE, FilePath);
memset(tbenc, 0, STREAM_BLOCK_SIZE);
cbEncode.cbContent = CMSG_INDEFINITE_LENGTH;
cbEncode.pfnStreamOutput = CmsgStreamOutputCallback;
cbEncode.pvArg = NULL;
hMsg = CryptMsgOpenToDecode(
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, /* Encoding type*/
0, /* Flags*/
0, /* Message type (get from message)*/
0, /* Cryptographic provider*/
NULL, /* Recipient information future*/
&cbEncode); /* Stream information*/
if (!hMsg)
return ErrorHandle(ERR_USE_GetLastError);
BOOL bFin = FALSE;
BOOL bFirst = TRUE;
int n = 0;
size_t tbenc_offset = 0;
while (bFin == FALSE)
{
cbCnt = fread(tbenc + tbenc_offset, sizeof(char), STREAM_BLOCK_SIZE - tbenc_offset, in);
if (cbCnt < STREAM_BLOCK_SIZE - tbenc_offset) {
if (ferror(in)) {
fclose(in);
::CryptMsgClose(hMsg);
return ErrorHandle(ERR_COMMON_FILE, File1);
}
bFin = TRUE;
}
ret = CryptMsgUpdate(
hMsg, /* Handle to the message*/
tbenc, /* Pointer to the encoded blob*/
(DWORD)cbCnt, /* Size of the encoded blob*/
bFin); /* Last call*/
if (!ret) {
::CryptMsgClose(hMsg);
return ErrorHandle(ERR_USE_GetLastError);
}
if (!bDecryptStarted) {
/* Тип вложения*/
ret = CryptMsgGetParam(
hMsg, /* Handle to the message*/
CMSG_ENVELOPE_ALGORITHM_PARAM, /* Parameter type*/
0, /* Index*/
NULL, /* Address for returned // information*/
&cbData); /* Size of the returned // information*/
if (!ret) {
if (GetLastError() == (DWORD)CRYPT_E_STREAM_MSG_NOT_READY)
continue;
else {
::CryptMsgClose(hMsg);
return ErrorHandle(ERR_USE_GetLastError);
}
}
/* Инициализация структуры CMSG_CONTROL_DECRYPT_PARA */
memset(&DecryptPara, 0, sizeof(DecryptPara));
DecryptPara.dwRecipientIndex = (DWORD)-1;
DecryptPara.cbSize = sizeof(DecryptPara);
DecryptPara.hCryptProv = hCryptProv; /* Using handle opened in */
DecryptPara.dwKeySpec = AT_KEYEXCHANGE;
/* Определим индекс в списке получателей сообщения, соответствующий */
/* сертификату, заданному для расшифрования*/
cbData = sizeof(DWORD);
ret = CryptMsgGetParam(hMsg,
CMSG_RECIPIENT_COUNT_PARAM,
0,
&recip_count,
&cbData);
if (!ret) {
::CryptMsgClose(hMsg);
return ErrorHandle(ERR_USE_GetLastError);
}
for (i = 0; i < (int)recip_count; i++) {
ret = CryptMsgGetParam(hMsg,
CMSG_RECIPIENT_INFO_PARAM,
i,
NULL,
&cbData);
if (!ret) {
::CryptMsgClose(hMsg);
return ErrorHandle(ERR_USE_GetLastError);
}
recip_info = (CERT_INFO*)malloc(cbData);
if (!recip_info) {
::CryptMsgClose(hMsg);
return ErrorHandle(ERR_COMMON_NO_MEM);
}
ret = CryptMsgGetParam(hMsg,
CMSG_RECIPIENT_INFO_PARAM,
i,
recip_info,
&cbData);
if (!ret) {
::CryptMsgClose(hMsg);
return ErrorHandle(ERR_USE_GetLastError);
}
/* Произведем сравнение серийных номеров сертификатов и имен издателей */
if (CertCompareCertificateName(
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
&(Cert->pCertInfo->Issuer),
&(recip_info->Issuer)) &&
CertCompareIntegerBlob(&(Cert->pCertInfo->SerialNumber),
&(recip_info->SerialNumber)))
{
free(recip_info);
recip_info = NULL;
DecryptPara.dwRecipientIndex = i;
break;
}
free(recip_info);
recip_info = NULL;
}
if (DecryptPara.dwRecipientIndex == (DWORD)-1) {
::CryptMsgClose(hMsg);
return ErrorHandle(ERR_ENCR_NO_SKEY);
}
bDecryptStarted = TRUE;
/* Расшифрование сообщения*/
ret = CryptMsgControl(
hMsg, /* Message handle*/
0, /* Flags*/
CMSG_CTRL_DECRYPT, /* Control type*/
&DecryptPara); /* Address of the parameters*/
if (!ret) {
::CryptMsgClose(hMsg);
return ErrorHandle(ERR_USE_GetLastError);
}
}
}
if (pbDecoded)
free(pbDecoded);
if (hMsg)
CryptMsgClose(hMsg);
if (recip_info)
free(recip_info);
}
|