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

Уведомление

Icon
Error

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

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

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

Создаю массив строк, заполняю строками, например, "строка1", "строка2", шифрую, расшифровываю закрытым ключем, записываю в другой массив. Получаю в нем "строка1", "строка1строка1" :(

Есть подозрение, что Delphi (или я!) что-то путает с указателями. Может, параметры CryptEncryptMessage не правильные?

На сообщения обработчиков ошибок прошу внимания не обращать.

Код функции:
Код:


Типы и переменные:
type
    TStringArray = array of string;
var
    strs, strs2, strs3: TStringArray;


Вызов:
    SetLength(strs, 2);
    SetLength(strs2, 2);
    SetLength(strs3, 2);
    strs[0] := 'test';
    strs[1] := 'dfgdsfg';
    strs2 := EncryptArrayWithKey(ContName, '12345678', strs, True);
    strs3 := DecryptArrayWithKey(ContName, '12345678', strs2, True);
    ShowMessage('a: ' + strs3[0] + ' ||||||| ' + strs3[1]);


Код функции:
function EncryptArrayWithKey(ContName: string; ContPassword: string; Txts: TStringArray; MakeBase64: Boolean = False): TStringArray;
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;

    i: Integer;

    FreeMemValue: Integer;
    ByteText: PByte;

begin
    if (ContName = pEmptyStr) then Exit;
    SetLength(Result, Length(Txts));

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

    if ContPassword <> pEmptyStr then
        SetCurContainerPassword(cc.Provider, ContPassword);

    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;

    SetLength(CertBytes, datalen);

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

    pCertContext := CertCreateCertificateContext(X509_ASN_ENCODING, PByte(PChar(CertBytes)), datalen);
    //
    {if GetPublicKeyString(cc.Provider, pCertContext, pb, pbSize) = sEmptyStr then begin
        MessageDlg('Error installing certificate in container: ' + IntToStr(GetLastError), mtError, [mbOK], 0);
        Exit;
    end;

    if not CryptImportKey(cc.Provider, pb, pbSize, hXChagngeKey, CRYPT_EXPORTABLE, @hPubKey) then begin
        MessageDlg('Error installing certificate in container: ' + IntToStr(GetLastError), mtError, [mbOK], 0);
        Exit;
    end;}

    //*********** Initialize the algorithm identifier structure. ******
    EncryptAlgSize := SizeOf(EncryptAlgorithm);
    ZeroMemory(@EncryptAlgorithm, EncryptAlgSize);
    EncryptAlgorithm.pszObjId := szOID_CP_GOST_28147;

    //********** Initialize the CRYPT_ENCRYPT_MESSAGE_PARA structure. ***
    EncryptParamsSize := SizeOf(EncryptParams);
    ZeroMemory(@EncryptParams, EncryptParamsSize);

    EncryptParams.cbSize := EncryptParamsSize;
    EncryptParams.dwMsgEncodingType := PKCS_7_ASN_ENCODING or X509_ASN_ENCODING;
    EncryptParams.hCryptProv := cc.Provider;
    EncryptParams.ContentEncryptionAlgorithm := EncryptAlgorithm;

    //*********************************************
    // Пробуем получить длину будущего сообщения
    //*********************************************
    arCertContext := TMemoryStream.Create;

    arCertContext.SetSize(SizeOf(pCertContext));
    TPointerList(arCertContext.Memory^)[0] := pCertContext;
    // pCertificateContext := PCCERT_CONTEXT( pICertificate.Header );

    for i := 0 to Length(Txts) - 1 do
    begin
        a := PAnsiChar(Txts[i]);
        cbContent := Length(a);

        if not CryptEncryptMessage(@EncryptParams, 1, arCertContext.Memory, PByte(a), cbContent, nil, @cbEncryptedBlob) then
        begin
            MessageDlg('Error installing certificate in container: ' + IntToStr(GetLastError), mtError, [mbOK], 0);
            Exit;
        end;
        GetMem(pbEncryptedBlob, cbEncryptedBlob);
        FreeMemValue := cbEncryptedBlob;
        if not CryptEncryptMessage(@EncryptParams, 1, arCertContext.Memory, PByte(a), cbContent, pbEncryptedBlob, @cbEncryptedBlob) then
        begin
            MessageDlg('Error installing certificate in container: ' + IntToStr(GetLastError), mtError, [mbOK], 0);
            Exit;
        end;

        Result[i] := CopyStr2(pbEncryptedBlob, cbEncryptedBlob);
        if MakeBase64 then
            Result[i] := EncodeStr(Result[i]);
        //
        FreeMem(pbEncryptedBlob, FreeMemValue);
        pbEncryptedBlob := nil;
        cbEncryptedBlob := 0;
        FreeMemValue := 0;
        a := nil;
    end;

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








function DecryptArrayWithKey(ContName: string; ContPassword: string; Txts: TStringArray; FromBase64: Boolean = False): TStringArray;
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;

    i: Integer;

    DecryptParams: CRYPT_DECRYPT_MESSAGE_PARA;
    DecryptParamsSize: DWORD;

    FileContent: string; //PChar;
    FileContentSize: Cardinal;

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

    PrivateKeyInfo: CERT_KEY_CONTEXT;

    hMemStore: HCERTSTORE;
    pCertContext2: PCCERT_CONTEXT;

begin

    SetLength(Result, Length(Txts));

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

    SetCurContainerPassword(cc.Provider, ContPassword);
    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;}
    //Don't work with CryptDecryptMessage

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

    hMemStore := CertOpenStore(CERT_STORE_PROV_MEMORY, PKCS_7_ASN_ENCODING or X509_ASN_ENCODING, cc.Provider, 0, nil);
    if hMemStore = nil then
    begin
        MessageDlg('Error in CertOpenStore: ' + IntToStr(GetLastError), mtError, [mbOK], 0);
        Exit;
    end;
    if not CertAddCertificateContextToStore(hMemStore, pCertContext, CERT_STORE_ADD_REPLACE_EXISTING, pCertContext2) then
    begin
        MessageDlg('Error in CertAddCertificateContextToStore: ' + IntToStr(GetLastError), mtError, [mbOK], 0);
        Exit;
    end;

    pCertContext := nil;
    pCertContext := CertFindCertificateInStore(hMemStore {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(hMemStore {Certs}, PKCS_7_ASN_ENCODING or X509_ASN_ENCODING, CERT_FIND_ANY, 0, nil, pCertContext);
    end;

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

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

    for i := 0 to Length(Txts) - 1 do
    begin
        if FromBase64 then
            FileContent := DecodeStr(Txts[i]) //LoadFromFile('c:\1.txt'); //PChar(LoadFromFile('c:\1.txt'));
        else
            FileContent := Txts[i];
        FileContentSize := Length(FileContent); //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);
        DecryptSize2 := DecryptSize; // После первого вызова получается размер чуть больше, чем реально будет записано. Поэтому, возможна утечка памяти на разницу между размерами. Поэтому запоминаем максимальный размер для дальнейшей очистки
        if not CryptDecryptMessage(@DecryptParams, PByte(FileContent), FileContentSize, DecryptedBlob, @DecryptSize, nil) then
        begin
            MessageDlg('Error decrypting information: ' + IntToStr(GetLastError), mtError, [mbOK], 0);
            Exit;
        end;

        Result[i] := CopyStr(DecryptedBlob, DecryptSize); // PByte -> String
        FreeMem(DecryptedBlob, DecryptSize2);
        {DeleteFile('c:\2.txt');
        SaveToFile('c:\2.txt', CopyStr(DecryptedBlob, DecryptSize));}
    end;

    arCertContext.Free;

    //
    CertCloseStore(hMemStore, CERT_CLOSE_STORE_CHECK_FLAG {CERT_CLOSE_STORE_FORCE_FLAG});
    CryptDestroyKey(hXChagngeKey);
    CertFreeCertificateContext(pCertContext);
    CryptReleaseContext(Prov, 0);
    cc.Free;
end;
Offline Maxim Korobov  
#2 Оставлено : 5 июня 2009 г. 20:35:30(UTC)
Maxim Korobov

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

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

Или я что-то не обнуляю/закрываю между проходами в цикле.

Используется Функция CopyStr:
Код:

function CopyStr(InStr: PByte; Len: Integer): string;
var
    i: Integer;
begin
    for i := 1 to Len do
        Result := Result + (PChar(InStr) + i - 1)^;
end;
Offline Maxim Korobov  
#3 Оставлено : 5 июня 2009 г. 22:11:06(UTC)
Maxim Korobov

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

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

Решилось.
Причем, ошибка была именно в CopyStr.

В начале функции Result не обнулялся, а так как Delphi сама не обнуляет, в нем оставался результат предыдущего вызова.

Соответственно, надо было только добавить в начало CopyStr:
Код:
Result := '';


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