13.12.2007 13:55:33Огранение блока данных передаваемых CryptMsgUpdate Ответов: 47
Волков
Существует ли ограничения на блок информации передаваемой функции CryptMsgUpdate&
 
Ответы:
13.12.2007 14:37:28Волков
Если да то будет ли выходом передача информации поблочно, скажем 200 мегабайт по 4 мегабайта?
13.12.2007 15:59:26Kirill Sobolev
Ограничение - только объем доступной памяти для размещения блока. Конечно, для 200Мб конечно лучше использовать поблочную передачу.
14.12.2007 8:48:00Волков
делаю поблочную передачу следующим образом но ничего не получается:
for (i=0; i < 200925; i++)
{
memcpy((LPVOID)(dest), (LPVOID)(tbenc+i), 1);


DWORD Block=1;

ret = CryptMsgUpdate(
hMsg,
dest,
Block,
false);
if (ret)
printf("The message to decode has been updated. \n");
else
printf("Decode MsgUpdate failed");
}
передаю функции 1 байт из сообщения, но ret=0 а если передать сразу все 200295 байт то все будет в порядке! Почему так?
14.12.2007 12:10:17Kirill Sobolev
Потому что CryptMsgUpdate ожидает законченных блоков, несколько вызовов нужно при передаче неприсоединенных данных. В Вашем же случае, для передачи информации побайтно, надо воспользоваться потоковым чтением.
Напримр как здесь
http://www.cryptopro.ru/CryptoPro/forum/view.asp?q=5840
14.12.2007 15:35:17Юрий
Не соглашусь с Кирилом. Не знаю что такое "законченные блоки", которых так ожидает CryptMsgUpdate. Скорее всего в данном случае играет роль размер ключа, на котором выполняется шифования или подпись (в зависимости от параметра CryptMsgOpenToEncode). Кстати, что выполняется в приведенном случае - Encode или Decode?

Попробуйте передавать скажем 1024 байта. Поэксперементируйте.
14.12.2007 15:47:01Юрий
И насчет "использования потокового чтения": как это его предпологается использовать? И что это такое? :)

CMSG_STREAM_INFO structure is called when CryptMsgUpdate is executed or when CryptMsgControl is executed when decoding a streamed enveloped message.

Причем в обоих случаях CMSG_STREAM_INFO используется для записи, а не для чтения.
14.12.2007 16:07:18Kirill Sobolev
CMSG_STREAM_INFO::pfnStreamOutput
Address of a callback function used to read from and write data to a disk when processing large messages.
14.12.2007 16:23:21Юрий
Вы можете привести пример, когда "data read"? Лично я никогда с таким не встречался. Хотя использовал потоковые функции крайне активно.

Даже в той ссылке на MSDN, которую Вы привели, в функции DecodeCallback просто печатаются переданые в функцию данные, не более того.
15.12.2007 12:02:27Юрий
Посмотрел еще, подумал. Все-таки в случае CryptMsgOpenToEncode размер массива, загружаемого CryptMsgUpdate, зависит от длины ключа используемого алгоритма. А вот в случае CryptMsgOpenToDecode похоже что первым блоком CryptMsgUpdate обязана загрузить весь заголовок PKCS сообщения. Нужно эксперементировать.
17.12.2007 10:53:02Волков
Обновляю соощение следующим образом:
stStreamInfo.cbContent = 0xffffffff;
stStreamInfo.pfnStreamOutput = DecodeCallback;

hMsg = CryptMsgOpenToDecode(
MY_ENCODING_TYPE,
0,
0,
hCryptProv,
NULL,
&stStreamInfo);
if(hMsg==NULL)
{
printf("OpenToDecode failed.");
return 0;
}

HANDLE hFile = INVALID_HANDLE_VALUE;

hFile = CreateFile(
in_filename,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE == hFile)
{
printf("CreateFile (IN MSG)");
return 0;
}

const DWORD cbBytesToRead = 4096;
byte pbEncodedBlob[cbBytesToRead];
DWORD cbBytesRead;
BOOL lastCall = FALSE;

while (ReadFile(
hFile,
pbEncodedBlob,
cbBytesToRead,
&cbBytesRead,
NULL))
{
if (cbBytesRead < cbBytesToRead)
{
lastCall = TRUE;
}

if(!(CryptMsgUpdate(
hMsg, // handle to the message
pbEncodedBlob, // pointer to the encoded BLOB
cbBytesRead, // size of the encoded BLOB
lastCall))) // last call
{
printf("Decode MsgUpdate failed.");
}

if (lastCall)
{
break;
}
}
и оно не расшифровывается, а если сделать без потоков:
hMsg = CryptMsgOpenToDecode(
TYPE_DER,
CMSG_CRYPT_RELEASE_CONTEXT_FLAG,
0,
hCryptProv,
NULL,
NULL);

