powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Как сделать цифровую подпись на основе сертификата
25 сообщений из 128, страница 5 из 6
Как сделать цифровую подпись на основе сертификата
    #36913719
Fiyanov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Ура!

было:
Код: plaintext
1.
2.
3.
 function  CryptSignMessage(pSignPara: PCRYPT_SIGN_MESSAGE_PARA;
  fDetachedSignature: BOOL; cToBeSigned: DWORD; rgpbToBeSigned: LPBYTE;
  rgcbToBeSigned: LPDWORD; pbSignedBlob: LPBYTE;  var  pcbSignedBlob: DWORD): BOOL; stdcall;

стало:
Код: plaintext
1.
2.
3.
 function  CryptSignMessage( var  pSignPara: CRYPT_SIGN_MESSAGE_PARA;
  fDetachedSignature: BOOL; cToBeSigned: DWORD; rgpbToBeSigned: LPBYTE;
  rgcbToBeSigned: LPDWORD; pbSignedBlob: LPBYTE;  var  pcbSignedBlob: DWORD): BOOL; stdcall;

сделал как у Альта... пока всё решилось:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
       if  CryptSignMessage(SigParams, False,  1 , @strMessage, @strSize, SignedBlob.pbData, SignedBlob.cbData)  then 
         begin 
          Memo1.Lines.Add('Размер: ' + intToStr(SignedBlob.cbData));
           if  CryptSignMessage(SigParams, False,  1 , @strMessage, @strSize, SignedBlob.pbData, SignedBlob.cbData)  then 
            Memo1.Lines.Add('Подписано!');
         end 
       else  Memo1.Lines.Add('False');
...
Рейтинг: 0 / 0
Как сделать цифровую подпись на основе сертификата
    #36913726
Fiyanov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Хотя странно... в msdn именно PCRYPT_SIGN_MESSAGE_PARA . Но почему то при:

Код: plaintext
1.
2.
 var 
SigParams: CRYPT_SIGN_MESSAGE_PARA;

и вызове функции с этим параметром со знаком "@":

