Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Как сделать цифровую подпись на основе сертификата / 25 сообщений из 128, страница 1 из 6
02.09.2007, 11:16
    #34770141
LimonFX
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как сделать цифровую подпись на основе сертификата
Сорри несколько за глупый вопрос. Просто проект нужно сдать в понедельник. Время поджимает и реально не успеваю.
Что нужно:
на основе сертификата (выбирается вручную из установленных) подписать файл цифровой подписью, а потом проверить эту самую подпись. Стало быть как сделать? Если кто-нибудь кинет рабочим примером на Дельфи, буду очень благодарен.
...
Рейтинг: 0 / 0
02.09.2007, 13:31
    #34770195
Альт
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как сделать цифровую подпись на основе сертификата
Вам ответил на форуме КриптоПро Кирил Соболев... а это наверное единственный человек... отвечающий на вопросы сторонних разработчиков... использующих продукты борланда
И ответил правильно... дал сылку на sample в си-исходниках... казалось бы, что еще требуется специалисту... вы же начали клянчить код на паскале...
Что могу добавить еще по теме... вам требуется научиться пользоваться минимальным набором функций "Simplified Message Functions" из крипто раздела msdn

зы: или назвать сумму вечнозеленых... с которой вы готовы расстаться... чтобы другие люди писали за вас код
...
Рейтинг: 0 / 0
02.09.2007, 14:17
    #34770212
LimonFX
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как сделать цифровую подпись на основе сертификата
На форуме КриптоПро вопрос задавал человек, который ушел в отпуск. А эту задачу теперь повесили на меня. Я с такими вещами никогда не работал и поэтому решил написать здесь. CryptoAPI я сейчас активно изучаю, но и еще хотелось бы посмотреть на код-пример.
...
Рейтинг: 0 / 0
02.09.2007, 14:49
    #34770233
Альт
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как сделать цифровую подпись на основе сертификата
тогда остается только повторить... что исходники примеров растут тут:
http://www.cryptopro.ru/cryptopro/products/csp/20/sample-2-0.zip
раздел msdn по CryptoAPI можно почитать тут:
http://msdn2.microsoft.com/en-us/library/aa380252.aspx

CryptoAPI message functions consist of two groups of functions: low-level message functions and simplified message functions.

Simplified message functions are at a higher level and wrap several low-level message functions and certificate functions into single functions that perform a specific task in a specific manner. These functions reduce the number of function calls needed to accomplish a task, thereby simplifying CryptoAPI use. For an overview of simplified messages, see Simplified Messages.

а из них только вот эти две:
CryptSignMessage
CryptVerifyDetachedMessageSignature (CryptVerifyMessageSignature)

код за вас я писать не буду, но на конкретные вопросы (подкрепленные самостоятельно написанным кодом) отвечу
...
Рейтинг: 0 / 0
03.09.2007, 11:53
    #34771169
LimonFX
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как сделать цифровую подпись на основе сертификата
Добрался до функции
function CertFindCertificateInStore(hCertStore :HCERTSTORE;
dwCertEncodingType :DWORD;
dwFindFlags :DWORD;
dwFindType :DWORD;
const pvFindPara :PVOID;
pPrevCertContext :PCCERT_CONTEXT
):PCCERT_CONTEXT ; stdcall;

Не моуг понять что должно быть указано в параметре pvFindPara? Знаю что это должно быть название сертификата. Пробовал искать его в личных сертификатах, но где оно там написано не понял. Там есть инфа о том кому выдали сертификат, кто выдал, когда выдали и т.д.
...
Рейтинг: 0 / 0
03.09.2007, 14:46
    #34771870
MAX2002
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как сделать цифровую подпись на основе сертификата
может эта статейка тебе поможет?
...
Рейтинг: 0 / 0
03.09.2007, 15:19
    #34772011
Альт
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как сделать цифровую подпись на основе сертификата
LimonFXДобрался до функции
function CertFindCertificateInStore(hCertStore :HCERTSTORE;
dwCertEncodingType :DWORD;
dwFindFlags :DWORD;
dwFindType :DWORD;
const pvFindPara :PVOID;
pPrevCertContext :PCCERT_CONTEXT
):PCCERT_CONTEXT ; stdcall;