ret = CryptMsgUpdate(
hMsg,
tbenc,
tbenc_len,
TRUE);
if (ret)
printf("The message to decode has been updated. \n");
else
printf("Decode MsgUpdate failed");
то все в порядке.
17.12.2007 11:10:42Юрий
А кто сказал, что последовательность CryptMsgOpenToDecode + CryptMsgUpdate расшифрует данные? Совсем нет :)

И что значит "без потоков все получается"? И что именно не получается с потоками? Какие ошибки и где?
17.12.2007 12:56:15Волков
Расшифрует CryptMsgControl в последствии. Без использования потоков это создаю сообщение CryptMsgOpenToDecode(hMsg...,NULL), добавляю в сообщение зашифрованную информацию из файла CryptMsgUpdate(hMsg,tbenc,tbenc_len,true) далее CryptMsgControl и CryptMsgGetParam. Расшифрование проходит успешно. Используя потоки это CryptMsgOpenToDecode (.....,&stStreamInfo) и так как писал выше. Но при вызове функции CryptMsgGetParam выполняется с ошибкой E_INVALIDARG
, в чем может быть дело?
17.12.2007 13:03:55Юрий
Ошибка в параметре (E_INVALIDARG - что бы это могло быть?) :)
Приводите полный код, как минимум для использования CryptMsgGetParam.
17.12.2007 13:06:54Юрий
Или Вы хотели получить декодированый контент в CryptMsgGetParam? Лучше проверьте, что передается в callback-функцию во время CryptMsgControl.
17.12.2007 13:21:22Волков
ret = CryptMsgGetParam(
hMsg,
CMSG_CONTENT_PARAM,
0,
NULL,
&cbDecoded);
17.12.2007 13:27:50Юрий
Так и должно быть. Проверяйте что передается в callback после (во время) выполнения CryptMsgControl.
17.12.2007 13:49:14Волков
Я извиняюсь а о каком колбэке идет речь?
17.12.2007 13:53:50Юрий
stStreamInfo.pfnStreamOutput = DecodeCallback;
18.12.2007 8:21:04Волков
Callback функция следующая
BOOL WINAPI
DecodeCallback(
const void *pvArg,
BYTE *pbData,
DWORD cbData,
BOOL fFinal)
{
int ret;
ret=write_file("test1.rar", cbData, pbData);
if (!ret)
{
printf("Error write_file");
}

return TRUE;
}
Вообщем файл расшифровывается корректно только если его длинна не более 3071 байт. Если файл будет 3072 байта то объем расшифрованных данны составит 1024 байта. В чем может быть проблема?
18.12.2007 10:26:04Юрий
Может места на диске на хватает, или что-то еще?

Вообщем у меня нормально шифровались (и расшифровывались) файлы размерами в гигабайты. Так что ищите в чем у Вас загвоздка.
18.12.2007 10:36:54Волков
Все это производилось тем же методом что и у меня? Просто при возростании размера файла с 3072 байт, размер расшифрованного файла тоже увеличивался. А зашифровывали вы тоже с использованием потоков?
18.12.2007 10:56:09Юрий
Да, все производилось с использованием потоков. Тем же самым алгоритмом, так как стандартным CryptoAPI больше никак данные операции с большими файлами не сделаешь.
Вообщем-то теперь алгоритм использование потоков у Вас выработался осталось только его отшлифовать.
18.12.2007 14:12:20Волков
Юрий подскажите где где можно поискать ошибку?
18.12.2007 14:16:35Юрий
Как Вы себе это представляете? Типа "...я выхожу в астрал, читаю ваш код, пишу ошибку..."? :)

Общий алгоритм использования потоков правильный, ищите в мелочах. Вроде записи в файл или выставления флажков. Еще раз почитайте внимательно про все использованые функции, там иногда в примечаниях пишут много полезного.

И не надо приводить весь свой код здесь и очень просить сказать мне где же ошибка, пожалуйста.
18.12.2007 14:25:25Волков
Юрий ну в астрал не стоит:) Последую совету.
19.12.2007 9:02:15Волков
Вот код:
stStreamInfo.cbContent = 0xffffffff;
stStreamInfo.pfnStreamOutput = DecodeCallback;

