Delphi Crypto API – шифрование потока данных и строки паролем

Не мало статей и публикаций посвящено шифрованию и в частности использованию для этого crypto api например здесь. В статье дается детальное описание системы шифрования реализованной в операционной системе Windows, однако после ее прочтения так и не нашлось ответа на простой вопрос, как средствами Crypto API зашифровать строку паролем. После долгих поисков решил сделать функцию, которая будет шифровать поток данных, а шифрование строки организовать путем загрузки сроки в поток с последующим шифрованием. Такая казалось бы простая задача однако отняла достаточно много времени, но результат принесла положительный. И так предлагаю вниманию читателей исходный код для шифрования и расшифрования потока данных и строки паролем. Для того чтобы использовать написанные мною функции необходим файл, который импортирует все необходимые функции из системных DLL “Wcrypt2.pas”, он достаточно распростаранен на просторах интернета и содержится в исходном коде примера использования шифрования и расшифрования потока данных. Исходные коды можно скачать здесь Crypto. Параметры функций интуитивно понятны (например ABuffSize – определяет размер буфера чтения потока данных при шифровании советую использовать одинаковые для шифрования и расшифровки). О специальных можно прочитать в справочной системе по Crypto API кротко поясним их

AAlgHash – тип “Хеша“ используемый при шифровании

AAlgKey – тип ключа который будет использоваться при шифровании

AProvType – тип шифрования

AFlags – дополнительные флаги используемые для настроек шифрования


unit uCryptoUtils;

 

interface

uses Windows, Classes, SysUtils, wcrypt2;

 

function CryptStr(ASourceStr, APassword: string; ABuffSize: integer;

AAlgHash, AAlgKey : Cardinal;  AProvType, AFlags:DWORD): string;

 

function UnCryptStr(ASourceStr, APassword: string; ABuffSize: integer;

AAlgHash, AAlgKey : Cardinal; AProvType, AFlags:DWORD): string;

 

function CryptStream(ASourceStream, ADestStream: TMemoryStream;

APassword: string; ABufferSize: Integer;  AAlgHash, AAlgKey : Cardinal;

AProvType, AFlags:DWORD): TMemoryStream;

 

function UnCryptStream(ASourceStream, ADestStream: TMemoryStream;

APassword: string; ABufferSize: Integer;  AAlgHash, AAlgKey : Cardinal;

AProvType, AFlags:DWORD): TMemoryStream;

 

implementation

 

function CryptStream(ASourceStream, ADestStream: TMemoryStream; APassword: string;

ABufferSize: Integer; AAlgHash, AAlgKey : Cardinal; AProvType, AFlags:DWORD): TMemoryStream;

var

l: DWORD;

data: PByte;

hProv: HCRYPTPROV;

hash: HCRYPTHASH;

key: HCRYPTKEY;

lBufLen, lDataLen: DWORD;

lBufSize: Integer;

lisEnd: Boolean;

lStr: string;

 

begin

try

try

{получаем контекст криптопровайдера}

if not CryptAcquireContext(@hProv, nil, nil, AProvType, AFlags) then

RaiseLastOSError;

{создаем хеш-объект}

if not CryptCreateHash(hProv, AAlgHash, 0, 0, @hash)then

RaiseLastOSError;

{хешируем пароль}

if not CryptHashData(hash, @APassword[1], length(APassword), 0) then

RaiseLastOSError;

{создаем ключ на основании пароля для потокового шифра RC4}

if not CryptDeriveKey(hProv, AAlgKey, hash, 0, @key) then

RaiseLastOSError;

{выделяем место для буфера}

GetMem(data, ABufferSize);

{шифруем данные}

lBufSize:= ABufferSize div 2;

ASourceStream.Position:= 0;

ADestStream.Position:= 0;

repeat

lisEnd:= ASourceStream.Position>= ASourceStream.Size;

lBufLen:= ASourceStream.Read(data^, lBufSize);

if not CryptEncrypt(key, 0, lisEnd, 0, (data),

@lBufLen, ABufferSize) then

RaiseLastOSError;

ADestStream.Write(data^,lBufLen);

until (lisEnd);

Except on e: Exception do

begin

raise;

end;

end;

finally

{очищаем память буфера}

FreeMem(data, ABufferSize);

{уничтожаем хеш-объект}

CryptDestroyHash(hash);

{освобождаем контекст криптопровайдера}

CryptReleaseContext(hProv, 0);

end;

end;

 

function UnCryptStream(ASourceStream, ADestStream: TMemoryStream; APassword: string;

ABufferSize: Integer; AAlgHash, AAlgKey : Cardinal; AProvType, AFlags:DWORD): TMemoryStream;