Код: plaintext
1.
  if  CryptSignMessage(@SigParams, ...

Наблюдается как раз мой случай когда после возврата размера прога падает... хотя может дело в ключевом слове var которого в моём заголовочном файле от JEDI не было...
...
Рейтинг: 0 / 0
Как сделать цифровую подпись на основе сертификата
    #37337496
dv_belyaev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
всем привет
в проекте использую шифрование и подпись файлов сертификатами
функции CryptEncryptMessage / CryptDecryptMessage / CryptSignMessage / CryptVerifyMessageSignature

все работает отлично, но есть момент
при расшифровке и проверке подписи у файлов размером ~ 100 Мб и выше
выскакивет ошибка Слишком большое значение ASN1"
в инете ничего кроме http://www.sql.ru/forum/actualthread.aspx?tid=804878 не обнаружил
там чел предлагает "Спасибо, скорее всего нужно блоками дробить."
пробовал расшифровывать кусками - копирую в дополнительный буфер часть файла и на расшифровку
ошибка - "В ASN1 встречен неожиданный конец данных"
наталкивает на мысль что я неправильно загоняю данные в буфер
вот кусок кода (на тестировании подразумеваю что файл больше 100 Мб, но всего 2 куска)

Код: pascal
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.
     pStreamIn := TMemoryStream.Create;
     pStreamOut := TMemoryStream.Create;
     pStreamIn.LoadFromFile(filename);


     if pStreamIn.Size > 95 * 1024 * 1024 then // если файл больше 95 Мб
     begin
       for i := 0 to 1 do
       begin
         tpStreamIn := TMemoryStream.Create;
         tpStreamOut := TMemoryStream.Create;
         if i = 0
           then tpStreamIn.CopyFrom(pStreamIn, 95 * 1024 * 1024)
           else tpStreamIn.CopyFrom(pStreamIn, pStreamIn.Size - pStreamIn.Position);
         tpStreamIn.Position := 0;

         if CryptVerifyMessageSignature( @VerifyParams, 0, tpStreamIn.Memory, tpStreamIn.Size, nil, @cbDecodedMessageBlob, nil ) then
         begin
           tpStreamOut.Size := cbDecodedMessageBlob;
           if CryptVerifyMessageSignature(@VerifyParams, 0, tpStreamIn.Memory, tpStreamIn.Size, tpStreamOut.Memory, @cbDecodedMessageBlob, @pCert) then
           begin
             pStreamOut.Size := pStreamOut.Size + tpStreamOut.Size;
             tpStreamOut.Position := 0;
             pStreamOut.CopyFrom(tpStreamOut, tpStreamOut.Size);
           end;
         end else ShowMessage(SysErrorMessage(GetLastError));
         tpStreamIn.Free;
         tpStreamOut.Free;
       end;
       if pStreamOut.Size > 0 then
       begin
         fotopath := UserTEMPDir+'tmp'+ExtractFileExt(temp);
         DeleteFile(fotopath);
         pStreamOut.SaveToFile( fotopath );
       end;
     end else  //  загоняю целиком
     begin
       if CryptVerifyMessageSignature( @VerifyParams, 0, pStreamIn.Memory, pStreamIn.Size, nil, @cbDecodedMessageBlob, nil ) then
       begin
         pStreamOut.Size := cbDecodedMessageBlob;
         if CryptVerifyMessageSignature(@VerifyParams, 0, pStreamIn.Memory, pStreamIn.Size, pStreamOut.Memory, @cbDecodedMessageBlob, @pCert) then
         begin
           fotopath := UserTEMPDir+'tmp'+ExtractFileExt(temp);
           pStreamOut.Size := cbDecodedMessageBlob;
           pStreamOut.SaveToFile( fotopath );
         end;
       end;
     end;
...
Рейтинг: 0 / 0
Как сделать цифровую подпись на основе сертификата
    #37337927
A-n-d-r-e-y
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Откажись от высокоуровневых функций: CryptVerifyMessageSignature и т.п.
...
Рейтинг: 0 / 0
Как сделать цифровую подпись на основе сертификата
    #37605591
exsander
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Здравствуйте!
Пытаюсь найти установленный в системе тестовый сертификат от КриптоПро. За основу взят код из первых сообщений данной темы
При поиске по отпечатку сертификат не найден, GetLastError возвращает ошибку 0x80092004 Объект или свойство не найдено

Код: pascal
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.
...
implementation
const
  CERT_STORE_NAME = 'ROOT';
  MY_ENCODING_TYPE = PKCS_7_ASN_ENCODING or X509_ASN_ENCODING;
  SignerName : WideString = 'Test Center CRYPTO-PRO';
...
procedure TForm1.btFindHashClick(Sender: TObject);
var
  pSignerCert: PCCERT_CONTEXT;
  hCertStoreHandle : HCERTSTORE;
  iLen, i:integer;
  P:PByte;
  pError:LPCTSTR;
  pCertHash: CRYPT_HASH_BLOB;
begin
  Memo.Clear;
  FillChar(pCertHash,SizeOf(pCertHash),0);

  Memo.Lines.Add(ByteArrayToStr(pCertHash.pbData,pCertHash.cbData));

  hCertStoreHandle := CertOpenSystemStore( 0, PChar( CERT_STORE_NAME ));
  if ( not assigned( hCertStoreHandle )) then
    Err( Format( 'Ошибка при открытии хранилища: %s', [ CERT_STORE_NAME ] ));

  iLen := Length(CertHash.Text) div 2;
  pCertHash.cbData:=iLen;
  pCertHash.pbData:= GetMemory(iLen);

  P:=pCertHash.pbData;
  i:=Length(CertHash.Text)-1;
  while i >= 0 do begin
    P^ := GetHexValue(CertHash.Text[i]) * 16 + GetHexValue(CertHash.Text[i + 1]);
    P := Pointer(Integer(P) + 1);
    dec(i, 2);
  end;
  Memo.Lines.Add(ByteArrayToStr(pCertHash.pbData,pCertHash.cbData));
  pSignerCert := CertFindCertificateInStore(hCertStoreHandle, MY_ENCODING_TYPE, 0, CERT_FIND_SHA1_HASH, @pCertHash, nil);
  if ( not assigned( pSignerCert )) then
    Err('Сертификат не найден')
  else
    Memo.Lines.Add(GetSerialNumber(pSignerCert));
end;




Хочется понять что делается мной не так? Заранее спасибо.
...
Рейтинг: 0 / 0
Как сделать цифровую подпись на основе сертификата
    #37606211
Здравствуйте, я даже задумываться не хочу, что именно делает вот этот говнокод:
exsander 0x80092004 Объект или свойство не найдено

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
  iLen := Length(CertHash.Text) div 2;
  pCertHash.cbData:=iLen;
  pCertHash.pbData:= GetMemory(iLen);

  P:=pCertHash.pbData;
  i:=Length(CertHash.Text)-1;
  while i >= 0 do begin
    P^ := GetHexValue(CertHash.Text[i]) * 16 + GetHexValue(CertHash.Text[i + 1]);
    P := Pointer(Integer(P) + 1);
    dec(i, 2);
  end;




Хочется понять что делается мной не так? Заранее спасибо.

при поиске там должен быть хеш в виде бина, т.е. если вам на влете приходит хеш в виде хекса, то и приводить его надо через HexToBin. Вы точно в правильном хранилище ищите? Сертификат не в MY? На глаз я больше особых проблем не вижу. В моих поделках эта функция объявлена вот так, сравнивайте со своим:
Код: pascal
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.
//+-------------------------------------------------------------------------
//  Find the first or next certificate context in the store.
//
//  The certificate is found according to the dwFindType and its pvFindPara.
//  See below for a list of the find types and its parameters.
//
//  Currently dwFindFlags is only used for CERT_FIND_SUBJECT_ATTR,
//  CERT_FIND_ISSUER_ATTR or CERT_FIND_CTL_USAGE. Otherwise, must be set to 0.
//
//  Usage of dwCertEncodingType depends on the dwFindType.
//
//  If the first or next certificate isn't found, NULL is returned.
//  Otherwise, a pointer to a read only CERT_CONTEXT is returned. CERT_CONTEXT
//  must be freed by calling CertFreeCertificateContext or is freed when passed as the
//  pPrevCertContext on a subsequent call. CertDuplicateCertificateContext
//  can be called to make a duplicate.
//
//  pPrevCertContext MUST BE NULL on the first
//  call to find the certificate. To find the next certificate, the
//  pPrevCertContext is set to the CERT_CONTEXT returned by a previous call.
//
//  NOTE: a NON-NULL pPrevCertContext is always CertFreeCertificateContext'ed by
//  this function, even for an error.
//--------------------------------------------------------------------------

function CertFindCertificateInStore( hCertStore :HCERTSTORE;
                                     dwCertEncodingType, dwFindFlags,
                                     dwFindType : DWORD;
                               const pvFindPara;
                                     pPrevCertContext: PCERT_CONTEXT = nil
                                    ): PCERT_CONTEXT ; stdcall;



ну и вызов первого поиска тогда будет вот таким:
Код: pascal
1.
CertFindCertificateInStore( FStore, CRYPT_ENCODING, 0, CERT_FIND_HASH, Blob );
...
Рейтинг: 0 / 0
Как сделать цифровую подпись на основе сертификата
    #37637028
exsander
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Добрый день!

С поиском я разобрался, сертификат находится, подписывает и шифрует файл. Непонятен остался один момент. При подписи файла, перед текстом сообщения и после него добавляется информация. При помощи утилиты cryptcp (КриптоПро-шная утилита командной строки) пытаюсь удалить подпись из сообщения. То что находится после текста, т.е. сама подпись удаляется, а вот то, что добавилось перед текстом - остается.
это подписываемый текст

Код: pascal
1.
2.
3.
 Сорри несколько за глупый вопрос. Просто проект нужно сдать в понедельник. Время поджимает и реально не успеваю.
Что нужно:на основе сертификата (выбирается вручную из установленных) подписать файл цифровой подписью, а потом
проверить эту самую подпись. Стало быть как сделать? Если кто-нибудь кинет рабочим примером на Дельфи, буду очень благодарен.


Это уже подписанный текст

Код: pascal
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.
0'	*┼H┼ч
 '0'10
*:	
 'd'`Сорри несколько за глупый вопрос. Просто проект нужно сдать в понедельник. Время поджимает и реально не успеваю.
Что нужно:на основе сертификата (выбирается вручную из установленных) подписать файл цифровой подписью, а потом
проверить эту самую подпись. Стало быть как сделать? Если кто-нибудь кинет рабочим примером на Дельфи, буду очень благодарен.1'v0'r0_Є0_>10	*┼H┼ч
	test-uc@tii.ru10	URU10
Umoscow10
Umoscow10U

Integrator IT10USecurity of documents10U
Testing CA
}О_
*:	
	1	*┼H┼ч
0	*┼H┼ч
	1
120129100105Z0/	*┼H┼ч
	1" UBiЙ-_РЪFzй)Х:о<sы&#9488;JН_у&#9488;D8лD0_ш*&#9532;H&#9532;ч
	/1_и0_е0_в0_Я0*:	 2Д-NУЬ![<&#9488;__biiЇ2XПpц_c~HЦы0_°0_Ў¤__0_>10	*&#9532;H&#9532;ч
	test-uc@tii.ru10	URU10
Umoscow10
Umoscow10U

Integrator IT10USecurity of documents10U
Testing CA
}О_
*:
р-є
р-є
р-є



а это текст после удаления подписи при помощи cryptcp

Код: pascal
1.
2.
3.
4.
5.
6.
0'_	*&#9532;H&#9532;ч
 '_0'_10
*:	
 'd'`Сорри несколько за глупый вопрос. Просто проект нужно сдать в понедельник. Время поджимает и реально не успеваю.
Что нужно:на основе сертификата (выбирается вручную из установленных) подписать файл цифровой подписью, а потом
проверить эту самую подпись. Стало быть как сделать? Если кто-нибудь кинет рабочим примером на Дельфи, буду очень благодарен.1



Что это за инфа в начале текста, и если это часть подписи почему она не удалилась? Заранее спасибо.
...
Рейтинг: 0 / 0
Как сделать цифровую подпись на основе сертификата
    #37637259
exsander
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Вопрос снят, ответ нашелся здесь: http://citforum.ru/security/articles/defense/
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
Как сделать цифровую подпись на основе сертификата
    #38861312
SereZa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
в теме встретился кусочек кода:
Store := CertOpenStore( CERT_STORE_PROV_PKCS7, MY_ENCODING_TYPE, 0, 0, @Blob );
я так понимаю что это работает только в случае если не было пароля. а если есть пароль на сертификате - коим образом его указать? это должна быть другая команда для чтения такого сертификата?
...
Рейтинг: 0 / 0
Как сделать цифровую подпись на основе сертификата
    #38861348
Antoshka
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SereZaв теме встретился кусочек кода:
Store := CertOpenStore( CERT_STORE_PROV_PKCS7, MY_ENCODING_TYPE, 0, 0, @Blob );
я так понимаю что это работает только в случае если не было пароля. а если есть пароль на сертификате - коим образом его указать? это должна быть другая команда для чтения такого сертификата?
На сертификате пароля не бывает. Вы про PFX или про eToken?
...
Рейтинг: 0 / 0
Как сделать цифровую подпись на основе сертификата
    #38862071
SereZa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
наверное про PFX... только PFXImportCertStore не хочет работать, пишет что не правильный алгоритм. PFXIsPFXBlob и PFXVerifyPassword замечательно работают. а вот PFXImportCertStore нет. и сам этот сертификат стандартным виндосовским мастером регистрации не устанавливается. в самом конце выдает ошибку про поставщика криптографии. здесь на форуме писали что нужен CSP - только на том сайте java апплет читает этот сертификат и регистрирует его в системе. никакой дополнительной программы при этом не устанавливается.
...
Рейтинг: 0 / 0
Как сделать цифровую подпись на основе сертификата
    #38862080
Antoshka
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
На каком "том сайте"? Вангую, что в сертификате у вас ГОСТовский ключ, который не распознаётся системой без установки соответствующего криптопровайдера, умеющего работать с алгоритмами ГОСТ. Откуда у вас вообще появился данный сертификат в PFX?
...
Рейтинг: 0 / 0
Как сделать цифровую подпись на основе сертификата
    #38862102
SereZa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
никакой установки криптопровайдера не происходит. все делает java апплет. он может выполнять функции подобного криптопровайдера? своеобразный портэйбл-CSP? такой сертификат выдает налоговая. для своего сайта для отправки налоговой отчетности. задумка была сделать программу, которая бы могла проверять сроки действия и читать имя в подобных сертификатах на жестком диске.


и второй момент, не совсем по теме - но рядом. существует некоторые интернет банкинки, которые как раз используют подобные CSP - там целая программа, что должна быть установлена, висит в процессах, работает как сервис. как можно объяснить браузеру чтоб он запустился без использования этого CSP? режим инкогнито хрома вроде как запускается без него... но проблема в том, что он не запоминает какой сертификат был выбран и опять выкидывает окно выбора сертификата при входе и зацикливается. (имелось в виду окошко с выбором уже установленных в системе сертификатов). как бы так хитро запустить браузер, чтоб и запоминал что выбрано и чтоб без использования CSP? принудительная остановка службы этого криптопровайдера не помогает. только если удалить полностью программы. а вот как бы без удаления...
...
Рейтинг: 0 / 0
Как сделать цифровую подпись на основе сертификата
    #38862107
sql2012
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
AntoshkaНа каком "том сайте"? Вангую, что в сертификате у вас ГОСТовский ключ, который не распознаётся системой без установки соответствующего криптопровайдера, умеющего работать с алгоритмами ГОСТ. Откуда у вас вообще появился данный сертификат в PFX?

Похоже SereZa Delphi и CryptoAPI ]не читает ответы на свои вопросы.
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
Как сделать цифровую подпись на основе сертификата
    #39602196
