11.02.2005 15:29:21ПОДПИСЬ БОЛЬШИХ ФАЙЛОВ Ответов: 7
Дробязко Алексей
Пытался с помощью примера в lowsign.c, переведенного на Делфи подписать файл размером 4Мб.
Для чтения большого файла использую BlockRead(infile, buf, 512);, т.е. читаю блоками по 512 байт.
Вот, что делал я:
----------------------------------------
var
hProv : HCRYPTPROV; // Дескриптор провайдера
pUserCert : PCCERT_CONTEXT; // Сертификат, используемый для формирования ЭЦП
keytype : DWORD; // Тип ключа (возвращается)
size : DWORD;
hMsg : HCRYPTMSG; // Дескриптор сообщения

HashAlgorithm : CRYPT_ALGORITHM_IDENTIFIER; // Идентификатор алг-ма хеширования
HashAlgSize : DWORD;
SignerEncodeInfo : CMSG_SIGNER_ENCODE_INFO; // Структура, описывающая отправителя
SignerEncodeInfoArray : array[1..1] of
CMSG_SIGNER_ENCODE_INFO; // Массив структур, описывающих отправителя

SignerCertBlob : CERT_BLOB;
SignerCertBlobArray : array[1..1] of CERT_BLOB;
cbEncodedBlob : DWORD;
pbEncodedBlob : pbyte;
SignedMsgEncodeInfo : CMSG_SIGNED_ENCODE_INFO; // Структура, описывающая подписанное сообщение
flags : DWORD;
should_release_ctx : boolean;
certfile : pchar;
ret : PCCERT_CONTEXT;
TYPE_DER : DWORD;
file_path : string;
sign_file_path : string;

include : integer;
detached : integer;

hCertSt : HCERTSTORE;
subject : PWideChar;
subj : string;
cbContent : string;

i : word;
infile: file;

buf: array[0..511] of byte;
begin
file_path := ’D:\!!\test.txt’;
sign_file_path := ’D:\!!\testsign.p7s’;

line := ’’;

include := 1; // Включать в подпись сертификат подписчика?
detached := 1; // ЭЦП отдельна от подписываемого файла.

errors := ’’;
TYPE_DER := PKCS_7_ASN_ENCODING or X509_ASN_ENCODING;

cert_subject := ’SARIT’;

OID := szOID_RSA_MD5;

CryptAcquireContext(@hProv, NIL, NIL, PROV_RSA_FULL, 0);

showmessage(syserrormessage(getlasterror()));

hCertSt := CertOpenSystemStore(0, ’MY’);

GetMem(subject, 2 * length(cert_subject) + 1);
StringToWideChar(cert_subject, subject, 2 * length(cert_subject) + 1);

pUserCert := CertFindCertificateInStore (
hCertSt,
TYPE_DER,
0,
CERT_FIND_SUBJECT_STR,
subject,
nil
);

showmessage(syserrormessage(getlasterror()));

// --------------------------------------------------------------------
// Инициализируем структуру алгоритма

HashAlgorithm.pszObjId := pansichar(OID); // Идентификатор алгоритма хэша

// --------------------------------------------------------------------
// Инициализируем структуру CMSG_SIGNER_ENCODE_INFO

SignerEncodeInfo.cbSize := sizeof(CMSG_SIGNER_ENCODE_INFO);
SignerEncodeInfo.pCertInfo := pUserCert^.pCertInfo;
SignerEncodeInfo.hCryptProv := hProv;
SignerEncodeInfo.dwKeySpec := keytype;
SignerEncodeInfo.HashAlgorithm := HashAlgorithm;
SignerEncodeInfo.pvHashAuxInfo := NIL;

// --------------------------------------------------------------------
// Создадим массив отправителей. Сейчас только из одного.

SignerEncodeInfoArray[1] := SignerEncodeInfo;

// --------------------------------------------------------------------
// Инициализируем структуру CMSG_SIGNED_ENCODE_INFO

SignerCertBlob.cbData := pUserCert^.cbCertEncoded;
SignerCertBlob.pbData := pUserCert^.pbCertEncoded;

SignerCertBlobArray[1] := SignerCertBlob;
// --------------------------------------------------------------------
// Инициализируем структуру массив структур CertBlob.

