Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
Топик располагается на нескольких страницах: Ctrl  назад   1 2 3 4 [5]      все
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Fiyanov
Member

Откуда: Казахстан
Сообщений: 27
Ура!

было:
function CryptSignMessage(pSignPara: PCRYPT_SIGN_MESSAGE_PARA;
  fDetachedSignature: BOOL; cToBeSigned: DWORD; rgpbToBeSigned: LPBYTE;
  rgcbToBeSigned: LPDWORD; pbSignedBlob: LPBYTE; var pcbSignedBlob: DWORD): BOOL; stdcall;

стало:
function CryptSignMessage(var pSignPara: CRYPT_SIGN_MESSAGE_PARA;
  fDetachedSignature: BOOL; cToBeSigned: DWORD; rgpbToBeSigned: LPBYTE;
  rgcbToBeSigned: LPDWORD; pbSignedBlob: LPBYTE; var pcbSignedBlob: DWORD): BOOL; stdcall;

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

      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');
22 окт 10, 09:08    [9653996]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Fiyanov
Member

Откуда: Казахстан
Сообщений: 27
Хотя странно... в msdn именно PCRYPT_SIGN_MESSAGE_PARA. Но почему то при:

var
SigParams: CRYPT_SIGN_MESSAGE_PARA;

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

 if CryptSignMessage(@SigParams, ...

Наблюдается как раз мой случай когда после возврата размера прога падает... хотя может дело в ключевом слове var которого в моём заголовочном файле от JEDI не было...
22 окт 10, 09:17    [9654030]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
dv_belyaev
Member

Откуда:
Сообщений: 7
всем привет
в проекте использую шифрование и подпись файлов сертификатами
функции CryptEncryptMessage / CryptDecryptMessage / CryptSignMessage / CryptVerifyMessageSignature

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

     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;
5 июл 11, 16:06    [10926136]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
A-n-d-r-e-y
Member

Откуда:
Сообщений: 53
Откажись от высокоуровневых функций: CryptVerifyMessageSignature и т.п.
5 июл 11, 19:56    [10927764]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
exsander
Member

Откуда:
Сообщений: 8
Здравствуйте!
Пытаюсь найти установленный в системе тестовый сертификат от КриптоПро. За основу взят код из первых сообщений данной темы
При поиске по отпечатку сертификат не найден, GetLastError возвращает ошибку 0x80092004 Объект или свойство не найдено
+

...
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;



Хочется понять что делается мной не так? Заранее спасибо.
8 янв 12, 14:27    [11870109]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Кто-то уже как бэ
Guest
Здравствуйте, я даже задумываться не хочу, что именно делает вот этот говнокод:
exsander
0x80092004 Объект или свойство не найдено
+

  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? На глаз я больше особых проблем не вижу. В моих поделках эта функция объявлена вот так, сравнивайте со своим:
+
//+-------------------------------------------------------------------------
//  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;


ну и вызов первого поиска тогда будет вот таким:
CertFindCertificateInStore( FStore, CRYPT_ENCODING, 0, CERT_FIND_HASH, Blob );
9 янв 12, 07:45    [11872757]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
exsander
Member

Откуда:
Сообщений: 8
Добрый день!

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

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

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

0'	*┼H┼ч
 '0'10
*:	
 '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лD0_ш*&#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
+

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


Что это за инфа в начале текста, и если это часть подписи почему она не удалилась? Заранее спасибо.
29 янв 12, 13:12    [11991185]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
exsander
Member

Откуда:
Сообщений: 8
Вопрос снят, ответ нашелся здесь: http://citforum.ru/security/articles/defense/
29 янв 12, 18:02    [11992167]     Ответить | Цитировать Сообщить модератору
Между сообщениями интервал более 1 года.
 Re: Как сделать цифровую подпись на основе сертификата  [new]
SereZa
Member

Откуда:
Сообщений: 21
в теме встретился кусочек кода:
Store := CertOpenStore( CERT_STORE_PROV_PKCS7, MY_ENCODING_TYPE, 0, 0, @Blob );
я так понимаю что это работает только в случае если не было пароля. а если есть пароль на сертификате - коим образом его указать? это должна быть другая команда для чтения такого сертификата?
23 янв 15, 05:05    [17157318]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Antoshka
Member

Откуда:
Сообщений: 828
SereZa
в теме встретился кусочек кода:
Store := CertOpenStore( CERT_STORE_PROV_PKCS7, MY_ENCODING_TYPE, 0, 0, @Blob );
я так понимаю что это работает только в случае если не было пароля. а если есть пароль на сертификате - коим образом его указать? это должна быть другая команда для чтения такого сертификата?

На сертификате пароля не бывает. Вы про PFX или про eToken?
23 янв 15, 08:37    [17157473]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
SereZa
Member

Откуда:
Сообщений: 21
наверное про PFX... только PFXImportCertStore не хочет работать, пишет что не правильный алгоритм. PFXIsPFXBlob и PFXVerifyPassword замечательно работают. а вот PFXImportCertStore нет. и сам этот сертификат стандартным виндосовским мастером регистрации не устанавливается. в самом конце выдает ошибку про поставщика криптографии. здесь на форуме писали что нужен CSP - только на том сайте java апплет читает этот сертификат и регистрирует его в системе. никакой дополнительной программы при этом не устанавливается.
23 янв 15, 19:46    [17161885]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Antoshka
Member

Откуда:
Сообщений: 828
На каком "том сайте"? Вангую, что в сертификате у вас ГОСТовский ключ, который не распознаётся системой без установки соответствующего криптопровайдера, умеющего работать с алгоритмами ГОСТ. Откуда у вас вообще появился данный сертификат в PFX?
23 янв 15, 20:32    [17162005]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
SereZa
Member

Откуда:
Сообщений: 21
никакой установки криптопровайдера не происходит. все делает java апплет. он может выполнять функции подобного криптопровайдера? своеобразный портэйбл-CSP? такой сертификат выдает налоговая. для своего сайта для отправки налоговой отчетности. задумка была сделать программу, которая бы могла проверять сроки действия и читать имя в подобных сертификатах на жестком диске.


и второй момент, не совсем по теме - но рядом. существует некоторые интернет банкинки, которые как раз используют подобные CSP - там целая программа, что должна быть установлена, висит в процессах, работает как сервис. как можно объяснить браузеру чтоб он запустился без использования этого CSP? режим инкогнито хрома вроде как запускается без него... но проблема в том, что он не запоминает какой сертификат был выбран и опять выкидывает окно выбора сертификата при входе и зацикливается. (имелось в виду окошко с выбором уже установленных в системе сертификатов). как бы так хитро запустить браузер, чтоб и запоминал что выбрано и чтоб без использования CSP? принудительная остановка службы этого криптопровайдера не помогает. только если удалить полностью программы. а вот как бы без удаления...
23 янв 15, 21:51    [17162327]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
sql2012
Member

Откуда: РФ
Сообщений: 624
Antoshka
На каком "том сайте"? Вангую, что в сертификате у вас ГОСТовский ключ, который не распознаётся системой без установки соответствующего криптопровайдера, умеющего работать с алгоритмами ГОСТ. Откуда у вас вообще появился данный сертификат в PFX?


Похоже SereZa Delphi и CryptoAPI]не читает ответы[/url] на свои вопросы.
23 янв 15, 22:02    [17162379]     Ответить | Цитировать Сообщить модератору
Между сообщениями интервал более 1 года.
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Shuraken
Member