Shuraken
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Хорошая тема, помогла найти многие ответы на вопросы, но кое-что мне непонятно.

Код: pascal
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.
unit JwaWinCrypt;
...
function CryptSignMessage( var pSignPara : CRYPT_SIGN_MESSAGE_PARA;
                           fDetachedSignature : BOOL;
                           cToBeSigned :DWORD;
                     const rgpbToBeSigned : PByteArray;
                           rgcbToBeSigned : PDWordArray;
                           pbSignedBlob : PBYTE;
                           var pcbSignedBlob : DWORD ) : BOOL; stdcall;
....

unit Main;

uses jwaWinScrypt...

// обрабатываем ошибки
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 ] );
  frmSignatureFromCertificate.mDestination.Lines.Text := msg;
  Raise Exception.Create( sError );
end;

// подписываем содержимое одного Memo-поля, выводим в другое Memo поле
procedure TfrmSignatureFromCertificate.acSignFileExecute(Sender: TObject);
const
  CERT_STORE_NAME = 'MY';
  MY_ENCODING_TYPE = PKCS_7_ASN_ENCODING or X509_ASN_ENCODING;
  SignerName : WideString = 'Shuraken';
var
  pSignerCert: PCCERT_CONTEXT;
  hCertStoreHandle: HCERTSTORE;
  SigParams: CRYPT_SIGN_MESSAGE_PARA;
  pStreamIn, pStreamOut: TMemoryStream;
  MessageArray : TByteArray;
  MessageSize : TDWordArray;
  MessageCert : TPCCertContextArray;
  cbSignedMessageBlob: DWORD;
  SignName: WideString;
