| ||||
| ||||
подписываю своей прогой простой тхт файлик. ГОСТ. ЭЦП в отдельном файле. проверяю - все ок. Запускаю АРМ выбираю подписанный тхт файл и файл ЭЦП. выводится ошибка -Ошибка при декодировании сообщения!- В чем причина? спасибо | ||||
Ответы: | ||||
| ||||
Файл с подписью должен соответствовать RFC 3369, "Cryptographic Message Syntax", August 2002 (http://www.ietf.org/rfc/rfc3369.txt) с учетом использования криптографических алгоритмов ГОСТ 28147-89, ГОСТ Р 34.10-94, ГОСТ Р 34.10-2001, ГОСТ Р 34.11-94 в соответствии с проектом рекомендаций "Using the GOST 28147-89, GOST R 34.11-94, GOST R 34.10-94 and GOST R 34.10-2001 algorithms with the Cryptographic Message Syntax (CMS)" (http://www.ietf.org/internet-drafts/draft-ietf-smime-gost-02.txt). | ||||
| ||||
Подпись получаю ф-ей CryptSignHash(hash, AT_KEYEXCHANGE, nil, 0, Pointer(signature), @size). Подскажите, мне нужно полученную ЭЦП еще перекодировать? | ||||
| ||||
ф-ей CryptSignHash вы получаете подписанный хэш. Это еще не подпись, того формата, который понимает АРМ разбора КС. Смотрите мой предыдущий ответ. | ||||
| ||||
Здравствуйте, Вероятно CryptSignMessage должно помочь. Смотрите наши примеры, <http://msdn.microsoft.com/library/en-us/security/security/cryptsignmessage.asp> или <http://msdn.microsoft.com/library/en-us/security/security/procedure_for_signing_data.asp>. Успехов. | ||||
| ||||
Дело в том что эта ф-я требует наличия сертификата.. а мне бы не хотелось с ним связываться. В криптоконтейнере его может и не быть, да и уже времени нет :) ). Можно ли привести к этому формату искусственно? т.е. создать заголовок самому и перекодировать в pkcs7? спасибо. | ||||
| ||||
Возвращаемся к началу разговора: 1. в сабже был АРМ разбора конфликтов. А он подпись без сертификатов ключей подписи не проверяет. 2. Подпись на подписанном сообщении предусматривает наличие информации о сертификате ключе подписи и его издателе. Итог: без сертификатов нет подписи! | ||||
| ||||
Здравствуйте, Вам надо что-бы ЭЦП было проверено на АРМ разбора. Для это нужно выполнение следующих условий: 1. ЭЦП должно быть в формате собщения CMS (PKCS#7); 2. Формат сообщения CMS (PKCS#7) требует, либо наличия сертификата открытого ключа, которым выполнено ЭЦП, в самом сообщении, либо собщение должно содержать серийный номер этого сертификата, либо содержать идентифкатор открытого ключа этого сертификата (cMsgCert != 0, cMsgCert == 0 && !(dwFlags&CRYPT_MESSAGE_KEYID_SIGNER_FLAG ), cMsgCert == 0 && (dwFlags&CRYPT_MESSAGE_KEYID_SIGNER_FLAG )); 3. Для этого сертификата АРМ может построить цепочку до сертификата находящегося в хранилище "Доверенные корневые центры сертификации"; 4. У АРМ есть СОС (список отозванных сертификатов, CRL) от УЦ выпустившего этот сертификат и он не отозван; > В криптоконтейнере его может и не быть, да и уже времени нет :) Если сертифакт у АРМ есть, то Ваш клиент на Windows 2k и выше может попробовать вызвать CryptSignMessage c (cMsgCert == 0 && (dwFlags&CRYPT_MESSAGE_KEYID_SIGNER_FLAG )) и pSigningCert созданном в ОЗУ с заполненым CERT_KEY_CONTEXT_PROP_ID. Либо Вы можете, прочитать цитированные RFC и draft, промоделировать на CryptSignMessage, и на коленке преобразовать результат CryptSignHash в CMS (PKCS#7). Если удавить все атрибуты и сертификаты, то там не очень сложно. Успехов. | ||||
| ||||
P.S. Если времени нет, то считайте, что в контейнере есть сертификат (большинство приложений КриптоПро CSP использует XEnroll или capilite, а они его туда всегда пытаются запихнуть). Соотвественно, делайте CryptGetKeyParam(..KP_CERTIFICATE..), формируйте CERT_CONTEXT c CERT_KEY_CONTEXT_PROP_ID и зовите CryptSignMessage. Для первой версии будет нормально. Успехов. | ||||
| ||||
В соответствии с последним советом и посмотрев Ваши примеры делаю так: ... CryptAcquireContext(); CryptGetUserKey(hProv, AT_KEYEXCHANGE, @hUserKey); CryptGetKeyParam(hUserKey, KP_CERTIFICATE, nil, @dwUserCertLength, 0); SetLength(pbUserCert,dwUserCertLength); CryptGetKeyParam (hUserKey, KP_CERTIFICATE, Pointer(pbUserCert), @dwUserCertLength, 0); PCRTC:=CertCreateCertificateContext(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, Pointer(pbUserCert), dwUserCertLength); SigParams.cbSize := sizeof(CRYPT_SIGN_MESSAGE_PARA); SigParams.dwMsgEncodingType := X509_ASN_ENCODING or PKCS_7_ASN_ENCODING; SigParams.pSigningCert := PCRTC; SigParams.HashAlgorithm.pszObjId := szOID_CP_GOST_R3411; SigParams.HashAlgorithm.Parameters.cbData := 0; SigParams.HashAlgorithm.Parameters.pbData := nil; SigParams.cMsgCert := 0; SigParams.rgpMsgCert := 0; SigParams.cAuthAttr := 0; SigParams.dwInnerContentType := 0; SigParams.cMsgCrl := 0; SigParams.cUnauthAttr := 0; SigParams.dwFlags := 0; SigParams.pvHashAuxInfo := nil; SigParams.rgAuthAttr := nil; CryptSignMessage(@SigParams,TRUE,1,ar1,ar2,nil,@size) ... Валится при первом вызове CryptSignMessage c ошибкой все время по одному и тому же адресу памяти в crypt32.dll Вопрос: нужно ли делать CryptAcquireContext и не вызывает ли CryptSignMessage его еще раз из себя или может причина в чем-то другом? | ||||
| ||||
Здравствуйте, > Вопрос: нужно ли делать CryptAcquireContext и не вызывает ли CryptSignMessage его еще раз из себя или может причина в чем-то другом? Хороший вопрос. Я же Вам указывал на необходимость установки CERT_KEY_CONTEXT_PROP_ID, а Вы это проигнорировали. Смотрите описание CertSetCertificateContextProperty. > Валится при первом вызове CryptSignMessage c ошибкой все время по одному и тому же адресу памяти в crypt32.dll Ну я же Вам не отладчик. Успехов. | ||||
| ||||
Господа! Взгляните краем глаза. видимо упускаю чтото. но все примеры,форум уже просмотрел и идей просто больше нет.. вываливается на CryptSignMessage в Access Volation. var SigParams : CRYPT_SIGN_MESSAGE_PARA; i : Integer; size : DWORD; arrBuff : array of PBYTE; arrECP : array of PBYTE; lenBuff,lenECP : array of DWORD; hUserKey : HCRYPTKEY; dwUserCertLength: DWORD; pbUserCert : String; PCRTC : PCCERT_CONTEXT; s : String; EncryptPara : CRYPT_ENCRYPT_MESSAGE_PARA ; rgpRecipientCert :array of PCCERT_CONTEXT; begin s:=’’; size:=0; SetLastError(0); CryptAcquireContext(@hProv, PChar(name), nil, PROV_GOST_2001_DH, 0); if not CryptGetUserKey (hProv, AT_KEYEXCHANGE, @hUserKey) then begin end; if not CryptGetKeyParam (hUserKey, KP_CERTIFICATE, nil, @dwUserCertLength, 0) then begin end; SetLength (pbUserCert,dwUserCertLength); if not CryptGetKeyParam (hUserKey, KP_CERTIFICATE, Pointer(pbUserCert), @dwUserCertLength, 0) then begin end; PCRTC:=CertCreateCertificateContext(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, Pointer(pbUserCert), dwUserCertLength); if (PCRTC=nil) then begin end; if not CertSetCertificateContextProperty(PCRTC,CERT_KEY_CONTEXT_PROP_ID,CERT_STORE_NO_CRYPT_RELEASE_FLAG,nil) then begin end; ZeroMemory(@SigParams,sizeof(CRYPT_SIGN_MESSAGE_PARA)); SigParams.cbSize := sizeof(CRYPT_SIGN_MESSAGE_PARA); SigParams.dwMsgEncodingType := X509_ASN_ENCODING or PKCS_7_ASN_ENCODING; SigParams.pSigningCert := PCRTC; SigParams.HashAlgorithm.pszObjId := szOID_CP_GOST_R3411; SigParams.HashAlgorithm.Parameters.cbData := 0; SigParams.cMsgCert := 0; SigParams.rgpMsgCert := nil; SigParams.cAuthAttr := 0; SigParams.dwInnerContentType := 0; SigParams.cMsgCrl := 0; SigParams.cUnauthAttr := 0; SigParams.dwFlags := 0; SigParams.pvHashAuxInfo := nil; SigParams.rgAuthAttr := nil; SigParams.dwInnerContentType:=0; SetLength(arrBuff,1); SetLength(lenBuff,1); SetLength(ECP,9024); arrBuff[0]:= Pointer(Buff[1]); lenBuff[0]:=Length(Buff); if(CryptSignMessage( @SigParams, TRUE, 1, arrBuff, lenBuff, Pointer(ECP), @size ) ) then begin end; | ||||
| ||||
а чему у Вас равен последний параметр в CryptSignMessage? | ||||
| ||||
последний параметр=0. насколько я понял ф-я должна вернуть в него размер подписи.. я пробовал использовать в 2 прохода, на результат это не повлияло. Access Volation | ||||
| ||||
Здравствуйте, Причины "Access Volation" не ясны. Но, очевидно, что Вы не устанавливаете для PCRTC. Нужно установить hProv и AT_KEYEXCHANGE в свойства PCRTC. Успехов. | ||||
| ||||
Если на входе в функцию, Pointer(ECP) != 0 (pbSignedBlob != 0), то в она должна вернуть ERROR_MORE_DATA для size == 0 (*pcbSignedBlob == 0) | ||||
| ||||
Добрый день! не совсем понял что значит установить. я ведь при получении контекста использую CryptAcquireContext(@hProv, PChar(name), nil, PROV_GOST_2001_DH, 0); CryptGetUserKey (hProv, AT_KEYEXCHANGE, @hUserKey); т.е. они установлены... или сделать CertSetCertificateContextProperty(PCRTC,CERT_KEY_PROV_HANDLE_PROP_ID,CERT_STORE_NO_CRYPT_RELEASE_FLAG ,nil); CertSetCertificateContextProperty(PCRTC,CERT_KEY_SPEC_PROP_ID,CERT_STORE_NO_CRYPT_RELEASE_FLAG ,nil); так это не помагает.. | ||||
| ||||
Вы же устанавливаете CERT_KEY_PROV_HANDLE_PROP_ID в nil, и не задаёте, что следует использовать AT_EXCHANGE с помощью CERT_KEY_PROV_INFO_PROP_ID. Вы же должны объяснить CryptoAPI, что этот ключ для этого сертификата, а не для другого. Читайте MSDN. На мой взгляд лучше использовать CERT_KEY_CONTEXT_PROP_ID | ||||
| ||||
Пардон. Вы же устанавливаете CERT_KEY_PROV_HANDLE_PROP_ID в nil, и не задаёте, что следует использовать AT_EXCHANGE с помощью CERT_KEY_SPEC_PROP_ID. | ||||
| ||||
Подскажите, а это на CAPICOM или Xenroll можно сделать? | ||||
| ||||
Добрый день! С подписанием разобрался. АРМ РКС все воспринимает. А какую функцию мне нужно использовать теперь для проверки, CryptVerifyDetachedMessageSignature или CryptVerifyMessageSignature, если при подписании detached=True, наверно CryptVerifyDetachedMessageSignature ? | ||||