hMsg = CryptMsgOpenToDecode(
MY_ENCODING_TYPE,
0,
0,
hCryptProv,
NULL,
&stStreamInfo);
if(hMsg==NULL)
{
printf("OpenToDecode failed.");
return 0;
}

HANDLE hFile = INVALID_HANDLE_VALUE;

hFile = CreateFile(
in_filename,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE == hFile)
{
printf("CreateFile (IN MSG)");
return 0;
}

DWORD count=0;
const DWORD cbBytesToRead = 4096;
byte pbEncodedBlob[cbBytesToRead];
DWORD cbBytesRead;
BOOL lastCall = FALSE;

while (ReadFile(
hFile,
pbEncodedBlob,
cbBytesToRead,
&cbBytesRead,
NULL))
{
count=count+cbBytesRead;
if (cbBytesRead < cbBytesToRead)
{
lastCall = TRUE;
}

if(!(CryptMsgUpdate(
hMsg, // handle to the message
pbEncodedBlob, // pointer to the encoded BLOB
cbBytesRead, // size of the encoded BLOB
lastCall))) // last call
{
printf("Decode MsgUpdate failed.");
}

if (lastCall)
{
break;
}
}

/*--------------------------------------------------------------------*/
/* &#210;&#232;&#239; &#226;&#235;&#238;&#230;&#229;&#237;&#232;&#255;*/

ret = CryptMsgGetParam(
hMsg,
CMSG_TYPE_PARAM,
0,
&dwMsgType,
&cbData);

if (ret)
printf("The message type has been retrieved. \n");
else
printf("Decode CMSG_TYPE_PARAM failed");

/*--------------------------------------------------------------------*/
/* &#206;&#225;&#240;&#224;&#225;&#224;&#242;&#251;&#226;&#224;&#229;&#242;&#241;&#255; &#242;&#238;&#235;&#252;&#234;&#238; &#242;&#232;&#239; &#226;&#235;&#238;&#230;&#229;&#237;&#232;&#255; CMSG_ENVELOPED*/

if(dwMsgType != CMSG_ENVELOPED)
printf("Message is not Enveloped message.");

/*-------------------------------------------------------------*/
/* &#206;&#239;&#240;&#229;&#228;&#229;&#235;&#229;&#237;&#232;&#229; &#228;&#235;&#232;&#237;&#251;, &#242;&#240;&#229;&#225;&#243;&#229;&#236;&#238;&#233; &#228;&#235;&#255; &#226;&#238;&#231;&#226;&#240;&#224;&#242;&#224; &#242;&#232;&#239;&#224; &#226;&#235;&#238;&#230;&#229;&#237;&#232;&#255;*/

ret = CryptMsgGetParam(
hMsg,
CMSG_INNER_CONTENT_TYPE_PARAM,
0,
NULL,
&cbInnerContentObjId);
if (!ret)
printf("Decode CMSG_INNER_CONTENT_TYPE_PARAM failed");

/*-------------------------------------------------------------*/
/* Allocate memory for the string.*/

pbInnerContentObjId = (BYTE *) malloc(cbInnerContentObjId);
if (!pbInnerContentObjId)
printf("Decode inner content malloc operation failed.");

/*-------------------------------------------------------------*/
/* &#206;&#239;&#240;&#229;&#228;&#229;&#235;&#229;&#237;&#232;&#229; &#242;&#232;&#239;&#224; &#226;&#235;&#238;&#230;&#229;&#237;&#232;&#255;*/

ret = CryptMsgGetParam(
hMsg,
CMSG_INNER_CONTENT_TYPE_PARAM,
0,
pbInnerContentObjId,
&cbInnerContentObjId);
if (ret)
printf("The OID of the inner content type is: %s.\n", (LPSTR) pbInnerContentObjId);
else
printf("Decode CMSG_INNER_CONTENT_TYPE_PARAM #2 failed");
/*--------------------------------------------------------------------*/
/* &#206;&#239;&#240;&#229;&#228;&#229;&#235;&#229;&#237;&#232;&#229; &#242;&#232;&#239;&#224; &#226;&#235;&#238;&#230;&#229;&#237;&#232;&#255;*/

pszInnerContentObjId = (LPSTR) pbInnerContentObjId;
free( pbInnerContentObjId );