begin
  mDestination.Clear;
  hCertStoreHandle := CertOpenSystemStore( 0, PChar( CERT_STORE_NAME ));
  if ( not assigned( hCertStoreHandle )) then
    Err( Format( 'Ошибка при открытии хранилища: %s', [ CERT_STORE_NAME ] ));
  try
    SignName := Trim(cmbCertificates.Text);
    pSignerCert := CertFindCertificateInStore( hCertStoreHandle, MY_ENCODING_TYPE, 0, CERT_FIND_SUBJECT_STR, PWideChar( SignName ), nil );
    try
      if ( not assigned( pSignerCert )) then
        Err( Format( 'Сертификат %s не найден', [ SignName ] ));
      pStreamIn := TMemoryStream.Create;
      pStreamOut := TMemoryStream.Create;
      try
        mSource.Lines.SaveToStream(pStreamIn);
        GetMem( MessageArray, 1 * SizeOf( PByte ));
        GetMem( MessageSize, 1 * SizeOf( DWORD ));
        GetMem( MessageCert, 1 * SizeOf( PPCCERT_CONTEXT ));
        MessageArray[ 0 ] := pStreamIn.Memory;
        MessageSize[ 0 ] := pStreamIn.Size;
        MessageCert[ 0 ] := 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 := Pointer( MessageCert );
        if ( not ( CryptSignMessage( SigParams, false, 1, Pointer( MessageArray ), Pointer( MessageSize ), nil, cbSignedMessageBlob ))) then
          Err( 'Размер буфера' );
        pStreamOut.Size := cbSignedMessageBlob;
        if not ( CryptSignMessage( SigParams, false, 1, Pointer( MessageArray ), Pointer( MessageSize ), pStreamOut.Memory, cbSignedMessageBlob )) then
          Err( 'Файл не подписан' );
        pStreamOut.Size := cbSignedMessageBlob;

        mDestination.Lines.LoadFromStream(pStreamOut);
      finally
        FreeAndNil( pStreamIn );
        FreeAndNil( pStreamOut );
      end;
    finally
      CertFreeCertificateContext(pSignerCert);
    end;
  finally
    CertCloseStore( hCertStoreHandle, CERT_CLOSE_STORE_CHECK_FLAG );
  end;