Не моуг понять что должно быть указано в параметре pvFindPara? Знаю что это должно быть название сертификата. Пробовал искать его в личных сертификатах, но где оно там написано не понял. Там есть инфа о том кому выдали сертификат, кто выдал, когда выдали и т.д.

Вот это уже более конструктивный разговор....
http://msdn2.microsoft.com/en-us/library/aa376064.aspx
Я не совсем понял, что подразумевается под под "названием сертификата", у него куча атрибутов, но предположим, что это CERT_FIND_SUBJECT_STR для dwFindType... msdn однозначно говорит, что pvFindPara для CERT_FIND_SUBJECT_STR должен быть data type: null-terminated Unicode string... т.е.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
 var 
  wsFind : WideString;
  ...
 begin 
  ...
  wsFind := 'find';
  m_pHandle := CertFindCertificateInStore(...., CERT_FIND_SUBJECT_STR, PWideString( wsFind ), ... );
  ...
...
Рейтинг: 0 / 0
03.09.2007, 16:11
    #34772232
LimonFX
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как сделать цифровую подпись на основе сертификата
C предыдущим вопросом я уже разобрался - сертификат находит. Теперь другая проблема. Функция CertNameToStr возвращает не нулевое значение, а вот Cert_name почему-то пустой.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
........
  hStoreHandle := CertOpenSystemStore( 0 , PChar(CERT_STORE_NAME));
........
  enctype := PKCS_7_ASN_ENCODING  or  X509_ASN_ENCODING;
  pSignerCert:= CertFindCertificateInStore(hStoreHandle,enctype, 0 ,CERT_FIND_SUBJECT_STR,pSignerName, nil );
   if  pSignerCert <>  nil   then 
    SignSize := CertNameToStr(encType, @pSignerCert.pCertInfo.Issuer , CERT_SIMPLE_NAME_STR, Cert_name,  512 );
  Memo.Lines.Add(IntToStr(SignSize));
  Memo.Lines.Add(Cert_name);
...
Рейтинг: 0 / 0
03.09.2007, 16:17
    #34772258
__Avenger__
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как сделать цифровую подпись на основе сертификата
Может данная статья поможет?
...
Рейтинг: 0 / 0
03.09.2007, 17:58
    #34772637
LimonFX
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как сделать цифровую подпись на основе сертификата
Сам нашел свою ошибку. Забыл вот эту строчку написать в коде Cert_name:= StrAlloc(2048); :)

Альт
Допустим я вытащил цифровую подпись из сертификата. Дальше мне нужно проверить подписанный файл. Какую из след. функции мне использовать, в чем их разница?
CryptSignMessage или CryptVerifyDetachedMessageSignature
...
Рейтинг: 0 / 0
03.09.2007, 19:13
    #34772784
Альт
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как сделать цифровую подпись на основе сертификата
LimonFXСам нашел свою ошибку. Забыл вот эту строчку написать в коде Cert_name:= StrAlloc(2048); :)
Допустим я вытащил цифровую подпись из сертификата. Дальше мне нужно проверить подписанный файл. Какую из след. функции мне использовать, в чем их разница?
CryptSignMessage или CryptVerifyDetachedMessageSignature

Плохо искал ошибку... узнай, что такое "Retrieving Data of Unknown Length"... пройдет желание писать "StrAlloc(2048)" ))
Самое забавное, что ничего тебе уже не надо... ты поймал контекст сертификата, а именно с ним и работают сипл-функции
Первая подписывает... вторая проверяет detached подписи
...
Рейтинг: 0 / 0
04.09.2007, 12:48
    #34774138
LimonFX
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как сделать цифровую подпись на основе сертификата
Со StrAlloc потом буду разбираться, не столь важно это сейчас.
На данный момент EXEшник собирается и даже работает, но результатом проверки подписи является такая вот ошибка NTE_BAD_ALGID. Вроде как не нравится используемый алгоритм. Хотелось бы узнать на что нужно в первую очередь обратить внимание, чтобы узнать причину этой ошибки?
...
Рейтинг: 0 / 0
04.09.2007, 12:58
    #34774194
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как сделать цифровую подпись на основе сертификата
NTE_BAD_ALGID The hHash handle specifies an algorithm that this CSP does
not support.