/*----------------------------------------------------------------*/
/* &#200;&#237;&#232;&#246;&#232;&#224;&#235;&#232;&#231;&#224;&#246;&#232;&#255; &#241;&#242;&#240;&#243;&#234;&#242;&#243;&#240;&#251; 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;

/*----------------------------------------------------------------*/
/* &#206;&#239;&#240;&#229;&#228;&#229;&#235;&#232;&#236; &#232;&#237;&#228;&#229;&#234;&#241; &#226; &#241;&#239;&#232;&#241;&#234;&#229; &#239;&#238;&#235;&#243;&#247;&#224;&#242;&#229;&#235;&#229;&#233; &#241;&#238;&#238;&#225;&#249;&#229;&#237;&#232;&#255;, &#241;&#238;&#238;&#242;&#226;&#229;&#242;&#241;&#242;&#226;&#243;&#254;&#249;&#232;&#233; */
/* &#241;&#229;&#240;&#242;&#232;&#244;&#232;&#234;&#224;&#242;&#243;, &#231;&#224;&#228;&#224;&#237;&#237;&#238;&#236;&#243; &#228;&#235;&#255; &#240;&#224;&#241;&#248;&#232;&#244;&#240;&#238;&#226;&#224;&#237;&#232;&#255;*/

cbData = sizeof (DWORD);
ret = CryptMsgGetParam (hMsg,
CMSG_RECIPIENT_COUNT_PARAM,
0,
&recip_count,
&cbData);
if (! ret)
printf("CryptMsgGetParam. CMSG_RECIPIENT_COUNT_PARAM failed.");

for (i = 0; i < (int) recip_count; i++)
{
ret = CryptMsgGetParam(
hMsg,
CMSG_RECIPIENT_INFO_PARAM,
i,
NULL,
&cbData);
if (! ret)
printf("CryptMsgGetParam. CMSG_RECIPIENT_INFO_PARAM failed.");

recip_info = (CERT_INFO*) malloc (cbData);
if (! recip_info)
printf("Memory allocation failed.");

ret = CryptMsgGetParam (hMsg,
CMSG_RECIPIENT_INFO_PARAM,
i,
recip_info,
&cbData);
if (! ret)
printf("CryptMsgGetParam. CMSG_RECIPIENT_INFO_PARAM failed.");

/*----------------------------------------------------------------*/
/* &#207;&#240;&#238;&#232;&#231;&#226;&#229;&#228;&#229;&#236; &#241;&#240;&#224;&#226;&#237;&#229;&#237;&#232;&#229; &#241;&#229;&#240;&#232;&#233;&#237;&#251;&#245; &#237;&#238;&#236;&#229;&#240;&#238;&#226; &#241;&#229;&#240;&#242;&#232;&#244;&#232;&#234;&#224;&#242;&#238;&#226; &#232; &#232;&#236;&#229;&#237; &#232;&#231;&#228;&#224;&#242;&#229;&#235;&#229;&#233;*/
if (CertCompareCertificateName(
TYPE_DER,
&(pUserCert->pCertInfo->Issuer),
&(recip_info->Issuer)) &&
CertCompareIntegerBlob(&(pUserCert->pCertInfo->SerialNumber),
&(recip_info->SerialNumber)))
{
free( recip_info );
recip_info = NULL;
DecryptPara.dwRecipientIndex = i;
break;
}
free( recip_info );
recip_info = NULL;
}
if (DecryptPara.dwRecipientIndex < 0 )
printf("Recipient matching with user certificate was not found.");

/*----------------------------------------------------------------*/
/* &#208;&#224;&#241;&#248;&#232;&#244;&#240;&#238;&#226;&#224;&#237;&#232;&#229; &#241;&#238;&#238;&#225;&#249;&#229;&#237;&#232;&#255;*/