end;

// выводим список личных сертификатов
procedure TfrmSignatureFromCertificate.FormShow(Sender: TObject);
var
  hProv       : HCRYPTPROV;
  hStoreHandle: hcertstore;
  pSignerCert : PCCERT_CONTEXT;
  pCertContext: PCCERT_CONTEXT;
  len: integer;
  CertName: PByte;

function CertNameToWideString: WideString;
begin
  if (len = 0) then
  begin
    Result := '';
    Exit;
  end;

  SetLength(Result, len div 2);
  System.Move(CertName^, Pointer(Result)^, len);
  len := Length(Result);
  if (Result[len] = #0) then
  begin
    Dec(len);
    SetLength(Result, len);
  end;
end;

begin

  if not CryptAcquireContext(hProv, nil, nil, PROV_RSA_SIG, CRYPT_VERIFYCONTEXT) then
    exit;

  hStoreHandle := CertOpenSystemStore(hProv, 'MY');
  if (hStoreHandle = nil) then
  begin
    Err('ErrorOpenStore');
    exit;
  end;

  pCertContext := nil;
  repeat
    pCertContext := CertEnumCertificatesInStore(hStoreHandle, pCertContext);
    if (pCertContext <> nil) then
    begin
      len := CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, nil, nil, 0);
      if len > 0 then
      begin
        len := len*2;
        GetMem(CertName, len);
        CertGetNameStringW(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, nil, PWideChar(CertName), len);
        cmbCertificates.Items.Add(CertNameToWideString);
        FreeMem(CertName);
        CertName := nil;
      end;
    end;
  until (pCertContext = nil);
  cmbCertificates.ItemIndex := 0;
