1

Тема: Использование метода выполнения ЭЦП блока памяти

Добрый день.
Возникла такая ситуация. в программе используется библиотека компонентов VCERTCOM, в частности метод выполнения ЭЦП блока памяти (SignMem).   при вызове используются совместно флаги Flag_Sign_Pkcs7 or Flag_Sign_Detached (то есть в результате должна быть отсоединенная ЭЦП). при отладке в переменной ЭЦП кроме самой ЭЦП явно присутствует подписываемый блок памяти(среди символов, относящихся к ЭЦП видна строка, ЭЦП которой выполнялась). В tmpStrm присутствует кроме ЭЦП текст потока Value. Не подскажите в чем ошибка?

procedure SignStreamToStream(Value,SignStream: TStream);
var data,signin,signout : OleVariant;
   singparam   : ISignParam;
    err         : WideString;
    tmpStrm     : TStringStream;
begin
  try
    try
      StreamToVariant(data,Value);                                    // преобразование потока в OleVariant
      singparam := CoSignParam.Create;
      singparam.flag := Flag_Sign_Pkcs7 or Flag_Sign_Detached;
      singparam.MyCert:=ICertId(IDispatch(Unassigned));
      signin:=Unassigned;
      FCrypt.SignMem(singparam,data,signin,signout);       // непосредственно выполнение ЭЦП
      tmpStrm:= TStringStream.Create;
      VariantToStream(signout,tmpStrm);                  // преобразование OleVariant в поток(для дальнейшей работы с ЭЦП)
      tmpStrm.Position:=0;
      EncodeStream(tmpStrm,SignStream);     
except
      on E: EOleException do
      begin
        FCrypt.GetPKIErrorText(E.ErrorCode,err);
        AddMsgInLog('При подписывании документа произошла ошибка( '+err+' )');
      end;
    end;
  finally
    tmpStrm.Free;
    signin:=null;
    data:=null;
    signout:=null;
    singparam:=nil;
  end;
end;

2

Re: Использование метода выполнения ЭЦП блока памяти

Добрый день!

Попробуйте строчку

singparam.flag := Flag_Sign_Pkcs7 or Flag_Sign_Detached;

заменить на

singparam.flag := 3;
// Flag_Sign_Pkcs7 = 1
// Flag_Sign_Detached = 2

3

Re: Использование метода выполнения ЭЦП блока памяти

Пробовал  - результат тот же самый.

Попробую объяснить подробнее свою проблему. Разработка ведется в Delphi. Создан отдельный класс TValidataCrypto отвечающий за всю криптографию(хэш, подписывание данных, шифрование- расшифровка). В этом классе  присутствует объект для вызова функций библиотеки(FCrypt). 
Объект класса создается при запуске приложения и в дальнейшем передается нескольким потокам(TThread) как входящий параметр(в связи с этим добавил в код класса критические секции что бы потоки не могли вызвать одновременно одну и ту же функцию функцию или обратиться к объекту FCrypt). В итоге при отладке вызывается функция подписывания блока памяти(точнее TStream) . Входящее значение проверил - нормальное. после чего данные "загоняются" в переменную "data"(OleVariant, ее под отладкой переводил обратно в поток - данные совпадали, то есть тут тоже вроде бы все нормально). Далее вызывается функция FCrypt.SignMem(singparam, data, signin, signout) которая в переменной "signout" должна сформировать только подпись данных(т.к. указан флаг Flag_Sign_Detached) . После преобразования переменной "signout"(OleVariant) в TStream в переменной присутствуют обычные, для еще не преобразованного потока, "кракозябры" среди которых явно присутствует подписываемый текст(пример в конце соообщения).
Инициализация объекта работы с Валидатой происходит при создании экземпляра класса а деинициализация при разрушении экземпляра класса.

TValidataCrypto = Class
private
..
  FCrypt     : VCERT;                // объект работы с криптозащитой
...
end;



TValidataCrypto.Initialize;
begin
...
CoInitialize(nil) ;
FCrypt := CoVCERT.Create;
FCrypt.Initialize(...);
...
end;

destructor TValidataCrypto.Destroy;
begin
  FCrypt.Uninitialize;
  CoUninitialize;
end;


Результат выполнения функции SignMem

'0‚'#4'c'#6#9'*†H†ч'#$D#1#7#2' ‚'#4'T0‚'#4'P'#2#1#1'1'#$C'0'#$A#6#6'*…'#3#2#2#9#5#0'0‚'#2'‹'#6#9'*†H†ч'#$D#1#7#1' ‚'#2'|'#4'‚'#2'x ПОДПИСЫВАЕМЫЕ ДАННЫЕ ПОЛНОСТЬЮ 1‚'#1'¬0‚'#1'Ё'#2#1#1'0ЃЭ0ЃИ1'#$B'0'#9#6#3'U'#4#6#$13#2'RU1'#$1B'0'#$19#6#3'U'#4#8#$C#$12'77 Рі.РњРѕСЃРєРІР°1'...