Покажи, какие константы CALG_* использовал?
Posted via ActualForum NNTP Server 1.4
...
Рейтинг: 0 / 0
04.09.2007, 14:01
    #34774481
LimonFX
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как сделать цифровую подпись на основе сертификата
ALG_ID нигде не использовал. Где его нужно указывать?
...
Рейтинг: 0 / 0
04.09.2007, 14:03
    #34774495
Альт
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как сделать цифровую подпись на основе сертификата
LimonFXСо StrAlloc потом буду разбираться, не столь важно это сейчас.
На данный момент EXEшник собирается и даже работает, но результатом проверки подписи является такая вот ошибка NTE_BAD_ALGID. Вроде как не нравится используемый алгоритм. Хотелось бы узнать на что нужно в первую очередь обратить внимание, чтобы узнать причину этой ошибки?

А как именно выполняется проверка? Например CRYPT_VERIFY_MESSAGE_PARA обязательно должна быть предварительно занулена и потом наполнена... размер cbSize должен быть правильным... подкрепляйте вопрос кодом, гадание на кофейной гуще утомляет...

для CryptVerify*
NTE_BAD_ALGID The message was hashed and signed by using an unknown or unsupported algorithm.

Как вариант... в системе отсутствует необходимый провайдер
...
Рейтинг: 0 / 0
04.09.2007, 14:11
    #34774530
LimonFX
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как сделать цифровую подпись на основе сертификата
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
.......  
VerifyPara.cbSize := SizeOf(CRYPT_VERIFY_MESSAGE_PARA);
  VerifyPara.dwMsgAndCertEncodingType := enctype;
  VerifyPara.hCryptProv := hProv;
  VerifyPara.pfnGetSignerCertificate := @MySignerCertificateCallback;
  VerifyPara.pvGetArg := pSignerCert;


   if  (dlgOpenSign.Execute)  and  (dlgOpenSign.FileName <> EmptyStr)  then 
   begin 
 //файл с подписью 
    AssignFile(f1,dlgOpenSign.FileName);
    Reset(f1,  1 );
    SignSize := FileSize(f1);
    GetMem(Sign, SignSize);

    BlockRead(f1,Sign^,SignSize);
    CloseFile(f1);
   end ;

   if  (dlgOpenFile.Execute)  and  (dlgOpenFile.FileName <> EmptyStr)  then 
   begin 
 //подписанынй файл 
    SetLength(MessageArray, sizeof(PByte));
    SetLength(MessageSize, sizeof(DWORD));

    AssignFile(f1,dlgOpenFile.FileName);
    Reset(f1,  1 );

    MessageSize[ 0 ] := FileSize(f1);
    GetMem(MessageArray[ 0 ], MessageSize[ 0 ]);

    BlockRead(f1, MessageArray[ 0 ]^, MessageSize[ 0 ]);
    CloseFile (f1);
   end ;


   if  CryptVerifyDetachedMessageSignature(@VerifyPara,  0 , Sign, SignSize,  1 , MessageArray, MessageSize, pSignerCert)  then 
   begin 
    Memo.Lines.Add('Проверка прошла успешно');
   end 
   else 
   begin 
    err := IntToStr(GetLastError);
    Memo.Lines.Add('Ошибка:' + err);
   end ;
...
Рейтинг: 0 / 0
04.09.2007, 14:13
    #34774538
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как сделать цифровую подпись на основе сертификата
LimonFXГде его нужно указывать?

В CryptCreateHash например...
Posted via ActualForum NNTP Server 1.4
...
Рейтинг: 0 / 0
04.09.2007, 15:31
    #34774861
Альт
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как сделать цифровую подпись на основе сертификата
Предположим, что подпись и сообщение читаются правильно... и содержат все необходимые данные....
Ну и заполняется вами вроде вся структура... хотя и тут есть свой нюанс:
VerifyPara.hCryptProv := hProv;
хендл какого провайдера вы сюда подпихиваете? может ну его нафик... жираф то большой и ему видней... скиньте в ноль... он сам проверить провайдеров в системе на факт реализации необходимых алгоритмов
VerifyPara.hCryptProv := 0;

