Использование API функции SignFile, электронная подпись файла

Автор z-arthur, 18.09.09, 08:28:43

« назад - далее »

0 Пользователи и 1 гость просматривают эту тему.

z-arthur

Здравствуйте!
Необходимо программно подписать документ объекта. У меня вопрос: подписывается сам файл документа или его контрольная сумма?
Спасибо!

AI


z-arthur

AI
Можете прояснить, как сам Лоцман формирует электронную подпись файла (из меню Инструменты)?
По-моему он делает это следующим образом:
1. После выбора сертификата, файл извлекается из базы данных во временную папку.
2. Создается подпись содержимого файла с помощью CryptoAPI функции CryptSignMessage и алгоритма хеширования sha-1.
3. Собственно подписывается файл с помощью API функции SignFile, во второй параметр которого передается подпись в виде массива байт.
Пробую создавать по этому алгоритму с помощью функций CryptoAPI. Но формируемая подпись совсем не совпадает с подписью, создаваемой Лоцманом.

z-arthur

Кому интересно, вот код:

uses
  wcrypt2;

procedure menu_SignFiles(ParentHandle, ClientHandle: THandle;
  RunMethod: TRunMethod; PDMVersion: TVersion;
  DataBaseName, stCheckOut: string; inIdLink: integer); stdcall; export;
const
  CERT_STORE_NAME  = 'MY';
  MY_ENCODING_TYPE = PKCS_7_ASN_ENCODING or X509_ASN_ENCODING;
  SignerName: WideString = 'SignerName';
var
  hCertStoreHandle: HCERTSTORE;
  MessageArray: TByteArray;
  MessageSize: TDWordArray;
  MessageCert: TPCCertContextArray;
  pSignerCert: PCCERT_CONTEXT;
  SigParams: CRYPT_SIGN_MESSAGE_PARA;
  pStreamOut,
  pStreamIn: TMemoryStream;
  cbSignedMessageBlob: DWORD;
  FullFileName: String;
  vaSign: Array of Byte;
  i: Integer;
begin
  AssignRunMethod(RunMethod);
  Application.Handle := ParentHandle;

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

    //------------------------------------------------------------------------
      pSignerCert := CertFindCertificateInStore(hCertStoreHandle,
        MY_ENCODING_TYPE, 0, CERT_FIND_SUBJECT_STR, PWideChar(SignerName), nil);
      if Assigned(pSignerCert) then begin
        pStreamOut := TMemoryStream.Create;
        pStreamIn  := TMemoryStream.Create;
        with TClientDataSet.Create(nil) do
        try
          Data := RunMethod('GetInfoAboutVersion', [PDMVersion.stType,
                            PDMVersion.stProduct, PDMVersion.stVersion, 0, 7]);
          First;
          FullFileName := RunMethod('ExtractFile', [PDMVersion.stType,
                            PDMVersion.stProduct, PDMVersion.stVersion, 0, FieldByName('_NAME').AsString,
                            FieldByName('_LOCALNAME').AsString, $00000000]);
                     
          SetLength(MessageArray, 1);
          SetLength(MessageSize, 1);
          SetLength(MessageCert, 1);

          pStreamIn.LoadFromFile(FullFileName);
          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_SHA1RSA;
          SigParams.cMsgCert          := 1;
          SigParams.rgpMsgCert        := @pSignerCert;
       
          GetMem(pEncodedBlob, SizeOf(PCRYPT_DATA_BLOB));
          if (CryptSignMessage(@SigParams,
                                True,
                                1,
                                Pointer(MessageArray),
                                Pointer(MessageSize),
                                nil,
                                @cbSignedMessageBlob)) then begin
            pStreamOut.Size := cbSignedMessageBlob;
            if (CryptSignMessage(@SigParams,
                                  True,
                                  1,
                                  Pointer(MessageArray),
                                  Pointer(MessageSize),
                                  pStreamOut.Memory,
                                  @cbSignedMessageBlob)) then begin
              for i := 0 to pStreamOut.Size - 1 do begin
                pStreamOut.Read(vaSign, 1);
              end;
              RunMethod('SignFile', [FieldByName('_ID_FILE').AsInteger,
                                      vaSign]);
            end; //if
          end; //if
        finally
          Free;
          FreeAndNil(pStreamIn);
          FreeAndNil(pStreamOut);
        end; //try
      end; //if
    //------------------------------------------------------------------------

  finally
    CertCloseStore(hCertStoreHandle, 0);
  end;
  Application.Handle := 0;
end;



AI

В RunMethod вынесено 4 метода клиента, которые реализуют тот функционал, который есть сейчас в клиенте, показывая те же самые системные диалоговые окна.

'CSignObjectEx', - создание цифровой подписи для объекта по его идентификатору procedure SignObjectEx(inObjectID: integer);

'CVerifySignObject', - проверка подписи объекта по ID procedure VerifySignObject(inObjectID: integer);

'CSignFileEx', - подпись файла
procedure SignFileEx(inFileID: integer; stFileName: String; stFilePath: String;
inVersionID: Longint);

'CVerifySignFile', - проверка подписи файла procedure VerifySignFile(inFileID: integer; stFileName: String; stFilePath:
String; inVersionID: Longint);

inFileID - идентификатор файла
stFileName - соответствует полю _NAME в GetInfoAboutFile stFilePath - соответствует полю _LOCALNAME в GetInfoAboutFile inVersionID - идентификатор объекта, к которому привязан файл

z-arthur

#5
При отладке выскакивает ошибка о том, что приложение вызвало несуществующий метод. Может дело в версии Лоцмана (9-я).
Да и не совсем то это. Процедура подписания файла должна осуществляться фоном.
Например, подписать все файлы объекта. Конечно, теряется смысл подписи, если сам пользователь этого не делает. Но нужна реализация именно данной функции.

Подозреваю, что содержимое файла в подпись не включается.
Буду дальше искать, какой формат подписи в Лоцмане. Может формируется по какому-нибудь ГОСТу.