4

Re: Использование метода выполнения ЭЦП блока памяти

Напишите, пожалуйста, какой провайдер и справочник Вы используете, а также номер версии.

5

Re: Использование метода выполнения ЭЦП блока памяти

СКЗИ "Валидата CSP" - v.4.0.267.11(64bit)
Справочник сертификатов (XCS)  v.4.0.268.01(64bit)  +  v.4.0.268.01(32bit)

6 (2013-09-05 13:08:27 отредактировано Alexey_)

Re: Использование метода выполнения ЭЦП блока памяти

для проверки сделал тестовый примерчик. в процедуре строка сначала подписывается а затем сразу же проверяется ее ЭЦП. в результате проверки в массиве есть одна запись(значит строка подписана одной подписью) но статус 0(так понимаю ошибка подписи?).

var
  Crypt : VCERT;
  data, signin, signout,veriresults : OleVariant ;
  text : string;
  singparam : ISignParam;
  verifyparam : IVerifyParam;
  sig : ISignStatus;
  err : WideString; 
  streamin, streamout : TStringStream;
  i, HighBound : Integer;
begin
   // подписываем строку
   data := BytesOf(text);
   Crypt.Initialize('Тестовый',64);
   singparam := CoSignParam.Create;
   singparam.flag := Flag_Sign_Pkcs7 or Flag_Sign_Detached;
   Crypt.SignMem(singparam,data,signin,signout);
   streamin := TStringStream.Create;
   VariantToStream(signout,streamin);
   streamout := TStringStream.Create;
   streamin.Position :=0;
   EncodeStream(streamin,streamout);
   mmSign.Lines.Text := streamout.DataString;
   streamin.Free;
   streamout.Free;
   // проверяем полученную подпись
   verifyparam := CoVerifyParam.Create;
   verifyparam.flag := Flag_Sign_Pkcs7 or Flag_Sign_Detached;
   signin:=signout;             // ЭП блока памяти с текстом
   signout:=Unassigned;
   Crypt.VerifyMem(verifyparam,data,signin,signout,veriresults);
   mmSign.Lines.Add('');
   if VarIsArray(veriresults) then
   begin
     i:=VarArrayLowBound(veriresults, 1);
     HighBound:=VarArrayHighBound(veriresults, 1);
     while i<= HighBound do
     begin
       sig := ISignStatus(IDispatch(veriresults[i]));
       mmSign.Lines.Add('Verify status:'+ IntToStr(sig.status));
       mmSign.Lines.Add('Cert:'+string(sig.cert.serialNumber));
       inc(i);
     end;
   end;
  Crypt.Uninitialize;
  CoUninitialize;
end;

7

Re: Использование метода выполнения ЭЦП блока памяти

Статус 0 означает, что подпись верна (статус равен коду ошибки).

Можно еще попробовать подписать файл и сравнить результаты.

8

Re: Использование метода выполнения ЭЦП блока памяти

то есть если данные в блоке памяти и файле совпадают то и их подписи будут совпадать?при подписывании файла учитывается ли расположение файла? просто при вызове процедуры подписывания строки (блока памяти) последовательно несколько раз каждый раз подпись получается немного разной(в основном меняется последняя четверть подписи, первая часть остается неизменной всегда).

9

Re: Использование метода выполнения ЭЦП блока памяти

Подписи будут разные. Нужно посмотреть, останутся ли в выходном файле подписываемые данные.

Еще можно попробовать подписать блок данных с флагом Flag_Sign_Detached и без этого флага и сравнить размеры подписей.

10

Re: Использование метода выполнения ЭЦП блока памяти

При использовании SignFile в выходном файле подписываемые данные так же присутствуют. при удалении флага Flag_Sign_Detached размер подписи стал меньше но в ней так же присутствует подписываемый текст.
При использовании SignMem при удалении флага Flag_Sign_Detached подпись увеличивается незначительно(в районе 10 символов при общей длине в 1500 символов)

11

Re: Использование метода выполнения ЭЦП блока памяти

Пришлите, пожалуйста, исходный файл и файлы с подписями (полученные с флагом Flag_Sign_Detached и без него).

12

Re: Использование метода выполнения ЭЦП блока памяти

Проблема решена. В потоке не вызывалась процедура Synchronize.
Тема закрыта.