Откуда:
Сообщений: 582
Хорошая тема, помогла найти многие ответы на вопросы, но кое-что мне непонятно.

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В Не удаётся найти сертификат и закрытый ключ для расшифровки". Делая то же самое сертификатом с закрытым ключом, получаю нормальный результат. Вопрос: почему не удаётся подписать содержимое сертификатом без закрытого ключа.
15 фев 18, 10:55    [21193157]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Shuraken
Member

Откуда:
Сообщений: 582
Подниму тему. Можно ли вообще подписывать что-либо сертификатом без закрытого ключа?
20 фев 18, 13:02    [21204636]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
__Avenger__
Member

Откуда:
Сообщений: 1971
Shuraken
Подниму тему. Можно ли вообще подписывать что-либо сертификатом без закрытого ключа?


Нет. Подпись только закрытым ключом. Шифровать можно на открытом ключе.
21 фев 18, 13:51    [21207977]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
alexer81
Member

Откуда:
Сообщений: 42
спасибо большое за код!
добавлю при подписи удобнее выбрать сертификат из установленных:
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?
7 сен 18, 16:19    [21668358]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
sql2012
Member

Откуда: РФ
Сообщений: 624
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- ФИО, которые ОС не покажет в этом списке) + эта функция может "тормозить", не использую её...

К сообщению приложен файл. Размер - 72Kb
8 сен 18, 12:30    [21668843]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
sql2012
Member

Откуда: РФ
Сообщений: 624
поэтому - можно своё что-то изобразить всегда, если захочется, см. снимок выше.
8 сен 18, 12:31    [21668845]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
sql2012
Member

Откуда: РФ
Сообщений: 624
alexer81,

Добавление атрибута даты в ЭЦП
https://qa-help.ru/questions/dobavlenie-atributa-daty-v-ecp
8 сен 18, 12:36    [21668848]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
sql2012
Member

Откуда: РФ
Сообщений: 624
  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[]
8 сен 18, 12:47    [21668853]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
alexer81
Member

Откуда:
Сообщений: 42
sql2012, спасибо за ответы! ваша информация пригодится.
Но в подписанном файле есть уже время подписания и потому мой вопрос:
автор
- CryptVerifyMessageSignature возвращает исходные данные и сертификат которым подписано, а как достать "Время подписания (1.2.840.113549.1.9.16.2.47 )" через CryptoAPi?
10 сен 18, 10:34    [21669603]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
sql2012
Member

Откуда: РФ
Сообщений: 624
alexer81,


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);


+ добавить проверку вызовов, выделение\освобождение памяти
10 сен 18, 10:44    [21669614]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
alexer81
Member

Откуда:
Сообщений: 42
спасибо. разобрался.
время конечно в в атрибуте с оид - 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
10 сен 18, 15:50    [21669975]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: Ctrl  назад   1 2 3 4 [5]      все
Все форумы / Delphi Ответить