| ||||
| ||||
Существует ли ограничения на блок информации передаваемой функции CryptMsgUpdate& | ||||
Ответы: | ||||
| ||||
Если да то будет ли выходом передача информации поблочно, скажем 200 мегабайт по 4 мегабайта? | ||||
| ||||
Ограничение - только объем доступной памяти для размещения блока. Конечно, для 200Мб конечно лучше использовать поблочную передачу. | ||||
| ||||
делаю поблочную передачу следующим образом но ничего не получается: 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 байт то все будет в порядке! Почему так? | ||||
| ||||
Потому что CryptMsgUpdate ожидает законченных блоков, несколько вызовов нужно при передаче неприсоединенных данных. В Вашем же случае, для передачи информации побайтно, надо воспользоваться потоковым чтением. Напримр как здесь http://www.cryptopro.ru/CryptoPro/forum/view.asp?q=5840 | ||||
| ||||
Не соглашусь с Кирилом. Не знаю что такое "законченные блоки", которых так ожидает CryptMsgUpdate. Скорее всего в данном случае играет роль размер ключа, на котором выполняется шифования или подпись (в зависимости от параметра CryptMsgOpenToEncode). Кстати, что выполняется в приведенном случае - Encode или Decode? Попробуйте передавать скажем 1024 байта. Поэксперементируйте. | ||||
| ||||
И насчет "использования потокового чтения": как это его предпологается использовать? И что это такое? :) CMSG_STREAM_INFO structure is called when CryptMsgUpdate is executed or when CryptMsgControl is executed when decoding a streamed enveloped message. Причем в обоих случаях CMSG_STREAM_INFO используется для записи, а не для чтения. | ||||
| ||||
CMSG_STREAM_INFO::pfnStreamOutput Address of a callback function used to read from and write data to a disk when processing large messages. | ||||
| ||||
Вы можете привести пример, когда "data read"? Лично я никогда с таким не встречался. Хотя использовал потоковые функции крайне активно. Даже в той ссылке на MSDN, которую Вы привели, в функции DecodeCallback просто печатаются переданые в функцию данные, не более того. | ||||
| ||||
Посмотрел еще, подумал. Все-таки в случае CryptMsgOpenToEncode размер массива, загружаемого CryptMsgUpdate, зависит от длины ключа используемого алгоритма. А вот в случае CryptMsgOpenToDecode похоже что первым блоком CryptMsgUpdate обязана загрузить весь заголовок PKCS сообщения. Нужно эксперементировать. | ||||
| ||||
Обновляю соощение следующим образом: 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"); то все в порядке. | ||||
| ||||
А кто сказал, что последовательность CryptMsgOpenToDecode + CryptMsgUpdate расшифрует данные? Совсем нет :) И что значит "без потоков все получается"? И что именно не получается с потоками? Какие ошибки и где? | ||||
| ||||
Расшифрует CryptMsgControl в последствии. Без использования потоков это создаю сообщение CryptMsgOpenToDecode(hMsg...,NULL), добавляю в сообщение зашифрованную информацию из файла CryptMsgUpdate(hMsg,tbenc,tbenc_len,true) далее CryptMsgControl и CryptMsgGetParam. Расшифрование проходит успешно. Используя потоки это CryptMsgOpenToDecode (.....,&stStreamInfo) и так как писал выше. Но при вызове функции CryptMsgGetParam выполняется с ошибкой E_INVALIDARG , в чем может быть дело? | ||||
| ||||
Ошибка в параметре (E_INVALIDARG - что бы это могло быть?) :) Приводите полный код, как минимум для использования CryptMsgGetParam. | ||||
| ||||
Или Вы хотели получить декодированый контент в CryptMsgGetParam? Лучше проверьте, что передается в callback-функцию во время CryptMsgControl. | ||||
| ||||
ret = CryptMsgGetParam( hMsg, CMSG_CONTENT_PARAM, 0, NULL, &cbDecoded); | ||||
| ||||
Так и должно быть. Проверяйте что передается в callback после (во время) выполнения CryptMsgControl. | ||||
| ||||
Я извиняюсь а о каком колбэке идет речь? | ||||
| ||||
stStreamInfo.pfnStreamOutput = DecodeCallback; | ||||
| ||||
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 байта. В чем может быть проблема? | ||||
| ||||
Может места на диске на хватает, или что-то еще? Вообщем у меня нормально шифровались (и расшифровывались) файлы размерами в гигабайты. Так что ищите в чем у Вас загвоздка. | ||||
| ||||
Все это производилось тем же методом что и у меня? Просто при возростании размера файла с 3072 байт, размер расшифрованного файла тоже увеличивался. А зашифровывали вы тоже с использованием потоков? | ||||
| ||||
Да, все производилось с использованием потоков. Тем же самым алгоритмом, так как стандартным CryptoAPI больше никак данные операции с большими файлами не сделаешь. Вообщем-то теперь алгоритм использование потоков у Вас выработался осталось только его отшлифовать. | ||||
| ||||
Юрий подскажите где где можно поискать ошибку? | ||||
| ||||
Как Вы себе это представляете? Типа "...я выхожу в астрал, читаю ваш код, пишу ошибку..."? :) Общий алгоритм использования потоков правильный, ищите в мелочах. Вроде записи в файл или выставления флажков. Еще раз почитайте внимательно про все использованые функции, там иногда в примечаниях пишут много полезного. И не надо приводить весь свой код здесь и очень просить сказать мне где же ошибка, пожалуйста. | ||||
| ||||
Юрий ну в астрал не стоит:) Последую совету. | ||||
| ||||
Вот код: 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; } } /*--------------------------------------------------------------------*/ /* Òèï âëîæåíèÿ*/ 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"); /*--------------------------------------------------------------------*/ /* Îáðàáàòûâàåòñÿ òîëüêî òèï âëîæåíèÿ CMSG_ENVELOPED*/ if(dwMsgType != CMSG_ENVELOPED) printf("Message is not Enveloped message."); /*-------------------------------------------------------------*/ /* Îïðåäåëåíèå äëèíû, òðåáóåìîé äëÿ âîçâðàòà òèïà âëîæåíèÿ*/ 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."); /*-------------------------------------------------------------*/ /* Îïðåäåëåíèå òèïà âëîæåíèÿ*/ 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"); /*--------------------------------------------------------------------*/ /* Îïðåäåëåíèå òèïà âëîæåíèÿ*/ pszInnerContentObjId = (LPSTR) pbInnerContentObjId; free( pbInnerContentObjId ); /*----------------------------------------------------------------*/ /* Èíèöèàëèçàöèÿ ñòðóêòóðû 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) 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."); /*----------------------------------------------------------------*/ /* Ïðîèçâåäåì ñðàâíåíèå ñåðèéíûõ íîìåðîâ ñåðòèôèêàòîâ è èìåí èçäàòåëåé*/ 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."); /*----------------------------------------------------------------*/ /* Ðàñøèôðîâàíèå ñîîáùåíèÿ*/ ret = CryptMsgControl( hMsg, 0, choice_opt, &DecryptPara); if (! ret) printf("CryptMsgControl. Decode decryption failed."); что здесь не так? | ||||
| ||||
Юрий нет возможности мне помочь? | ||||
| ||||
Юрий нет возможности мне помочь? | ||||
| ||||
Упрощайте пример. То есть шифруйте изначально с одним получателем и потом индекс не перебирайте, а ставьте ноль. Не проверяйте INNER_CONTENT ну и т.п. | ||||
| ||||
И сделайте вывод из DecodeCallback просто на экран, а не в файл. Потом запускайте программу как "my_code.exe >> output.txt". | ||||
| ||||
Использую следующую колбэк функцию как в мсдн, для вывода расшифрованного файла на экран: 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; } Но где-то в середине происходит некоторое искожение расшифрованного текста. Сделал все так как вы сказали, один получатель, мндекс ноль, лишнее поубирал. | ||||
| ||||
Ну если расшифровывается полностью, то осталась совсем ерунда :) | ||||
| ||||
Юрий благодарю, заработало:) | ||||
| ||||
Пожалуйста :) И где же был этот неприятный мелкий глюк? | ||||
| ||||
Как теперь запсать расшифрованную информацию? Если файл больше определенного размера, то появляются ошибки!!! | ||||
| ||||
А как насчет ответить сначала на мой вопрос? (см. мой предыдущий пост) | ||||
| ||||
Там была проблема с функцией записи файла на диск. А сейчас в расшифрованном сообщении появляются блоки по 8 байт не соответствующие действительности. В чем может быть дело? | ||||
| ||||
Все в той же функции записи :)Это, естественно, только мое предположение. И в общем случае: если работа с перенаправлением вывода (*.exe > out.txt) все работает нормально, то ошибка явно в фунции записи в файлю | ||||
| ||||
Проблема не в выводе а в чем то другом, т.к. > outfile тоже не дает нужного результата. | ||||
| ||||
8 байт в начале расшифрованого текста? И криптопровайдер КриптоПРО? Если да, то советую поискать сходные вопросы на этом же форуме. И для начальных тестов использовать обычные криптопровайдеры от Microsoft. | ||||
| ||||
портятся не первые 8 байт расшифрованного сообщения, криптопровайдер КриптоПро. Это проблема с вектором инициализации? | ||||
| ||||
Если не первые то продолжайте искать все свои ошибки. Еще раз поймите: ДЕСЯТКИ людей во всем мире сделали до Вас все то же самое и у них все работает. Сотни тестеров в огромной компании Microsoft все это протестировали. То же самое сделали в КриптоПРО, да еще и прошли дополнительную сертификацию. Все что я хочу сказать - еще раз: ищите свои ошибки. | ||||
| ||||
А где примерно они могут быть. Зашифровывается правильно т.к. криптсп правильно расшифровывает. Может кто сталкивался, при использовании низкоуровневых функций была такая же проблема там все дело было в векторе инициализации. Просто у предприятия нет средств на то чтобы меня на курсы, поэтому и ищиту помощи здесь. Литературы на русском тоже не встречал. | ||||
| ||||
В прошлый раз это была ошибка в функции записи в файл. В этот раз это может быть где-то еще в коде, непосредственно не связанном с CryptoAPI. Я еще раз подтверждаю, что используемый алгоритм правильный (правильный с точки зрения использования функций CryptoAPI). Оставьте копание в криптографических функциях и копайте в других местах. Польза курсов лично для меня сомнительна (хотя честно говоря я никогда на таковых не был). Литература вся на английском. Чуть позже (в начале следующего года) напишу статью про использование этих функций и на русском. А пока старайтесь все понять сами. | ||||
| ||||
Юрий сроки уже не просто поджимают, а не знаю как и вырозить что делают. И осталась единственная загвоздка только в функции расшифрования. И где копать даже не предсталяю т.к. имею малый опыт не только использования КриптоАПИ но и самого программирования. Если есть возможность мне помочь, буду очень признателен. | ||||
| ||||
1) Я не собираюсь проверять чужой код; 2) Меня не волнуют чужие сроки; 3) Слова "пожалуйста" меня тоже мало трогают; 4) Я не буду оправдыватся за предыдущие пункты; 5) И так уже подсказал достаточно; Как уже было написано ранее - если что-то не получится, значит это Вам и не дано. | ||||
| ||||
Полностью с вами согласен:) | ||||