end;



Какой-то код взят из этой темы, какой-то из других источников, и вот что интересно. У меня на компьютере установлено 5 различных сертификатов. Когда я пытаюсь подписать содержимое memo-поля сертификатом, у которого нет закрытого ключа, то выдаётся ошибка "0х8009200В Не удаётся найти сертификат и закрытый ключ для расшифровки". Делая то же самое сертификатом с закрытым ключом, получаю нормальный результат. Вопрос: почему не удаётся подписать содержимое сертификатом без закрытого ключа.
...
Рейтинг: 0 / 0
Как сделать цифровую подпись на основе сертификата
    #39604755
Shuraken
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Подниму тему. Можно ли вообще подписывать что-либо сертификатом без закрытого ключа?
...
Рейтинг: 0 / 0
Как сделать цифровую подпись на основе сертификата
    #39605510
__Avenger__
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ShurakenПодниму тему. Можно ли вообще подписывать что-либо сертификатом без закрытого ключа?

Нет. Подпись только закрытым ключом. Шифровать можно на открытом ключе.
...
Рейтинг: 0 / 0
Как сделать цифровую подпись на основе сертификата
    #39699762
alexer81
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
спасибо большое за код!
добавлю при подписи удобнее выбрать сертификат из установленных:
pSignerCert :=CryptUIDlgSelectCertificateFromStore(hCertStoreHandle, self.Handle,'','',0,0,nil);
и вставил (не знаю правильно ли)CryptAcquireCertificatePrivateKey(pSignerCert,CRYPT_ACQUIRE_CACHE_FLAG,nil,prov,@pdwKeySpec,@pfCallerFreeProv)
перед CryptSignMessage(..) чтобы пароль два раза от контейнера не вводить

