Ключевое слово в защите информации
КЛЮЧЕВОЕ СЛОВО
в защите информации
Получить ГОСТ TLS-сертификат для домена (SSL-сертификат)
Добро пожаловать, Гость! Чтобы использовать все возможности Вход или Регистрация.

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline Maxim Korobov  
#1 Оставлено : 21 апреля 2009 г. 19:36:58(UTC)
Maxim Korobov

Статус: Активный участник

Группы: Участники
Зарегистрирован: 19.02.2008(UTC)
Сообщений: 66
Откуда: Москва

Зашифровал с помощью CryptEncryptMessage, без ошибок (были проблемы как в http://www.cryptopro.ru/...o/forum/view.asp?q=2188, но решились как там же).

При расшифровке с помощью CryptDecryptMessage при втором вызове (непосредственно расшифровка) выскакивает ошибка Access Violation в библиотеке crypt32.dll (чтение по адресу 00000047);

Пробывал в CRYPT_DECRYPT_MESSAGE_PARA вместо указания хранилища давать контектс сертификата с заполненным CERT_KEY_CONTEXT_PROP_ID, ругалась на библиотеку ntdll.dll (запись по адресу ABABABBB).

Вот код (активен код с указанием CertStore для CryptDecryptMessage, код с указанием контекста сертификата закомменчен):

Код:

var
    Prov: HCRYPTPROV;
    hKey: HCRYPTKEY;
    hXChagngeKey: HCRYPTKEY;
    //
    keyProvInfo: CRYPT_KEY_PROV_INFO;
    cc: TCryptContext;
    //
    encCertLen: DWORD;
    encCert: PByte;
    context: PCCERT_CONTEXT;
    encType: DWORD;
    DecodedCert: string;
    store: HCERTSTORE;
    n: PCCERT_CONTEXT;
    //
    CertInCont: TCert;
    CertBytes: string;
    pCertContext: PCCERT_CONTEXT;
    datalen: Integer;
    subjnamestring: pchar;

    //
    pb: PByte;
    pbSize: Cardinal;
    hPubKey: HCRYPTKEY;
    //

    EncryptAlgSize: DWORD;
    EncryptParamsSize: DWORD;
    EncryptAlgorithm: CRYPT_ALGORITHM_IDENTIFIER;
    EncryptParams: CRYPT_ENCRYPT_MESSAGE_PARA;
    RecipientCertArray: array of PCCERT_CONTEXT;
    cbContent: DWORD;
    cbEncryptedBlob: DWORD;
    pbEncryptedBlob: PByte;
    pbContent: PByte;

    Dummy: PByte;

    a: PChar;
    arCertContext: TMemoryStream;

    DT: TTime;
    i: Integer;

    DecryptParams: CRYPT_DECRYPT_MESSAGE_PARA;
    DecryptParamsSize: DWORD;

    FileContent: PChar;
    FileContentSize: Cardinal;

    DecryptSize: DWORD;
    DecryptedBlob: PByte;
    Certs: HCERTSTORE;

    PrivateKeyInfo: CERT_KEY_CONTEXT;

const
    ContName = 'Prism';
begin
    cc := TCryptContext.Create(PAnsiChar(ContName), CP_GR3410_94_PROV_A, PROV_GOST_94_DH, []);

    SetCurContainerPassword(cc.Provider, '12345678');
    CryptGetUserKey(cc.Provider, AT_KEYEXCHANGE, @hXChagngeKey);

    datalen := 0;
    if not CryptGetKeyParam(hXChagngeKey, KP_CERTIFICATE, nil, @datalen, 0) then
    begin
        MessageDlg('Error installing certificate in container: ' + IntToStr(GetLastError), mtError, [mbOK], 0);
        exit;
    end;

//Don't work with CryptDecryptMessage
//    SetLength(CertBytes, datalen);
//
//    if not CryptGetKeyParam(hXChagngeKey, KP_CERTIFICATE, PByte(PChar(CertBytes)), @datalen, 0) then
//    begin
//        MessageDlg('Error of certificate in container: ' + IntToStr(GetLastError), mtError, [mbOK], 0);
//        Exit;
//    end;
//
//    pCertContext := CertCreateCertificateContext(PKCS_7_ASN_ENCODING or X509_ASN_ENCODING, PByte(PChar(CertBytes)), datalen);
//
//    PrivateKeyInfo.cbSize := SizeOf(PrivateKeyInfo);
//    PrivateKeyInfo.hCryptProv := cc.Provider;
//    PrivateKeyInfo.dwKeySpec := AT_KEYEXCHANGE;
//    if not CertSetCertificateContextProperty(pCertContext, CERT_KEY_CONTEXT_PROP_ID, 0, @PrivateKeyInfo) then
//    begin
//        MessageDlg('Error in CERT_KEY_CONTEXT_PROP_ID: ' + IntToStr(GetLastError), mtError, [mbOK], 0);
//        Exit;
//    end;
//
//    datalen := 0;
//    if not CertGetCertificateContextProperty(pCertContext, CERT_KEY_CONTEXT_PROP_ID, nil, @datalen) then
//    begin
//        MessageDlg('Error in CertGetCertificateContextProperty: ' + IntToStr(GetLastError), mtError, [mbOK], 0);
//        Exit;
//    end;

    // Trying with CertStore 
    Certs := CertOpenSystemStore(0{cc.Provider}, 'MY');

    DecryptParamsSize := SizeOf(DecryptParams);
    ZeroMemory(@DecryptParams, DecryptParamsSize);

    DecryptParams.cbSize := DecryptParamsSize;
    DecryptParams.dwMsgAndCertEncodingType := PKCS_7_ASN_ENCODING or X509_ASN_ENCODING;
    DecryptParams.cCertStore := 1;
    DecryptParams.rghCertStore := Certs;//@pCertContext; 

    FileContent := PChar(LoadFromFile('c:\1.txt'));
    FileContentSize := GetFileSize('c:\1.txt');

    if not CryptDecryptMessage(@DecryptParams, PByte(FileContent), FileContentSize, nil, @DecryptSize, nil) then
    begin
        MessageDlg('Error decrypting information: ' + IntToStr(GetLastError), mtError, [mbOK], 0);
        Exit;
    end;

    GetMem(DecryptedBlob, DecryptSize);

    if not CryptDecryptMessage(@DecryptParams, PByte(FileContent), FileContentSize, DecryptedBlob, @DecryptSize, nil) then
    begin
        MessageDlg('Error decrypting information: ' + IntToStr(GetLastError), mtError, [mbOK], 0);
        Exit;
    end;

    memLog.Text := CopyStr(DecryptedBlob, DecryptSize); // PByte -> String

    arCertContext.Free;
    FreeMem(DecryptedBlob, DecryptSize);

    //
    CryptDestroyKey(hXChagngeKey);
    CertFreeCertificateContext(pCertContext);
    CryptReleaseContext(Prov, 0);
    cc.Free;
end;



Важные обстоятельства, возможно, являющиеся причиной ошибки:
1. Шифрую и расшифровываю на одном ПК. То есть, использую один сертификат и расшифровываю, давая его же контекст (так как есть связь с секретным ключем);
2. Шифрую файл размером 99000 байт, размер зашифрованного файла - 99 393. ВАЖНО! При первом вызове CryptDecryptMessage в переменную для хранения размера расшифрованного файла записывается 99006 (байт).

Где может быть ошибка?
Offline Maxim Korobov  
#2 Оставлено : 21 апреля 2009 г. 19:44:50(UTC)
Maxim Korobov

Статус: Активный участник

Группы: Участники
Зарегистрирован: 19.02.2008(UTC)
Сообщений: 66
Откуда: Москва

Согласно 30.03.2006 12:27:10 Kirill Sobolev важное обстоятельство №1 не содержит ошибку:
"Для шифрования нужен открытый ключ (сертификат)получателя, для расшифрования - секретный ключ получателя. Ключи отправителя тут вообщем то непричем - их вообще может не быть. А ключ обмена в КриптоПро CSP создается с использованием открытого ключа получателя."
Offline Kirill Sobolev  
#3 Оставлено : 21 апреля 2009 г. 20:20:56(UTC)
Кирилл Соболев

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 25.12.2007(UTC)
Сообщений: 1,732
Мужчина
Откуда: КРИПТО-ПРО

Поблагодарили: 177 раз в 168 постах
как объявлена CryptDecryptMessage?
Техническую поддержку оказываем тут
Наша база знаний
Offline Maxim Korobov  
#4 Оставлено : 21 апреля 2009 г. 20:24:06(UTC)
Maxim Korobov

Статус: Активный участник

Группы: Участники
Зарегистрирован: 19.02.2008(UTC)
Сообщений: 66
Откуда: Москва

//+-------------------------------------------------------------------------
// Decrypts the message.
//
// If pbDecrypted == NULL, then, *pcbDecrypted is implicitly set to 0 on input.
// For *pcbDecrypted == 0 && ppXchgCert == NULL on input, the message isn't
// decrypted.
//
// For a successfully decrypted message, *ppXchgCert is updated
// with the CertContext used to decrypt. It must be freed by calling
// CertStoreFreeCert. Otherwise, *ppXchgCert is set to NULL.
//
// ppXchgCert can be NULL, indicating the caller isn't interested
// in getting the CertContext used to decrypt.
//--------------------------------------------------------------------------
function CryptDecryptMessage(pDecryptPara: PCRYPT_DECRYPT_MESSAGE_PARA;
const pbEncryptedBlob: PBYTE;
cbEncryptedBlob: DWORD;
pbDecrypted: PBYTE;
pcbDecrypted: PDWORD;
ppXchgCert: PPCCERT_CONTEXT): BOOL; stdcall;
Offline Kirill Sobolev  
#5 Оставлено : 21 апреля 2009 г. 20:57:29(UTC)
Кирилл Соболев

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 25.12.2007(UTC)
Сообщений: 1,732
Мужчина
Откуда: КРИПТО-ПРО

Поблагодарили: 177 раз в 168 постах
Цитата:

Certs: HCERTSTORE;
....
DecryptParams.rghCertStore := Certs;

в MSDN
Цитата:
typedef struct _CRYPT_DECRYPT_MESSAGE_PARA {
DWORD cbSize;
DWORD dwMsgAndCertEncodingType;
DWORD cCertStore;
HCERTSTORE* rghCertStore;
DWORD dwFlags;
} CRYPT_DECRYPT_MESSAGE_PARA, *PCRYPT_DECRYPT_MESSAGE_PARA;
Техническую поддержку оказываем тут
Наша база знаний
Offline Maxim Korobov  
#6 Оставлено : 21 апреля 2009 г. 21:15:47(UTC)
Maxim Korobov

Статус: Активный участник

Группы: Участники
Зарегистрирован: 19.02.2008(UTC)
Сообщений: 66
Откуда: Москва

Я поражаюсь вашему искусству, демонстрируемому в течении нескольких лет.

Исправил
Код:

    DecryptParams.rghCertStore := Certs;

на
Код:

    DecryptParams.rghCertStore := @Certs;


Теперь стало вполне обычно ругаться:
2148081676 CRYPT_E_NO_DECRYPT_CERT: No certificate was found having a private key property to use for decrypting.
Offline Maxim Korobov  
#7 Оставлено : 21 апреля 2009 г. 21:46:45(UTC)
Maxim Korobov

Статус: Активный участник

Группы: Участники
Зарегистрирован: 19.02.2008(UTC)
Сообщений: 66
Откуда: Москва

Попробовал пробежаться по всем (1) контекстам сертификата, чтобы указать им на связь с ключем:

Код:

    Certs := CertOpenSystemStore(cc.Provider, 'MY');

    pCertContext := nil;
    pCertContext := CertFindCertificateInStore(Certs, PKCS_7_ASN_ENCODING or X509_ASN_ENCODING, CERT_FIND_ANY, 0, nil, pCertContext);
    while (pCertContext <> nil) do
    begin
        PrivateKeyInfo.cbSize := SizeOf(PrivateKeyInfo);
        PrivateKeyInfo.hCryptProv := cc.Provider;
        PrivateKeyInfo.dwKeySpec := AT_KEYEXCHANGE;
        if not CertSetCertificateContextProperty(pCertContext, CERT_KEY_CONTEXT_PROP_ID, 0, @PrivateKeyInfo) then
        begin
            MessageDlg('Error in CERT_KEY_CONTEXT_PROP_ID: ' + IntToStr(GetLastError), mtError, [mbOK], 0);
            Exit;
        end;

        datalen := 0;
        if not CertGetCertificateContextProperty(pCertContext, CERT_KEY_CONTEXT_PROP_ID, nil, @datalen) then
        begin
            MessageDlg('Error in CertGetCertificateContextProperty: ' + IntToStr(GetLastError), mtError, [mbOK], 0);
            Exit;
        end;
        //
        pCertContext := CertFindCertificateInStore(Certs, PKCS_7_ASN_ENCODING or X509_ASN_ENCODING, CERT_FIND_ANY, 0, nil, pCertContext); 
    end;


Получилось!
Offline Maxim Korobov  
#8 Оставлено : 21 апреля 2009 г. 21:51:57(UTC)
Maxim Korobov

Статус: Активный участник

Группы: Участники
Зарегистрирован: 19.02.2008(UTC)
Сообщений: 66
Откуда: Москва

Забавно, что при первом вызове в DecryptSize записывается размер в 99006 байт, я честно выделяю столько памяти, а при втором вызове в DecryptSize записывается 99000 (сколько нужно).

Хорошо, что работаем с указателями и останавливается считываение по актуальному значению размера данных.
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Guest
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.