unit Tools.Crypt;
interface
uses
System.SysUtils, DECUtil, DECHash, DECCipherBase, DECCiphers, DECHashBase,
DECFormatBase, DECFormat, DECRandom, DECHashAuthentication;
const
conKey = 'aYr14iaz8u)xO7Ok';
var
CipherMode: TCipherMode = cmCBCx;
HashClass: TDECHashClass = THash_SHA256;
TextFormat: TDECFormatClass = TFormat_Base64;
KDFIndex: Integer = 1; // Iterations
type
TToolsCrypt = class
public
class function Decrypt(const aHash: string; out NoAuthResult: string; aKey: string = ''): string;
class function Encrypt(const aText: string; aKey: string = ''): string;
end;
implementation
{ TToolsCrypt }
class function TToolsCrypt.Decrypt(const aHash: string; out NoAuthResult: string; aKey: string): string;
var
Cipher: TCipher_Rijndael;
Salt, Data, Check, Pass, Mac: TBytes;
MacLength, SaltLen, DataLen: Integer;
begin
if aKey = '' then
begin
aKey := conKey;
end;
Cipher := TCipher_Rijndael.Create;
try
MacLength := Cipher.Context.BlockSize;
SaltLen := Cipher.InitVectorSize;
Salt := ValidFormat(TextFormat).Decode(BytesOf(aHash));
DataLen := Length(Salt) - MacLength - Cipher.Context.BufferSize;
Data := Copy(Salt, MacLength, DataLen);
Check := Copy(Salt, DataLen + SaltLen, Cipher.Context.BufferSize);
SetLength(Salt, SaltLen);
Pass := ValidAuthenticationHash(HashClass).KDFx(aKey[Low(aKey)], Length(aKey) * SizeOf(Char), Salt[Low(Salt)], Length(Salt), Cipher.Context.KeySize, KDFIndex);
Cipher.Mode := CipherMode;
Cipher.Init(Pass, nil);
SetLength(Result, DataLen div SizeOf(Char));
Cipher.Decode(Data[Low(Data)], Result[Low(Result)], DataLen);
NoAuthResult := Result;
Mac := BytesOf(Cipher.CalcMAC);
if MacLength < Length(Check) then
MacLength := Length(Check);
if (MacLength <> Cipher.Context.BlockSize) or (not CompareMem(Check, Mac, MacLength)) then
begin
Result := '';
end;
finally
Cipher.Free;
ProtectBytes(Salt);
ProtectBytes(Check);
ProtectBytes(Data);
ProtectBytes(Pass);
ProtectBytes(Mac);
end;
end;
class function TToolsCrypt.Encrypt(const aText: string; aKey: string): string;
var
Cipher: TCipher_Rijndael;
Salt, Pass, Data, Mac: TBytes;
begin
if aKey = '' then
begin
aKey := conKey;
end;
Cipher := TCipher_Rijndael.Create;
try
Salt := RandomBytes(Cipher.InitVectorSize);
Pass := ValidAuthenticationHash(HashClass).KDFx(aKey[Low(aKey)], Length(aKey) * SizeOf(Char), Salt[Low(Salt)], Length(Salt), Cipher.Context.KeySize, KDFIndex);
Cipher.Mode := CipherMode;
Cipher.Mode := cmCBCx;
Cipher.Init(Pass, nil);
SetLength(Data, Length(aText) * SizeOf(Char));
Cipher.Encode(aText[Low(aText)], Data[Low(Data)], Length(Data));
Mac := BytesOf(Cipher.CalcMAC);
Result := StringOf(ValidFormat(TextFormat).Encode(Salt + Data + Mac));
finally
Cipher.Free;
ProtectBytes(Salt);
ProtectBytes(Pass);
ProtectBytes(Data);
ProtectBytes(Mac);
end;
end;
end.