А остался у меня такой вопрос - CryptVerifyMessageSignature возвращает исходные данные и сертификат которым подписано, а как достать "Время подписания (1.2.840.113549.1.9.16.2.47 )" через CryptoAPi?
...
Рейтинг: 0 / 0
Как сделать цифровую подпись на основе сертификата
    #39699911
sql2012
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alexer81спасибо большое за код!
добавлю при подписи удобнее выбрать сертификат из установленных:
pSignerCert :=CryptUIDlgSelectCertificateFromStore(hCertStoreHandle, self.Handle,'','',0,0,nil);
и вставил (не знаю правильно ли)CryptAcquireCertificatePrivateKey(pSignerCert,CRYPT_ACQUIRE_CACHE_FLAG,nil,prov,@pdwKeySpec,@pfCallerFreeProv)
перед CryptSignMessage(..) чтобы пароль два раза от контейнера не вводить

А остался у меня такой вопрос - CryptVerifyMessageSignature возвращает исходные данные и сертификат которым подписано, а как достать "Время подписания (1.2.840.113549.1.9.16.2.47 )" через CryptoAPi?


CryptUIDlgSelectCertificateFromStore - не особо будет удобен, когда есть сертификаты с одинаковым CN и т.п.
(разные УЦ\разные SN, G- ФИО, которые ОС не покажет в этом списке) + эта функция может "тормозить", не использую её...
...
Рейтинг: 0 / 0
Как сделать цифровую подпись на основе сертификата
    #39699913
sql2012
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
поэтому - можно своё что-то изобразить всегда, если захочется, см. снимок выше.
...
Рейтинг: 0 / 0
Как сделать цифровую подпись на основе сертификата
    #39699916
sql2012
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alexer81,