ret = CryptMsgControl(
hMsg,
0,
choice_opt,
&DecryptPara);
if (! ret)
printf("CryptMsgControl. Decode decryption failed.");
что здесь не так?
19.12.2007 12:49:30Волков
Юрий нет возможности мне помочь?
19.12.2007 12:49:51Волков
Юрий нет возможности мне помочь?
19.12.2007 13:03:23Юрий
Упрощайте пример. То есть шифруйте изначально с одним получателем и потом индекс не перебирайте, а ставьте ноль. Не проверяйте INNER_CONTENT ну и т.п.
19.12.2007 13:32:52Юрий
И сделайте вывод из DecodeCallback просто на экран, а не в файл. Потом запускайте программу как "my_code.exe >> output.txt".
19.12.2007 15:01:21Волков
Использую следующую колбэк функцию как в мсдн, для вывода расшифрованного файла на экран:
BOOL WINAPI
DecodeCallback(
const void *pvArg,
BYTE *pbData,
DWORD cbData,
BOOL fFinal)
{
int ret;
ret=write_file("test1.rar", cbData, pbData);
if (!ret)
{
printf("Error write_file");
}

if (pbData != NULL && cbData > 0)
{
*(pbData+cbData) = 0;
printf("%s", (char*)pbData);
}
return TRUE;
}
Но где-то в середине происходит некоторое искожение расшифрованного текста. Сделал все так как вы сказали, один получатель, мндекс ноль, лишнее поубирал.
19.12.2007 15:18:10Юрий
Ну если расшифровывается полностью, то осталась совсем ерунда :)
20.12.2007 10:39:00Волков
Юрий благодарю, заработало:)
20.12.2007 11:10:03Юрий
Пожалуйста :)
И где же был этот неприятный мелкий глюк?
21.12.2007 14:58:07Волков
Как теперь запсать расшифрованную информацию? Если файл больше определенного размера, то появляются ошибки!!!
21.12.2007 15:19:10Юрий
А как насчет ответить сначала на мой вопрос? (см. мой предыдущий пост)
24.12.2007 9:29:51Волков
Там была проблема с функцией записи файла на диск. А сейчас в расшифрованном сообщении появляются блоки по 8 байт не соответствующие действительности. В чем может быть дело?
24.12.2007 11:11:09Юрий
Все в той же функции записи :)Это, естественно, только мое предположение. И в общем случае: если работа с перенаправлением вывода (*.exe > out.txt) все работает нормально, то ошибка явно в фунции записи в файлю
24.12.2007 14:06:21Волков
Проблема не в выводе а в чем то другом, т.к. > outfile тоже не дает нужного результата.
24.12.2007 14:15:53Юрий
8 байт в начале расшифрованого текста? И криптопровайдер КриптоПРО?
Если да, то советую поискать сходные вопросы на этом же форуме. И для начальных тестов использовать обычные криптопровайдеры от Microsoft.
25.12.2007 6:16:10Волков
портятся не первые 8 байт расшифрованного сообщения, криптопровайдер КриптоПро. Это проблема с вектором инициализации?
25.12.2007 10:52:23Юрий
Если не первые то продолжайте искать все свои ошибки.

Еще раз поймите: ДЕСЯТКИ людей во всем мире сделали до Вас все то же самое и у них все работает. Сотни тестеров в огромной компании Microsoft все это протестировали. То же самое сделали в КриптоПРО, да еще и прошли дополнительную сертификацию.

Все что я хочу сказать - еще раз: ищите свои ошибки.
25.12.2007 11:00:06Волков
А где примерно они могут быть. Зашифровывается правильно т.к. криптсп правильно расшифровывает. Может кто сталкивался, при использовании низкоуровневых функций была такая же проблема там все дело было в векторе инициализации. Просто у предприятия нет средств на то чтобы меня на курсы, поэтому и ищиту помощи здесь. Литературы на русском тоже не встречал.
25.12.2007 11:21:52Юрий
В прошлый раз это была ошибка в функции записи в файл. В этот раз это может быть где-то еще в коде, непосредственно не связанном с CryptoAPI.

Я еще раз подтверждаю, что используемый алгоритм правильный (правильный с точки зрения использования функций CryptoAPI). Оставьте копание в криптографических функциях и копайте в других местах.

Польза курсов лично для меня сомнительна (хотя честно говоря я никогда на таковых не был). Литература вся на английском. Чуть позже (в начале следующего года) напишу статью про использование этих функций и на русском. А пока старайтесь все понять сами.
25.12.2007 11:57:03Волков
Юрий сроки уже не просто поджимают, а не знаю как и вырозить что делают. И осталась единственная загвоздка только в функции расшифрования. И где копать даже не предсталяю т.к. имею малый опыт не только использования КриптоАПИ но и самого программирования. Если есть возможность мне помочь, буду очень признателен.
25.12.2007 12:16:53Юрий
1) Я не собираюсь проверять чужой код;
2) Меня не волнуют чужие сроки;
3) Слова "пожалуйста" меня тоже мало трогают;
4) Я не буду оправдыватся за предыдущие пункты;
5) И так уже подсказал достаточно;

Как уже было написано ранее - если что-то не получится, значит это Вам и не дано.
25.12.2007 12:22:34Волков
Полностью с вами согласен:)