Надеюсь и калбек (MySignerCertificateCallback) делает, что нужно

а подписывалось на каком HashAlgorithm.pszObjId?
...
Рейтинг: 0 / 0
05.09.2007, 17:33
    #34778768
LimonFX
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как сделать цифровую подпись на основе сертификата
Вообщем задача немного поменялась. Теперь все в одном флаконе (инфа и подпись в одном файле), т.е. не detached. Старый код выбросил, залез на msdn, нашел там подходящий пример и на его основе сделал вот этот код:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
 procedure  TForm1.Button3Click(Sender: TObject);
 Const 
  CERT_STORE_NAME = 'MY';
  MY_ENCODING_TYPE = PKCS_7_ASN_ENCODING  or  X509_ASN_ENCODING;
 var 
  hCertStoreHandle : HCERTSTORE;
  SIGNER_NAME:  string ;
  pSignerName: PWideChar;
   //pbMessage: PByte; 
   //cbMessage: DWORD; 
  MessageArray:  array   of  PByte;
  MessageSize :  array   of  DWORD;
  pSignerCert: PCCERT_CONTEXT;
  SigParams: CRYPT_SIGN_MESSAGE_PARA;
  cbSignedMessageBlob: DWORD;
  pbSignedMessageBlob: PByte;
  pSignedMessageBlob: CRYPT_DATA_BLOB;
  err:  String ;
  f1:  File ;
 begin 
  Memo.Clear;
  SIGNER_NAME := 'test';
  hCertStoreHandle :=  nil ;
  pSignedMessageBlob.cbData :=  0 ;
  pSignedMessageBlob.pbData :=  nil ;
  hCertStoreHandle := CertOpenSystemStore( 0 ,PChar(CERT_STORE_NAME));
   if  hCertStoreHandle =  nil   then  Memo.Lines.Add('Ошибка при открытии хранилища ' + CERT_STORE_NAME);
  GetMem(pSignerName, 2 *Length(SIGNER_NAME)+ 1 );
  StringToWideChar(SIGNER_NAME,pSignerName, 2 *Length(SIGNER_NAME)+ 1 );
  pSignerCert := CertFindCertificateInStore(
                                            hCertStoreHandle,
                                            MY_ENCODING_TYPE,
                                             0 ,
                                            CERT_FIND_SUBJECT_STR,
                                            pSignerName,
                                             nil );
  FreeMem(pSignerName);
   if  pSignerCert =  nil   then 
   begin 
    err := IntToStr(GetLastError);
    Memo.Lines.Add('Сертификат ' + SIGNER_NAME + ' не найден: ' + err);
    exit;
   end ;

   if  (srcFile.Execute)  and  (srcFile.FileName <> EmptyStr)  then 
   begin 
    SetLength(MessageArray,  1 *sizeof(PByte));
    SetLength(MessageSize,  1 *sizeof(DWORD));

    AssignFile(f1,srcFile.FileName);
    Reset(f1,  1 );

    MessageSize[ 0 ] := FileSize(f1);
    GetMem(MessageArray[ 0 ], MessageSize[ 0 ]);

    BlockRead(f1, MessageArray[ 0 ]^, MessageSize[ 0 ]);
    CloseFile (f1);
   end ;

  SigParams.cbSize := SizeOF(CRYPT_SIGN_MESSAGE_PARA);
  SigParams.dwMsgEncodingType := MY_ENCODING_TYPE;
  SigParams.pSigningCert := pSignerCert;
  SigParams.HashAlgorithm.pszObjId := szOID_PKCS_7;
  SigParams.HashAlgorithm.Parameters.cbData :=  0 ;
  SigParams.cMsgCert :=  1 ;
  SigParams.rgpMsgCert := @pSignerCert;
  SigParams.cAuthAttr :=  0 ;
  SigParams.dwInnerContentType :=  0 ;
  SigParams.cMsgCrl :=  0 ;
  SigParams.cUnauthAttr :=  0 ;
  SigParams.dwFlags :=  0 ;
  SigParams.pvHashAuxInfo :=  nil ;
  SigParams.rgAuthAttr :=  nil ;

   if   not  (CryptSignMessage(
        @SigParams,
        FALSE,
         1 ,
        MessageArray,
        MessageSize,
         nil ,
        @cbSignedMessageBlob))  then 
   begin 
    err := IntToStr(GetLastError);
    Memo.Lines.Add('Размер буфера: ' + err);
    exit;
   end ;
  GetMem(pbSignedMessageBlob, cbSignedMessageBlob);
   if   not  (CryptSignMessage(
          @SigParams,
          FALSE,
           1 ,
          MessageArray,
          MessageSize,
          pbSignedMessageBlob,
          @cbSignedMessageBlob))  then 
   begin 
    err := IntToStr(GetLastError);
    Memo.Lines.Add('Файл не подписан: ' + err);
    exit;
   end 
   else  Memo.Lines.Add('Файл подписан: ' + err);
  CertFreeCertificateContext(pSignerCert);
  CertCloseStore(hCertStoreHandle, CERT_CLOSE_STORE_CHECK_FLAG);
  hCertStoreHandle :=  nil ;
  pSignedMessageBlob.cbData := cbSignedMessageBlob;
  pSignedMessageBlob.pbData := pbSignedMessageBlob;
   if  SaveSignFile.Execute  then 
   begin 
    AssignFile(f1,SaveSignFile.FileName);
    Rewrite(f1,  1 );
    BlockWrite(f1, pbSignedMessageBlob^, cbSignedMessageBlob);
    CloseFile (f1);
   end ;
 end ;

 procedure  TForm1.Button4Click(Sender: TObject);
 Const 
  CERT_STORE_NAME = 'MY';
  MY_ENCODING_TYPE = PKCS_7_ASN_ENCODING  or  X509_ASN_ENCODING;
  PROVIDER_NAME = '';
 var 
  hCertStoreHandle: HCERTSTORE;
  cbDecodedMessageBlob: DWORD;
  pbDecodedMessageBlob: PByte;
  VerifyParams: CRYPT_VERIFY_MESSAGE_PARA;
  pSignedMessageBlob: CRYPT_DATA_BLOB;
  pDecodedMessageBlob: CRYPT_DATA_BLOB;
  err:  string ;
  SIGNER_NAME:  string ;
  pSignerName: PWideChar;
  pSignerCert: PCCERT_CONTEXT;
  MessageArray:  array   of  PByte;
  MessageSize :  array   of  DWORD;
  f1:  File ;
  hProv: HCRYPTPROV;
  
   function  MySignerCertificateCallback( pvGetArg : pvoid; 
dwCertEncodingType : DWORD;
pSignerId : PCERT_INFO;
hMsgCertStore : HCERTSTORE): PCCERT_CONTEXT ; stdcall;
   begin 
    Result := PCCERT_CONTEXT(pvGetArg);
   end ;

 begin 
  pbDecodedMessageBlob :=  nil ;
  pDecodedMessageBlob.cbData :=  0 ;
  pDecodedMessageBlob.pbData :=  nil ;

  Memo.Clear;
  SIGNER_NAME := 'test';
  hCertStoreHandle :=  nil ;
  pSignedMessageBlob.cbData :=  0 ;
  pSignedMessageBlob.pbData :=  nil ;
  hCertStoreHandle := CertOpenSystemStore( 0 ,PChar(CERT_STORE_NAME));
   if  hCertStoreHandle =  nil   then  Memo.Lines.Add('Ошибка при открытии хранилища ' + CERT_STORE_NAME);
  GetMem(pSignerName, 2 *Length(SIGNER_NAME)+ 1 );
  StringToWideChar(SIGNER_NAME,pSignerName, 2 *Length(SIGNER_NAME)+ 1 );
  pSignerCert := CertFindCertificateInStore(
                                            hCertStoreHandle,
                                            MY_ENCODING_TYPE,
                                             0 ,
                                            CERT_FIND_SUBJECT_STR,
                                            pSignerName,
                                             nil );
  FreeMem(pSignerName);
   if  pSignerCert =  nil   then 
   begin 
    err := IntToStr(GetLastError);
    Memo.Lines.Add('Сертификат ' + SIGNER_NAME + ' не найден: ' + err);
    exit;
   end ;

   if   not  CryptAcquireContext(@hProv,  nil , PROVIDER_NAME, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)  then 
   begin 
    Memo.Lines.Add('Провайдер '+PROVIDER_NAME+' не найден');
    exit;
   end ;

  VerifyParams.cbSize := sizeof(CRYPT_VERIFY_MESSAGE_PARA);
  VerifyParams.dwMsgAndCertEncodingType := MY_ENCODING_TYPE;
  VerifyParams.hCryptProv := hProv;
  VerifyParams.pfnGetSignerCertificate := @MySignerCertificateCallback;
  VerifyParams.pvGetArg := pSignerCert;

   if  (srcFile.Execute)  and  (srcFile.FileName <> EmptyStr)  then 
   begin 
    AssignFile(f1,srcFile.FileName);
    Reset(f1,  1 );

    pSignedMessageBlob.cbData := FileSize(f1);
    GetMem(pSignedMessageBlob.pbData, pSignedMessageBlob.cbData);

    BlockRead(f1, pSignedMessageBlob.pbData^, pSignedMessageBlob.cbData);
    CloseFile (f1);
   end ;

   if   not  (CryptVerifyMessageSignature(
                  @VerifyParams,
                   0 ,
                  pSignedMessageBlob.pbData,
                  pSignedMessageBlob.cbData,
                   nil ,
                  cbDecodedMessageBlob,
                   nil ))  then 
   begin 
    err := IntToStr(GetLastError);
    Memo.Lines.Add('Не удалось узнать размер буфера : ' + err);
    exit;
   end ;

  GetMem(pbDecodedMessageBlob,cbDecodedMessageBlob); 

   if   not  (CryptVerifyMessageSignature(
                  @VerifyParams,
                   0 ,
                  pSignedMessageBlob.pbData,
                  pSignedMessageBlob.cbData,
                  pbDecodedMessageBlob,
                  cbDecodedMessageBlob,
                   nil ))  then 
   begin 
    err := IntToStr(GetLastError);
    Memo.Lines.Add('Не удалось проверить подпись: ' + err);
    exit;
   end ;
  pDecodedMessageBlob.cbData := cbDecodedMessageBlob;
  pDecodedMessageBlob.pbData := pbDecodedMessageBlob;
 end ;