Добавление атрибута даты в ЭЦП
https://qa-help.ru/questions/dobavlenie-atributa-daty-v-ecp
...
Рейтинг: 0 / 0
Как сделать цифровую подпись на основе сертификата
    #39699918
sql2012
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
  ca: array[0..10] of CRYPT_ATTRIBUTE;  // перечень подписываемых атрибутов: дата\время, комментарий, использование, csp и т.д.
  FTime: TFileTime;
  cablob: CRYPT_ATTR_BLOB;
  pbAuth : PByte;
...

 ///////////////////////////////////////////////////////////////////////////////////////////
  FTime := DateTimeToFileTime(DTSign);
  CryptEncodeObject(MY_ENCODING_TYPE, szOID_RSA_signingTime, @FTime, nil, cbAuth);
  GetMem(pbAuth, cbAuth);  
  CryptEncodeObject(MY_ENCODING_TYPE, szOID_RSA_signingTime, @FTime, pbAuth, cbAuth); 
  cablob.cbData := cbAuth;
  cablob.pbData := pbAuth;
  ///////////////////////////////////////////////////////////////////////////////////////////
  ca[0].pszObjId := szOID_RSA_signingTime; // дата и время
  ca[0].cValue := 1;
  ca[0].rgValue := @cablob;
  /////////////////////////////////////////////////////////////////////////////////////////////////////////////
  
 // ca[1] .. 9 - другие атрибуты при необходимости
...

  SignerEncodeInfo.rgAuthAttr := @ca; 
    SignerEncodeInfo.cAuthAttr :=1 ; // если использовать только дату\время из ca[]
...
Рейтинг: 0 / 0
Как сделать цифровую подпись на основе сертификата
    #39700283
alexer81
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
sql2012, спасибо за ответы! ваша информация пригодится.
Но в подписанном файле есть уже время подписания и потому мой вопрос:
автор- CryptVerifyMessageSignature возвращает исходные данные и сертификат которым подписано, а как достать "Время подписания (1.2.840.113549.1.9.16.2.47 )" через CryptoAPi?
...
Рейтинг: 0 / 0
Как сделать цифровую подпись на основе сертификата
    #39700288
sql2012
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alexer81,


Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
hMsg: HCRYPTMSG;  
  authAttr: PCRYPT_ATTRIBUTES;
  Attr: PCRYPT_ATTRIBUTE;  
ft: FILETIME;

...
CryptMsgGetParam(hMsg, CMSG_SIGNER_AUTH_ATTR_PARAM, signerIndex, nil, authAttr_len)
выделить память размером authAttr_len  для authAttr 
 CryptMsgGetParam(hMsg, CMSG_SIGNER_AUTH_ATTR_PARAM, signerIndex, authAttr, authAttr_len) 
...
 Attr := CertFindAttribute(szOID_RSA_signingTime, authAttr.cAttr, authAttr.rgAttr);

 dwSize := SizeOf(ft);
    Win32Check(CryptDecodeObject(MY_ENCODING_TYPE, szOID_RSA_signingTime,
    
  Attr.rgValue.pbData, Attr.rgValue.cbData, 0, @ft, dwSize));
    

DT := DecodeFileTime(ft);



+ добавить проверку вызовов, выделение\освобождение памяти
...
Рейтинг: 0 / 0
Как сделать цифровую подпись на основе сертификата
    #39700484
alexer81
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
спасибо. разобрался.
время конечно в в атрибуте с оид - szOID_RSA_signingTime. я приплёл 1.2.840.113549.1.9.16.2.47, не туда наверно глянул
но почему-то атрибуты сразу через CryptMsgGetParam(..CMSG_SIGNER_AUTH_ATTR_PARAM..) не получилось взять
взял через CryptMsgGetParam(..CMSG_SIGNER_INFO_PARAM..)
в CMSG_SIGNER_INFO.AuthAttrs
...
Рейтинг: 0 / 0
25 сообщений из 128, страница 5 из 6
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Как сделать цифровую подпись на основе сертификата
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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