Статус: Активный участник
Группы: Участники
Зарегистрирован: 20.06.2012(UTC) Сообщений: 30   Откуда: Москва Сказал «Спасибо»: 4 раз Поблагодарили: 4 раз в 2 постах
|
Добрый день! Я решаю задачу создания программы подписания XML документа на Delphi заявления СМЭВ. Подпись должна быть представлена в формате DER в виде отдельного файла. На рабочей станции установлен Crypto PRO CSP 3.6 и КриптоАРМ 4.6 (для проверки подписи вручную). Зарегистрирована библиотека CAPICOM.dll. Я написал следующий код подписания: Код:
// **********************************************cFXML
// Создание цифровой подписи
procedure TMainForm.BitBtn1Click(Sender: TObject);
const
CAPICOM_STORE_OPEN_READ_ONLY = 0;
CAPICOM_CURRENT_USER_STORE = 2;
CAPICOM_ENCODE_ANY = -1;
CAPICOM_ENCODE_BASE64 = 0;
CAPICOM_ENCODE_BINARY = 1;
CAPICOM_CERTIFICATE_INCLUDE_CHAIN_EXCEPT_ROOT = 0; // Saves all certificates in the chain with the exception of the root entity.
CAPICOM_CERTIFICATE_INCLUDE_WHOLE_CHAIN = 1; // Saves the complete certificate chain.
CAPICOM_CERTIFICATE_INCLUDE_END_ENTITY_ONLY = 2; // Saves only the end entity certificate.
var
oStore, oCertificates, oCer, oCer1, oSigner, oSignerData, oSignerUtil: OLEVariant;
filStream: TFileStream;
strStream: TStringStream;
strStream2: TStringStream;
cMesShifr: string;
Buffer: TBytes;
VBuffer: variant;
inputString: string;
dec: TIdDecoderMIME;
begin
// Создать COM-объекты
try
oStore := CreateOleObject('CAPICOM.Store');
oSignerData := CreateOleObject('CAPICOM.SignedData');
oSigner := CreateOleObject('CAPICOM.Signer');
oSignerUtil := CreateOleObject('CAPICOM.Utilities');
oStore.Open(CAPICOM_CURRENT_USER_STORE,'My', CAPICOM_STORE_OPEN_READ_ONLY);
except
on oErr: Exception do
begin
ShowMessage('Для подписи запроса электронно-цифровой подписью необходимо наличие установленного компонента Microsoft CAPICOM на вашей рабочей станции.'+chr(13)+
'Пожалуйста, обратитесь к системному администратору.'+Chr(13)+
Trim(oErr.Message));
exit;
end;
end;
// Записать файл для шифрования в память
try
filStream := TFileStream.Create(EditSignedFile.Text, fmOpenRead);
strStream := TStringStream.Create;
try
filStream.Seek(0, soFromBeginning);
DynArrayToVariant(VBuffer, Pointer(strStream.Bytes), TypeInfo(TBytes));
oSignerData.Content := oSignerUtil.ByteArrayToBinaryString(VBuffer);
ShowMessage('Длина шифруемых данных в байтах: '+IntToStr(Length(oSignerData.Content)));
except
on oErr: Exception do
begin
ShowMessage('Ошибка при записи в SignerData.Content содержимого файла:' + Chr(13) +
'"'+EditSignedFile.Text+'"' + Chr(13) +
Trim(oErr.Message));
Exit;
end;
end;
finally
strStream.Free;
filStream.Free;
end;
// Выбрать сертификат
try
oCertificates := oStore.Certificates;
oCer := oCertificates.Select('Выбор сертификата', 'Пожалуйста, выберите сертификат для подписи.', FALSE);
oCer1 := oCer.Item[1];
oSigner.Certificate := oCer1;
//oSigner.Options := CAPICOM_CERTIFICATE_INCLUDE_CHAIN_EXCEPT_ROOT;
except
on oErr: Exception do
begin
ShowMessage('Сертификат не найден. Пожалуйста, обратитесь к системному администратору.!' + Chr(13) +
Trim(oErr.Message));
Exit;
end;
end;
// Создать подпись
try
cMesShifr := oSignerData.Sign(oSigner, TRUE, CAPICOM_ENCODE_BASE64 );
except
on oErr: Exception do
begin
ShowMessage('Ошибка при подписи документа. Пожалуйста, обратитесь к системному администратору.' + Chr(13) +
Trim(oErr.Message));
Exit;
end;
end;
// Записать подпись в файл
try
filStream := TFileStream.Create(EditSignFile.Text, fmCreate);
dec := TIdDecoderMIME.Create;
strStream2 := TStringStream.Create(dec.DecodeString(cMesShifr));
ShowMessage('Длина подписи в байтах: '+IntToStr(strStream2.Size));
strStream2.Seek(0, soFromBeginning);
filStream.Seek(0, soFromBeginning);
filStream.CopyFrom(strStream2, strStream2.Size);
finally
dec.Free;
strStream.Free;
strStream2.Free;
filStream.Free;
end;
end;
Подписал файл "req_42990fb2-2c12-4c3a-b6f2-5fe4f8a45adc.xml" . Получил файл подписи "req_42990fb2-2c12-4c3a-b6f2-5fe4f8a45adc.xml.sig". При вызове проверки подписи в КриптоАРМе, тот пишет: "Неверный формат данных (0x80070057)".Почему КАПИКОМ выдаёт файл "неверного" формата, который не понимает Крипто-ПРО? Что я делаю не то в программе? Помогите, пожалуйста!--- С уважением Отредактировано пользователем 31 июля 2012 г. 16:48:36(UTC)
| Причина: Не указана Вложение(я):  req_42990fb2-2c12-4c3a-b6f2-5fe4f8a45adc.xml (4kb) загружен 21 раз(а). req_42990fb2-2c12-4c3a-b6f2-5fe4f8a45adc.xml.sig (2kb) загружен 22 раз(а).У Вас нет прав для просмотра или загрузки вложений. Попробуйте зарегистрироваться.
|
|
|
|
Статус: Сотрудник
Группы: Участники
Зарегистрирован: 26.07.2011(UTC) Сообщений: 13,726   Сказал «Спасибо»: 574 раз Поблагодарили: 2303 раз в 1804 постах
|
Для начала - выбросить кодирование\декодирование base64... и работать с входными\выходными данными - без преобразований... Цитата: Почему КАПИКОМ выдаёт файл "неверного" формата, который не понимает Крипто-ПРО?
Цитата:ShowMessage('Длина шифруемых данных в байтах... определись все-таки... сообщаешь пользователю о шифровании... а код "выполняет создание ЭЦП"... Capicom все отлично выдает. Проблема в "твоем" коде ... Цитата:DynArrayToVariant(VBuffer, Pointer(strStream.Bytes), TypeInfo(TBytes));
oSignerData.Content := oSignerUtil.ByteArrayToBinaryString(VBuffer); это мягко сказать... лишнее... Отредактировано пользователем 31 июля 2012 г. 16:46:50(UTC)
| Причина: Не указана |
|
|
|
|
Статус: Активный участник
Группы: Участники
Зарегистрирован: 20.06.2012(UTC) Сообщений: 30   Откуда: Москва Сказал «Спасибо»: 4 раз Поблагодарили: 4 раз в 2 постах
|
Цитата:Для начала - выбросить кодирование\декодирование base64... и работать с входными\выходными данными - без преобразований... ВыбросилЦитата:ShowMessage('Длина шифруемых данных в байтах... ИсправилЦитата:Capicom все отлично выдает. Проблема в "твоем" коде ...
DynArrayToVariant(VBuffer, Pointer(strStream.Bytes), TypeInfo(TBytes));
oSignerData.Content := oSignerUtil.ByteArrayToBinaryString(VBuffer); это мягко сказать... лишнее... УбралКод: // **********************************************cFXML
// Создание цифровой подписи
procedure TMainForm.BitBtn1Click(Sender: TObject);
const
CAPICOM_STORE_OPEN_READ_ONLY = 0;
CAPICOM_CURRENT_USER_STORE = 2;
CAPICOM_ENCODE_ANY = -1;
CAPICOM_ENCODE_BASE64 = 0;
CAPICOM_ENCODE_BINARY = 1;
CAPICOM_CERTIFICATE_INCLUDE_CHAIN_EXCEPT_ROOT = 0; // Saves all certificates in the chain with the exception of the root entity.
CAPICOM_CERTIFICATE_INCLUDE_WHOLE_CHAIN = 1; // Saves the complete certificate chain.
CAPICOM_CERTIFICATE_INCLUDE_END_ENTITY_ONLY = 2; // Saves only the end entity certificate.
var
oStore, oCertificates, oCer, oCer1, oSigner, oSignerData, oSignerUtil: OLEVariant;
strStream: TStringStream;
cMesShifr: string;
Buffer: TBytes;
VBuffer: variant;
inputString: string;
dec: TIdDecoderMIME;
begin
// Создать COM-объекты
try
oStore := CreateOleObject('CAPICOM.Store');
oSignerData := CreateOleObject('CAPICOM.SignedData');
oSigner := CreateOleObject('CAPICOM.Signer');
oSignerUtil := CreateOleObject('CAPICOM.Utilities');
oStore.Open(CAPICOM_CURRENT_USER_STORE,'My', CAPICOM_STORE_OPEN_READ_ONLY);
except
on oErr: Exception do
begin
ShowMessage('Для подписи запроса электронно-цифровой подписью необходимо наличие установленного компонента Microsoft CAPICOM на вашей рабочей станции.'+chr(13)+
'Пожалуйста, обратитесь к системному администратору.'+Chr(13)+
Trim(oErr.Message));
exit;
end;
end;
// Записать файл для шифрования в память
try
strStream := TStringStream.Create;
try
strStream.LoadFromFile(EditSignedFile.Text);
oSignerData.Content := strStream.DataString;
ShowMessage('Длина подписываемых данных в байтах: '+IntToStr(Length(oSignerData.Content)));
except
on oErr: Exception do
begin
ShowMessage('Ошибка при записи в SignerData.Content содержимого файла:' + Chr(13) +
'"'+EditSignedFile.Text+'"' + Chr(13) +
Trim(oErr.Message));
Exit;
end;
end;
finally
strStream.Free;
end;
// Выбрать сертификат
try
oCertificates := oStore.Certificates;
oCer := oCertificates.Select('Выбор сертификата', 'Пожалуйста, выберите сертификат для подписи.', FALSE);
oCer1 := oCer.Item[1];
oSigner.Certificate := oCer1;
except
on oErr: Exception do
begin
ShowMessage('Сертификат не найден. Пожалуйста, обратитесь к системному администратору.!' + Chr(13) +
Trim(oErr.Message));
Exit;
end;
end;
// Создать подпись
try
cMesShifr := oSignerData.Sign(oSigner, TRUE, CAPICOM_ENCODE_BINARY );
except
on oErr: Exception do
begin
ShowMessage('Ошибка при подписи документа. Пожалуйста, обратитесь к системному администратору.' + Chr(13) +
Trim(oErr.Message));
Exit;
end;
end;
ShowMessage('Длина подписи в байтах: '+IntToStr(Length(cMesShifr)));
// Записать подпись в файл
try
strStream := TStringStream.Create(cMesShifr);
strStream.Seek(0, soFromBeginning);
strStream.SaveToFile(EditSignFile.Text);
finally
strStream.Free;
end;
end;
При вызове проверки подписи в КриптоАРМе, тот по прежнему пишет: "Неверный формат данных (0x80070057)".Подписываемый файл: req_42990fb2-2c12-4c3a-b6f2-5fe4f8a45adc.xml Файл подписи: req_42990fb2-2c12-4c3a-b6f2-5fe4f8a45adc.xml.sig Он заметно похудел! Стал размером 644 байта, а при прошлом коде он был 1328 байт... Файл подписи почти весь заполнен символом с кодом 3F, так и должно быть? Вложение(я):  req_42990fb2-2c12-4c3a-b6f2-5fe4f8a45adc.xml (4kb) загружен 8 раз(а). req_42990fb2-2c12-4c3a-b6f2-5fe4f8a45adc.xml.sig (1kb) загружен 9 раз(а).У Вас нет прав для просмотра или загрузки вложений. Попробуйте зарегистрироваться.
|
|
|
|
Статус: Сотрудник
Группы: Участники
Зарегистрирован: 26.07.2011(UTC) Сообщений: 13,726   Сказал «Спасибо»: 574 раз Поблагодарили: 2303 раз в 1804 постах
|
импортируй Capicom v2.1 type library (import type library) на выходе: CAPICOM_TLB.pas uses .. ActiveX,ComObj, StrUtils, CAPICOM_TLB, OleServer, ComCtrls ... далее ... var Store: CAPICOM_TLB.IStore; SignedData: CAPICOM_TLB.ISignedData; и т.п. .. Чтение файла FileStm:= TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite ); FileStm.ReadBuffer(Pointer(Buffer)^, FileStm.Size); .. SignedData.Content:=Buffer; .. создание ЭЦП Buffer := SignedData.Sign(signer2, bDetached, ENCODING_TYPE); запись ЭЦП в файл: FileStm.WriteBuffer(Pointer(Buffer)^, SysStringByteLen(PWideChar(Buffer))); таким нехитрым способом подписывал в свое время (с Capicom) файлы до 300 мб... КриптоАРМ и другое ПО - проверяли успешно Отредактировано пользователем 31 июля 2012 г. 19:14:28(UTC)
| Причина: Не указана |
|
|
|
|
Статус: Активный участник
Группы: Участники
Зарегистрирован: 20.06.2012(UTC) Сообщений: 30   Откуда: Москва Сказал «Спасибо»: 4 раз Поблагодарили: 4 раз в 2 постах
|
Андрей * написал:импортируй Capicom v2.1 type library (import type library) на выходе: CAPICOM_TLB.pas
uses .. ActiveX,ComObj, StrUtils, CAPICOM_TLB, OleServer, ComCtrls ...
далее ... var Store: CAPICOM_TLB.IStore; SignedData: CAPICOM_TLB.ISignedData; и т.п. .. Чтение файла FileStm:= TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite ); FileStm.ReadBuffer(Pointer(Buffer)^, FileStm.Size); .. SignedData.Content:=Buffer; .. создание ЭЦП Buffer := SignedData.Sign(signer2, bDetached, ENCODING_TYPE);
запись ЭЦП в файл: FileStm.WriteBuffer(Pointer(Buffer)^, SysStringByteLen(PWideChar(Buffer)));
таким нехитрым способом подписывал в свое время (с Capicom) файлы до 300 мб... КриптоАРМ и другое ПО - проверяли успешно
Спасибо за подсказку! Я сделал следующий код: Код:// **********************************************cFXML
// Создание цифровой подписи
procedure TMainForm.BitBtn2Click(Sender: TObject);
var
filStream: TFileStream;
Buffer: WideString;
oStore: CAPICOM_TLB.IStore3;
oSignedData: CAPICOM_TLB.ISignedData;
oSigner: CAPICOM_TLB.ISigner;
oCertificates: CAPICOM_TLB.ICertificates2;
begin
// Чтение файла
try
filStream := TFileStream.Create(EditSignedFile.Text, fmOpenRead or fmShareDenyWrite );
SetLength(Buffer, filStream.Size);
filStream.ReadBuffer(Pointer(Buffer)^, filStream.Size);
finally
filStream.Free;
end;
// Создать COM-объекты
try
oStore := CoStore.Create;
oSignedData := CoSignedData.Create;
oSigner := CoSigner.Create;
oStore.Open(CAPICOM_CURRENT_USER_STORE,'My', CAPICOM_STORE_OPEN_READ_ONLY);
except
on oErr: Exception do
begin
ShowMessage('Для подписи запроса электронно-цифровой подписью необходимо наличие установленного компонента Microsoft CAPICOM на вашей рабочей станции.'+chr(13)+
'Пожалуйста, обратитесь к системному администратору.'+Chr(13)+
Trim(oErr.Message));
exit;
end;
end;
// Содержимое
oSignedData.Content := Buffer;
// Выбрать сертификат
try
//oStore.Certificates := oCertificates;
oCertificates := ICertificates2(IDisPatch(oStore.Certificates));
oCertificates := oCertificates.Select('Выбор сертификата', 'Пожалуйста, выберите сертификат для подписи.', FALSE);
oSigner.Certificate := CAPICOM_TLB.ICertificate(IDisPatch(oCertificates[1]));
except
on oErr: Exception do
begin
ShowMessage('Сертификат не найден. Пожалуйста, обратитесь к системному администратору.!' + Chr(13) +
Trim(oErr.Message));
Exit;
end;
end;
// Создание ЭЦП
Buffer := oSignedData.Sign(oSigner, TRUE, CAPICOM_ENCODE_BINARY);
// Запись ЭЦП в файл:
try
filStream := TFileStream.Create(EditSignFile.Text, fmCreate );
filStream.WriteBuffer(Pointer(Buffer)^, SysStringByteLen(PWideChar(Buffer)));
finally
filStream.Free;
end;
end;
Подписал с его помощью файл req_42990fb2-2c12-4c3a-b6f2-5fe4f8a45adc.xml, и получил файл req_42990fb2-2c12-4c3a-b6f2-5fe4f8a45adc.xml.sig. Теперь процедура проверки подписи КриптоАРМ-ом проходит дальше чем прежде! До третьего шага! На третьем шаге выдаёт ошибку: Статус завершения операции: Одна или несколько подписей некорректна или нет доверия. Длительность выполнения операции: 0:00:00.42 Входной файл: D:\FileCryptoSigner\1\req_42990fb2-2c12-4c3a-b6f2-5fe4f8a45adc.xml.sig Описание ошибки: Одна или несколько подписей некорректна или нет доверия
Что может быть не так? Вложение(я):  req_42990fb2-2c12-4c3a-b6f2-5fe4f8a45adc.xml (4kb) загружен 6 раз(а). req_42990fb2-2c12-4c3a-b6f2-5fe4f8a45adc.xml.sig (2kb) загружен 9 раз(а).У Вас нет прав для просмотра или загрузки вложений. Попробуйте зарегистрироваться.
|
|
|
|
Статус: Сотрудник
Группы: Участники
Зарегистрирован: 26.07.2011(UTC) Сообщений: 13,726   Сказал «Спасибо»: 574 раз Поблагодарили: 2303 раз в 1804 постах
|
Подпись не верна [2148077575] :Неправильное значение хеша
Хеш вложенных данных: 31A6C136A8182709C91174CFFFF4178A8DF42B54F3559B45BC0EF8319B45967A а хеш от файла: 10E3C383BDC8A58D16588B8558B252C52B9F3F7419AFE3BB7E6844F5BEA27C1C
значит имеет место быть неправильное считывание данных (т.е. ЭЦП создается не на оригинал)
Delphi - версия какая? |
|
|
|
|
Статус: Активный участник
Группы: Участники
Зарегистрирован: 20.06.2012(UTC) Сообщений: 30   Откуда: Москва Сказал «Спасибо»: 4 раз Поблагодарили: 4 раз в 2 постах
|
Андрей * написал:Подпись не верна [2148077575] :Неправильное значение хеша
Хеш вложенных данных: 31A6C136A8182709C91174CFFFF4178A8DF42B54F3559B45BC0EF8319B45967A а хеш от файла: 10E3C383BDC8A58D16588B8558B252C52B9F3F7419AFE3BB7E6844F5BEA27C1C
значит имеет место быть неправильное считывание данных (т.е. ЭЦП создается не на оригинал)
Delphi - версия какая? Delphi XE2 Update 4
|
|
|
|
Статус: Активный участник
Группы: Участники
Зарегистрирован: 20.06.2012(UTC) Сообщений: 30   Откуда: Москва Сказал «Спасибо»: 4 раз Поблагодарили: 4 раз в 2 постах
|
Интересно, что если подписывать АРМ-ом, то он предлагает поставить галку "Включить время создания подписи". Это где то задаётся при подписании через CAPICOM? Отредактировано пользователем 1 августа 2012 г. 16:11:43(UTC)
| Причина: Не указана
|
|
|
|
Статус: Сотрудник
Группы: Участники
Зарегистрирован: 26.07.2011(UTC) Сообщений: 13,726   Сказал «Спасибо»: 574 раз Поблагодарили: 2303 раз в 1804 постах
|
Zester написал:Интересно, что если подписывать АРМ-ом, то он предлагает поставить галку "Включить время создания подписи". Это где то задаётся при подписании через CRYPTOCOM? CRYPTOCOM его реально используешь или Capicom? Код: Attribute:=CoAttribute.Create;
Attribute.Name:=CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME;
Attribute.Value:=now; // в UTC нужно...
Signer.AuthenticatedAttributes.Add(Attribute);
Отредактировано пользователем 1 августа 2012 г. 16:07:28(UTC)
| Причина: Не указана |
|
|
|
|
Статус: Активный участник
Группы: Участники
Зарегистрирован: 20.06.2012(UTC) Сообщений: 30   Откуда: Москва Сказал «Спасибо»: 4 раз Поблагодарили: 4 раз в 2 постах
|
Андрей * написал:Zester написал:Интересно, что если подписывать АРМ-ом, то он предлагает поставить галку "Включить время создания подписи". Это где то задаётся при подписании через CRYPTOCOM? CRYPTOCOM его реально используешь или Capicom? Код: Attribute:=CoAttribute.Create;
Attribute.Name:=CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME;
Attribute.Value:=now; // в UTC нужно...
Signer.AuthenticatedAttributes.Add(Attribute);
Ой описался CAPICOM конечно
|
|
|
|
Быстрый переход
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.
Important Information:
The Форум КриптоПро uses cookies. By continuing to browse this site, you are agreeing to our use of cookies.
More Details
Close