Сам файл вроде бы подписывается, ошибок замечено не было. А вот при проверке подписи всё таже ошибка - NTE_BAD_ALGID.
...
Рейтинг: 0 / 0
06.09.2007, 11:24
    #34780265
Альт
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как сделать цифровую подпись на основе сертификата
Нда... очень смешно про "szOID_PKCS_7"... ты где взял этот код? короче уломал ты меня писать за тебя... готовь деньги
Вот слепленная на скорую руку реализация поверх твоей

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
 uses 
  WinCrypt;

 const 
  CERT_STORE_NAME = 'MY';
  MY_ENCODING_TYPE = PKCS_7_ASN_ENCODING  or  X509_ASN_ENCODING;
  SignerName : WideString = 'Pavel';

 procedure  Err(  const  msg :  String  );
 var 
  dwError, dwLen : DWORD;
  sError, sErrorDecode :  String ;
  pBuffer : Cardinal;
 begin 
  dwError := GetLastError;
  dwLen := FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM  or 
                          FORMAT_MESSAGE_ARGUMENT_ARRAY  or 
                          FORMAT_MESSAGE_ALLOCATE_BUFFER,
                           nil , dwError,  0 , @pBuffer,  0 ,  nil  );
   try 
    SetString( sErrorDecode, PChar( pBuffer ), dwLen );
   finally 
    LocalFree( pBuffer );
   end ;
  sError := Format( '%s'# 10 # 13 '0x%x %s', [ msg, dwError, sErrorDecode ] );
  Form1.Memo.Lines.Add( msg );
   Raise  Exception.Create( sError );
 end ;

 procedure  TForm1.Button1Click(Sender: TObject);
 var 
  pSignerCert: PCCERT_CONTEXT;
  hCertStoreHandle : HCERTSTORE;
  SigParams: CRYPT_SIGN_MESSAGE_PARA;
  pStreamIn, pStreamOut : TMemoryStream;
  MessageArray : PAPBYTE;
  MessageSize : PADWORD;
  MessageCert : PAPCCERT_CONTEXT;
  cbSignedMessageBlob: DWORD;
 begin 
  Memo.Clear;
  hCertStoreHandle := CertOpenSystemStore(  0 , PChar( CERT_STORE_NAME ));
   if  (  not  assigned( hCertStoreHandle ))  then 
    Err( Format( 'Ошибка при открытии хранилища: %s', [ CERT_STORE_NAME ] ));
   try 
    pSignerCert := CertFindCertificateInStore( hCertStoreHandle, MY_ENCODING_TYPE,  0 , CERT_FIND_SUBJECT_STR, PWideChar( SignerName ),  nil  );
     try 
       if  (  not  assigned( pSignerCert ))  then 
        Err( Format( 'Сертификат %s не найден', [ SignerName ] ));
      pStreamIn := TMemoryStream.Create;
      pStreamOut := TMemoryStream.Create;
       try 
        pStreamIn.LoadFromFile( 'd:\test.txt' );
        GetMem( MessageArray,  1  * SizeOf( PByte ));
        GetMem( MessageSize,  1  * SizeOf( DWORD ));
        GetMem( MessageCert,  1  * SizeOf( PAPCCERT_CONTEXT ));
        MessageArray[  1  ] := pStreamIn.Memory;
        MessageSize[  1  ] := pStreamIn.Size;
        MessageCert[  1  ] := pSignerCert;
        FillChar( SigParams, SizeOf( CRYPT_SIGN_MESSAGE_PARA ), # 0  );
        SigParams.cbSize := SizeOF( CRYPT_SIGN_MESSAGE_PARA );
        SigParams.dwMsgEncodingType := MY_ENCODING_TYPE;
        SigParams.pSigningCert := pSignerCert;
        SigParams.HashAlgorithm.pszObjId := szOID_RSA_MD5;
        SigParams.cMsgCert :=  1 ;
        SigParams.rgpMsgCert := MessageCert;
         if   not  ( CryptSignMessage( @SigParams, false,  1 , MessageArray, MessageSize,  nil , cbSignedMessageBlob ))  then 
          Err( 'Размер буфера' );
        pStreamOut.Size := cbSignedMessageBlob;
         if   not  ( CryptSignMessage( @SigParams, false,  1 , MessageArray, MessageSize, pStreamOut.Memory, cbSignedMessageBlob ))  then 
          Err( 'Файл не подписан' );
        pStreamOut.Size := cbSignedMessageBlob;
        pStreamOut.SaveToFile( 'd:\test.sig' );
        Memo.Lines.Add( 'Файл подписан' );
       finally 
        FreeAndNil( pStreamIn );
        FreeAndNil( pStreamOut );
       end ;
     finally 
      CertFreeCertificateContext(pSignerCert);
     end ;
   finally 
    CertCloseStore( hCertStoreHandle, CERT_CLOSE_STORE_CHECK_FLAG );
   end ;
 end ;

 procedure  TForm1.Button2Click(Sender: TObject);
 var 
  VerifyParams : CRYPT_VERIFY_MESSAGE_PARA;
  pStreamIn, pStreamOut : TMemoryStream;
  cbDecodedMessageBlob : DWORD;
 begin 
  Memo.Clear;
  pStreamIn := TMemoryStream.Create;
  pStreamOut := TMemoryStream.Create;
   try 
    pStreamIn.LoadFromFile( 'd:\test.sig' );
    FillChar( VerifyParams, SizeOf( CRYPT_VERIFY_MESSAGE_PARA ), # 0  );
    VerifyParams.cbSize := SizeOf( CRYPT_VERIFY_MESSAGE_PARA );
    VerifyParams.dwMsgAndCertEncodingType := MY_ENCODING_TYPE;
     if   not  ( CryptVerifyMessageSignature( @VerifyParams,  0 , pStreamIn.Memory, pStreamIn.Size,
                                           nil , cbDecodedMessageBlob,  nil  ))  then 
      Err( 'Не удалось узнать размер буфера' );
    pStreamOut.Size := cbDecodedMessageBlob;
     if   not  ( CryptVerifyMessageSignature( @VerifyParams,  0 , pStreamIn.Memory, pStreamIn.Size,
                                          pStreamOut.Memory, cbDecodedMessageBlob,  nil  ))  then 
      Err( 'Не удалось проверить подпись' );
    pStreamOut.Size := cbDecodedMessageBlob;
    pStreamOut.SaveToFile( 'd:\test.res' );
    Memo.Lines.Add( 'Подпись верна' );
   finally 
    FreeAndNil( pStreamIn );
    FreeAndNil( pStreamOut );
   end ;
 end ;

у тебя прототипы функций неправильные... ты используешь очень странный алгоритм хеширования... он вообще вычисляется перепобором по-хорошему
Я заморачиваться не стал и просто вложил сертификат в подписанное attached сообщение... потому верификация выглядит так скромно... специфичных мементов в этом коде вагон и маленькая тележка... разбирайся... удачи
...
Рейтинг: 0 / 0
06.09.2007, 11:31
    #34780301
Альт
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как сделать цифровую подпись на основе сертификата
потерял все парные FreeMem в коде есть утечки... только заметил
...
Рейтинг: 0 / 0
06.09.2007, 14:36
    #34781487
LimonFX
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как сделать цифровую подпись на основе сертификата
Про код я уже писал. За основу взял СИшный пример с MSDN. Ну вообщем, спасибо. Будем разбираться, а там глядишь и знающий человек с отпуска вернется.

P.S: еще немного и я смело могу программистом идти работать :)
...
Рейтинг: 0 / 0
11.03.2008, 12:32
    #35182159
vovanka
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как сделать цифровую подпись на основе сертификата
ты прогу домучал?
...
Рейтинг: 0 / 0
27.03.2008, 07:15
    #35216378
Miktor
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как сделать цифровую подпись на основе сертификата
У меня таже проблема. Попробовал код, любезно предоставленный Альт 'ом, но на строчке
Код: plaintext
1.
2.
 if   not  ( CryptSignMessage( @SigParams, false,  1 , MessageArray, MessageSize,  nil , cbSignedMessageBlob ))  then 
          Err( 'Размер буфера' );
вы дает ошибку "Access viol... in module wcrypt32.dll". Я не очень разбираюсь в алгоритмах всей этой криптографии... Мне просто нужно подписать сертификатом и проверить подпись. Может есть готовые решения или компоненты?
...
Рейтинг: 0 / 0
27.03.2008, 12:05
    #35217190
Альт
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как сделать цифровую подпись на основе сертификата
Давайте сверять прототипы функций и типов. Я тоже.. в свое время... стучал головой в монитор... например вот такой нюанс:
WinCrypt.pas
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
 {.$define CRYPT_SIGN_MESSAGE_PARA_HAS_CMS_FIELDS} 

 type 
  PCRYPT_SIGN_MESSAGE_PARA = ^CRYPT_SIGN_MESSAGE_PARA;
  CRYPT_SIGN_MESSAGE_PARA =  record 
    cbSize :DWORD;
    dwMsgEncodingType :DWORD;
    pSigningCert :PCCERT_CONTEXT;
    HashAlgorithm :CRYPT_ALGORITHM_IDENTIFIER;
    pvHashAuxInfo :PVOID;
    cMsgCert :DWORD;
    rgpMsgCert : PPCCERT_CONTEXT;
    cMsgCrl : DWORD;
    rgpMsgCrl : PPCCRL_CONTEXT;
    cAuthAttr :DWORD;
    rgAuthAttr :PCRYPT_ATTRIBUTE;
    cUnauthAttr :DWORD;
    rgUnauthAttr :PCRYPT_ATTRIBUTE;
    dwFlags :DWORD;
    dwInnerContentType :DWORD;
   {$ifdef CRYPT_SIGN_MESSAGE_PARA_HAS_CMS_FIELDS} 
    HashEncryptionAlgorithm : CRYPT_ALGORITHM_IDENTIFIER;
    pvHashEncryptionAuxInfo : DWORD;
   {$endif} 
   end ;
т.е. структура должна быть реально короче для операционок ниже XP/2003
Ну и давайте показывайте все ваши используемые прототипы... танцуя от CryptSignMessage
...
Рейтинг: 0 / 0
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Как сделать цифровую подпись на основе сертификата / 25 сообщений из 128, страница 1 из 6
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]