16.05.2007 15:13:58Подпись при помощи низкоуровневых функций Ответов: 14
jar
Имею код:
//////////////////////////////////////
CMSG_STREAM_INFO stream = {};
stream.cbContent = 0xFFFFFFFF;
stream.pfnStreamOutput = SavingCallback;
stream.pvArg = (void*)pobjOutFile;

HCRYPTPROV hProv = NULL;
DWORD dwKeySpec = NULL;
BOOL bFree = FALSE;
if (!CryptAcquireCertificatePrivateKey(*pobjSign, 0, NULL, &hProv, &dwKeySpec, &bFree)) {
//Исключение
}

if (hProv == NULL) {
//Исключение
}

CMSG_SIGNER_ENCODE_INFO signerInfo;
CMSG_SIGNER_ENCODE_INFO signerInfoArray[1];

memset(&signerInfo, 0, sizeof(CMSG_SIGNER_ENCODE_INFO));
signerInfo.cbSize = sizeof(CMSG_SIGNER_ENCODE_INFO);
signerInfo.pCertInfo = ((PCCERT_CONTEXT)pobjSign)->pCertInfo;
signerInfo.hCryptProv = hProv;
signerInfo.dwKeySpec = dwKeySpec;
signerInfo.HashAlgorithm.pszObjId = (LPSTR)(pobjSign->GetHashOID().c_str());
signerInfo.pvHashAuxInfo = NULL;

signerInfoArray[0] = signerInfo;

CMSG_SIGNED_ENCODE_INFO info;
memset(&info, 0, sizeof(CMSG_SIGNED_ENCODE_INFO));
info.cbSize = sizeof(CMSG_SIGNED_ENCODE_INFO);
info.cSigners = 1;
info.rgSigners = signerInfoArray;

HCRYPTMSG hMsg = CryptMsgOpenToEncode(MY_ENCODING_TYPE, 0, CMSG_SIGNED, &info, 0, &stream);
/////////////////////////////////////////////

Получаем hMsg равным нулю.
GetLastError() даёт ошибку 0x80090020 (Внутренняя ошибка)

Что здесь реализовано неправильно?

Если подписывать при помощи CryptSignMessage подпись ставится. Но мне нужна именно работа с потоками.
 
Ответы:
16.05.2007 16:33:50jar
Буду благодарен за любую помощь.
По-моему, в csptest и MSDN аналогично сделано, но не понятно, почему в моём коде выдаёт Внутреннюю Ошибку?
У меня КриптоПро CSP 2.0 (Build 2089)
16.05.2007 17:03:24Kirill Sobolev
А что такое pobjSign?
17.05.2007 9:31:45jar
pobjSign - это указатель на наш класс, инкапсулирующий работу с подписями.
Операция ((PCCERT_CONTEXT)pobjSign) просто возвращает член класса, который объявлен так:
PCCERT_CONTEXT pSignerCert;

pobjSign->GetHashOID() возвращает член класса std::basic_string<char> saHashOID, который просто инициализируется в конструкторе.
Я изменил строку на
signerInfo.HashAlgorithm.pszObjId = (LPSTR)(pobjSign->GetHashOID().data());
Всё равно возникает внутренняя ошибка.
17.05.2007 10:14:47jar
В нашем случае signerInfo.HashAlgorithm.pszObjId принимает значение, например, "1.2.643.2.2.9"
17.05.2007 10:39:26Kirill Sobolev
А без CMSG_STREAM_INFO работает?
17.05.2007 11:07:16jar
Нет, если вместо него передать в CryptMsgOpenToEncode значение NULL, та же самая ошибка.
Если делать через CryptSignMessage(), работает.
17.05.2007 11:31:02jar
_Эта_ проблема решена. Оказывается, я забыл взять значение по адресу:
PCCERT_CONTEXT(*pobjSign)->pCertInfo;
Такую ерунду не заметил :)
Спасибо за помощь!
26.09.2007 17:12:56Иван
Уважаемый, Jar!

Не могли бы Вы проконсультировать по поводу использования потоков при операциях подписи/шифрования. Почитал MSDN - голову сломал. Если не трудно, вышлите хотя бы скелет функции, которую вы здесь привели. Меня интересует порядок вызовов функций CryptoAPI при работе с потоками, а также выставленные флаги и размеры буферов...

Заранее спасибо!

rysev@inbox.ru
27.09.2007 11:03:25Kirill Sobolev
А вот в MSDN есть пример тоже
http://msdn2.microsoft.com/en-us/library/aa382381.aspx
27.09.2007 12:59:19Иван
О, замечательно. Кирилл, спасибо!

Меня вот какой вопрос ещё интересует. В MSDN в описаниях функций CryptMsg* используется термин "encoding", в то время как в прочих функциях - "encrypting". Это тождественно по функциональному наполнению?
27.09.2007 13:43:53Kirill Sobolev
Нет, это разные вещи. Под encoding в CryptoAPI подразумевается кодирование в криптографические форматы, под encrypting - исключительно шифрование.
27.09.2007 13:53:05Иван
А почему в Вашем примере csptest в исходном коде в комментариях говорится о шифровании при использовании CryptMsg*? Или я чего-то недопонимаю?

Спасибо
27.09.2007 14:16:44Kirill Sobolev
Потому что с помощью CryptMsg* можно как шифровать, так и кодировать результат в криптографический формат. Как и в функции CryptEncryptMessage.
MSDN: The CryptEncryptMessage function encrypts and encodes a message.
А вот функция CryptEncrypt умеет только шифровать, кодировать она не умеет.
27.09.2007 17:11:32jar
Иван,
К сожалению мы пока отказались от поддержки потоков, т.к. была затруднена поддержка некоторых функций.
Но если будут конкретные вопросы по работе с потоками, если смогу постараюсь помочь...