SignedMsgEncodeInfo.cbSize := sizeof(CMSG_SIGNED_ENCODE_INFO);
SignedMsgEncodeInfo.cSigners := 1;
SignedMsgEncodeInfo.rgSigners := @SignerEncodeInfoArray;
SignedMsgEncodeInfo.cCertEncoded := include;

// Если задан флаг добавления сертификата отправителя
if ( include = 1 ) Then
SignedMsgEncodeInfo.rgCertEncoded := @SignerCertBlobArray
else
SignedMsgEncodeInfo.rgCertEncoded := NIL;

SignedMsgEncodeInfo.rgCrlEncoded := NIL;

if (detached = 1) Then
flags := CMSG_DETACHED_FLAG;

// --------------------------------------------------------------------
// Определим длину подписанного сообщения

cbEncodedBlob := CryptMsgCalculateEncodedLength(
TYPE_DER, // Message encoding type
flags, // Flags
CMSG_SIGNED, // Message type
@SignedMsgEncodeInfo, // Pointer to structure
NIL, // Inner content object ID
mem_len // Size of content
);

showmessage(syserrormessage(getlasterror()));

pbEncodedBlob := allocmem(cbEncodedBlob);

// --------------------------------------------------------------------
// Создадим дескриптор сообщения

hMsg := CryptMsgOpenToEncode(
TYPE_DER, // Encoding type
flags, // Flags (CMSG_DETACHED_FLAG)
CMSG_SIGNED, // Message type
@SignedMsgEncodeInfo, // Pointer to structure
NIL, // Inner content object ID
NIL // Stream information (not used)
);

showmessage(syserrormessage(getlasterror()));

// --------------------------------------------------------------------
// Поместим в сообщение подписываемые данные

AssignFile(infile, file_path);
reset(infile, 1);
while not eof(infile) do
begin
BlockRead(infile, buf, 512, size);
// size=512 постоянно
CryptMsgUpdate(hMsg, @buf, size, True);
showmessage(syserrormessage(getlasterror()));
End;

showmessage(syserrormessage(getlasterror()));

CloseFile(infile);

// --------------------------------------------------------------------
// Вернем подписанное сообщение или только значение ЭЦП, если установлен признак detached


if(CryptMsgGetParam(
hMsg, // Handle to the message
CMSG_CONTENT_PARAM, // Parameter type
0, // Index
pbEncodedBlob, // Pointer to the blob
@cbEncodedBlob) // Size of the blob
) Then
errors := errors + ’Message encoded successfully.’
else
errors := errors + ’MsgGetParam failed.’;


----------------------------------------
Первый раз вызов CryptMsgUpdate выполняется успешно, последующие вызовы выдают ошибку "Ошибка при обработке криптографического сообщения".

Скажите, пожалуйста, что я делаю не так?
Спасибо.
 
Ответы:
11.02.2005 15:41:28Юрий
Советую почитать в MSDN описание функции CryptMsgUpdate. Обратите внимание на примечания к этой функции и на ее реакцию на флаг ATTACHED/DETACHED.
11.02.2005 18:09:52Дробязко Алексей
Спасибо за совет.
Я решил немного формализировать задачу. Мне необходимо подписать файл размером 4 Мб, причем подпись должна быть отдельно от файла(flags := CMSG_DETACHED_FLAG).
Из MSDN-а я понял, что ф-ию CryptMsgUpdate необходимо вызывать с fFinal=True ТОЛЬКО при апдейте последним блоком данных. Но в результате функция CryptMsgUpdate уже при первом вызове(с fFinal=False) выдает "Ошибка при обработке криптогр. сообщения". Что делать не знаю...
14.02.2005 9:19:14Юрий
:) И я не знаю :)
Все, программе трындец :)
14.02.2005 10:09:52Дробязко Алексей
Да, скорее всего, что так :))))))
14.02.2005 10:13:34kure
CryptMsgUpdate(hMsg, @buf, size, True);

Насколько помню, True - флаг последнего блоа.
14.02.2005 13:30:56kure
Кстати, большие файлы это больше 4 Гб.
14.02.2005 15:11:49Дробязко Алексей
Вроде так и делал...:))
Теперь все работает.
Спасибо всем!