var

l: DWORD;

data: PByte;

hProv: HCRYPTPROV;

hash: HCRYPTHASH;

key: HCRYPTKEY;

lBufLen, lDataLen: DWORD;

lBufSize: Integer;

lisEnd: Boolean;

begin

try

try

{выделяем место для буфера}

GetMem(data, ABufferSize);

{получаем контекст криптопровайдера}

if not CryptAcquireContext(@hProv, nil, nil, AProvType, AFlags) then

RaiseLastOSError;

{создаем хеш-объект}

if not CryptCreateHash(hProv, AAlgHash, 0, 0, @hash)then

RaiseLastOSError;

{хешируем пароль}

if not CryptHashData(hash, @APassword[1], length(APassword), 0) then

RaiseLastOSError;

{создаем ключ на основании пароля для потокового шифра RC4}

if not CryptDeriveKey(hProv, AAlgKey, hash, 0, @key) then

RaiseLastOSError;

ASourceStream.Position:= 0;

ADestStream.Position:= 0;

{шифруем данные}

repeat

lisEnd:= ASourceStream.Position >= ASourceStream.Size;

lBufLen:= ASourceStream.Read(data^, lBufSize);

if not CryptDecrypt(key, 0, lisEnd, 0, (data)

,@lBufLen) then

RaiseLastOSError;

ADestStream.Write(data^,lBufLen);

until lisEnd;

Except on e: Exception do

begin

Raise;

end;

end;

 

finally

{очишаем память от буфера}

FreeMem(data, ABufferSize);

{уничтожаем хеш-объект}

CryptDestroyHash(hash);

{освобождаем контекст криптопровайдера}

CryptReleaseContext(hProv, 0);

end;

end;

 

 

function fCryptStr(AStr: String): string;

var

ms, ms1: TMemoryStream;

lStringList: TStringList;

begin

ms:= TMemoryStream.Create;

ms1:= TMemoryStream.Create;

lStringList:= TStringList.Create;

lStringList.Text:= AStr;

lStringList.SaveToStream(ms);

CryptStream(ms, ms1,'123456', 512, CALG_SHA,

CALG_RC4, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);

ms1.Position:= 0;

lStringList.LoadFromStream(ms1);

Result:= lStringList.Text;

lStringList.Free;

ms1.Free;

ms.Free;

end;

 

function fUnCryptStr(AStr: String): string;

var

ms, ms1: TMemoryStream;

lStringList: TStringList;

begin

ms:= TMemoryStream.Create;

ms1:= TMemoryStream.Create;

lStringList:= TStringList.Create;

lStringList.Text:= AStr;

lStringList.SaveToStream(ms);

UnCryptStream(ms, ms1,'123456', 512, CALG_SHA,

CALG_RC4, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);

ms1.Position:= 0;

lStringList.LoadFromStream(ms1);

Result:= lStringList.Text;

lStringList.Free;

ms1.Free;

ms.Free;

end;

 

function CryptStr(ASourceStr, APassword: string;  ABuffSize: integer;

AAlgHash, AAlgKey : Cardinal; AProvType, AFlags:DWORD): string;

var

lInStringStream, lOutStringStream: TMemoryStream;

begin

lInStringStream:= TMemoryStream.Create;

lOutStringStream:= TMemoryStream.Create;

lInStringStream.Write(ASourceStr[1], Length(ASourceStr));

try

CryptStream(lInStringStream, lOutStringStream, APassword, ABuffSize,

AAlgHash, AAlgKey, AProvType, AFlags );

lOutStringStream.Position:= 0;

SetLength(Result, lOutStringStream.Size);

lOutStringStream.Read(Result[1], lOutStringStream.Size);

finally

lInStringStream.Free;

lOutStringStream.Free;

end;

end;

 

function UnCryptStr(ASourceStr, APassword: string; ABuffSize: integer;

AAlgHash, AAlgKey : Cardinal; AProvType, AFlags:DWORD): string;

var

lInStringStream, lOutStringStream: TMemoryStream;

begin

lInStringStream:= TMemoryStream.Create;

lOutStringStream:= TMemoryStream.Create;

lInStringStream.Write(ASourceStr[1], Length(ASourceStr));

try

UnCryptStream(lInStringStream, lOutStringStream, APassword, ABuffSize,

AAlgHash, AAlgKey, AProvType, AFlags );

lOutStringStream.Position:= 0;

SetLength(Result, lOutStringStream.Size);

lOutStringStream.Read(Result[1], lOutStringStream.Size);

finally

lInStringStream.Free;

lOutStringStream.Free;

end;

end;

 

end.

Share

Tags: , ,

Leave a Reply