Статус: Участник
Группы: Участники
Зарегистрирован: 19.09.2013(UTC) Сообщений: 18
|
Добрый день, возник вопрос по работе с большими файлами. До сих пор для шифрования и расшифровки использовались высокоуровненые функции CryptEncryptMessage и CryptDecryptMessage, теперь встала задача поблочной обработки файлов и возникли проблемы следующего характера - при потоковой обработке с помощью CryptMsgOpenToEncode после сбора обработанных данных файл оказывается не совместим с форматом CryptEncryptMessage/CryptDecryptMessage. Используется следующий код: Код:int ICryptoImpl::encrypt_stream_ex(std::istream& plainStream, std::ostream& cryptoStream, std::vector<std::string>& saRecepientIDs)
{
if (saRecepientIDs.size() < 2)
return NoSender;
std::string strSender = saRecepientIDs.front();
std::vector<PCCERT_CONTEXT> arrCertRecipient;
for_each_(itRecipient, std::vector<std::string>, saRecepientIDs)
{
PCCERT_CONTEXT pFountCert = CertFindInStore(*itRecipient);
if(pFountCert == NULL)
return CantFindCertInStore;
arrCertRecipient.push_back(pFountCert);
}
//Первый сертификат - сертификат отправителя. Убедимся в этом и откроем провайдера
AUTO_HCRYPTPROV hProv;
DWORD dwFlag = CRYPT_ACQUIRE_COMPARE_KEY_FLAG | CRYPT_ACQUIRE_CACHE_FLAG ;
if (!m_Settings.bShowUICSP) dwFlag |= CRYPT_ACQUIRE_SILENT_FLAG;
if (!::CryptAcquireCertificatePrivateKey(arrCertRecipient.front(), dwFlag, NULL, hProv, NULL, NULL))
return CantFindPrivateKey;
//Начинаем шифровать --------------------------------------------------------------------
//соберем информацию по сертификатам шифрования
AUTO<PCERT_INFO*> pciRecipient = new PCERT_INFO[arrCertRecipient.size()];
if(pciRecipient == NULL)
return OutOfMemory;
//Подготовим массивы ключей и данных сертификатов
int nCertIdx = 0;
for_each_(itCert, std::vector<PCCERT_CONTEXT>, arrCertRecipient)
{
PCCERT_CONTEXT& pCertContext = *itCert;
pciRcpnt[nCertIdx++] = pCertContext->pCertInfo;
}
//подготовим оболочку PKCS7-ASN
struct callbackStream
{
static BOOL WINAPI CmsgStreamOutputCallback(const void *pvArg, BYTE *pbData, DWORD cbData, BOOL fFinal)
{
callbackStream* pcsShell = (callbackStream*)pvArg;
if(pcsShell->bGotFinal)return TRUE;
pcsShell->cryptoStream.write(reinterpret_cast<const char*>(pbData), cbData);
pcsShell->bGotFinal = fFinal;
return TRUE;
}
std::ostream& cryptoStream;
BOOL bGotFinal;
} csShell = { cryptoStream, FALSE };
CMSG_STREAM_INFO msg_si;
{
msg_si.cbContent = 64;//CMSG_INDEFINITE_LENGTH;
msg_si.pfnStreamOutput = &callbackStream::CmsgStreamOutputCallback;
msg_si.pvArg = &csShell;
}
CMSG_ENVELOPED_ENCODE_INFO eeiMsg;
{
memset(&eeiMsg, 0, sizeof(CMSG_ENVELOPED_ENCODE_INFO));
eeiMsg.cbSize = sizeof(CMSG_ENVELOPED_ENCODE_INFO);
eeiMsg.hCryptProv = hProv;
memset(&eeiMsg.ContentEncryptionAlgorithm, 0, sizeof(CRYPT_ALGORITHM_IDENTIFIER));
eeiMsg.ContentEncryptionAlgorithm.pszObjId = szOID_CP_GOST_28147;
eeiMsg.cRecipients = arrCertRcpt.size();
eeiMsg.rgpRecipients = pciRcpnt;
}
//Получаем хендл криптографического сообщения
// AUTO_HCRYPTMSG hMsg = ::CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
// CPCRYPT_MESSAGE_CADES_DISABLE, CMSG_ENVELOPED, &eeiMsg, NULL, NULL);
AUTO_HCRYPTMSG hMsg = ::CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
NULL/*CPCRYPT_MESSAGE_CADES_DISABLE*/, CMSG_ENVELOPED, &eeiMsg, NULL, &msg_si);
if (hMsg == NULL)
return CantOpenToEncode;
DWORD max_buff = macros::calc_read_buffer(plainStream) + 1;
AUTO<LPBYTE> bData = new BYTE[max_buff];
if (bData == NULL)
return OutOfMemory;
for(plainStream.seekg(0, plainStream.beg); !plainStream.eof();)
{
int nread = macros::read_nbyte(bData, max_buff, plainStream);
if(nread == 0)
return CantReadStream;
if (!::CryptMsgUpdate(hCryptMsg, bData, nread, plainStream.eof() != false))
return CantAddDataToMessage;
}
/*
DWORD dwMsgLen = 0;
if(!::CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, NULL, &dwMsgLen))
return -1;
AUTO_CRYPT_DATA_BLOB cmsgcp(dwMsgLen);
if(!::CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, cmsgcp->pbData, &cmsgcp->cbData))
return -1;
std::ofstream fout("d:\\encrypt_a.dat");
fout.write((LPCTSTR)cmsgcp->pbData, cmsgcp->cbData);
*/
return NoError;
}
Если же потоки не использовать и получать данные через ::CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM...) цельным куском, то все прекрасно работает. Подскажите, в чем проблема и как обойти? Отредактировано пользователем 21 сентября 2013 г. 10:04:34(UTC)
| Причина: поправил код
|