Enhance the Deklphi code below so the encrypted string will be the shortest possible: Rember that when the MAC is encoded in binary, MAC size will be 16 instead of 32 bytes

unit Main;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, ORM_Utils, Vcl.StdCtrls;

type
TMainForm = class(TForm)
Memo1: TMemo;
ORM_Test1: TButton;
ORM_Test2: TButton;
procedure ORM_Test1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
MainForm: TMainForm;

implementation

Uses DECHash, DECCipherBase, DECHashBase, DECCiphers, DECUtil, DECFormat, DECRandom, DECHashAuthentication, DECCipherModes, DECCipherFormats, System.NetEncoding;

{$R *.dfm}

// HexToBytes and BytesToHex Functions
function HexToBytes(const Hex: string): TBytes;
var
I: Integer;
ByteValue: Byte;
Temp: string;
ByteInt: Integer;
begin
if Length(Hex) mod 2 <> 0 then
raise Exception.Create('Invalid hex string length');

SetLength(Result, Length(Hex) div 2);

for I := 0 to Length(Result) - 1 do
begin
Temp := Copy(Hex, 2 * I + 1, 2);
if not TryStrToInt('$' + Temp, ByteInt) then
raise Exception.CreateFmt('Invalid hex character at position %d', [2 * I + 1]);
if (ByteInt < 0) or (ByteInt > 255) then
raise Exception.CreateFmt('Hex value out of byte range at position %d', [2 * I + 1]);
ByteValue := Byte(ByteInt);
Result[I] := ByteValue;
end;
end;

function BytesToHex(const Bytes: TBytes): string;
const
HexChars: array[0..15] of Char = '0123456789ABCDEF';
var
I: Integer;
begin
SetLength(Result, Length(Bytes) * 2);
for I := 0 to Length(Bytes) - 1 do
begin
Result[I * 2 + 1] := HexChars[Bytes[I] shr 4];
Result[I * 2 + 2] := HexChars[Bytes[I] and $0F];
end;
end;

// Updated Base64ToBytes Function
function Base64ToBytes(const Base64: string): TBytes;
var
Encoder: TBase64Encoding;
begin
Encoder := TBase64Encoding.Create(0); // '0' specifies no line breaks
try
Result := Encoder.DecodeStringToBytes(Base64);
finally
Encoder.Free;
end;
end;

// Updated BytesToBase64 Function
function BytesToBase64(const Bytes: TBytes): string;
var
Encoder: TBase64Encoding;
begin
Encoder := TBase64Encoding.Create(0); // '0' specifies no line breaks
try
Result := Encoder.EncodeBytesToString(Bytes);
finally
Encoder.Free;
end;
end;

function EncryptString(const SourceText, Password: string): string;
var
Cipher: TCipher_Rijndael;
CipherKeyBytes, KeyKDF, IVBytes, Input, Ciphertext, SeedBytes, CombinedOutput: TBytes;
MACString: RawByteString;
EncryptedBase64: string;
begin
Cipher := TCipher_Rijndael.Create;
try
Cipher.Mode := cmCBCx;
CipherKeyBytes := TEncoding.UTF8.GetBytes(Password);
SeedBytes := RandomBytes(16);
KeyKDF := THash_Whirlpool0.KDFx(CipherKeyBytes[0], Length(CipherKeyBytes), SeedBytes[0], Length(SeedBytes), 8);
IVBytes := RandomBytes(16);
Cipher.Init(RawByteString(KeyKDF), RawByteString(IVBytes), 0);
Input := TEncoding.UTF8.GetBytes(SourceText);
Ciphertext := Cipher.EncodeBytes(Input);

// Calculate MAC
MACString := Cipher.CalcMAC(TFormat_HEXL);

// Debug output
MainForm.Memo1.Lines.Add('Encryption:');
MainForm.Memo1.Lines.Add('SeedBytes: ' + BytesToHex(SeedBytes));
MainForm.Memo1.Lines.Add('IVBytes: ' + BytesToHex(IVBytes));
MainForm.Memo1.Lines.Add('Ciphertext: ' + BytesToHex(Ciphertext));
MainForm.Memo1.Lines.Add('MAC: ' + string(MACString));

// Combine SeedBytes, IVBytes, Ciphertext, and MAC into one byte array
SetLength(CombinedOutput, Length(SeedBytes) + Length(IVBytes) + Length(Ciphertext) + Length(MACString));
Move(SeedBytes[0], CombinedOutput[0], Length(SeedBytes));
Move(IVBytes[0], CombinedOutput[Length(SeedBytes)], Length(IVBytes));
Move(Ciphertext[0], CombinedOutput[Length(SeedBytes) + Length(IVBytes)], Length(Ciphertext));
Move(MACString[1], CombinedOutput[Length(SeedBytes) + Length(IVBytes) + Length(Ciphertext)], Length(MACString));

EncryptedBase64 := BytesToBase64(CombinedOutput);
Result := EncryptedBase64;
Cipher.Done;

finally
Cipher.Free;
end;
end;

function DecryptString(const EncryptedBase64: string; const Password: string): string;
var
Cipher: TCipher_Rijndael;
CipherKeyBytes, KeyKDF, IVBytes, CombinedBytes, SeedBytes, CipherBytes, PlainBytes: TBytes;
StoredMACString, CalculatedMACString: RawByteString;
DecryptedText: string;
begin
Cipher := TCipher_Rijndael.Create;
try
// Decode the Base64 encrypted data
CombinedBytes := Base64ToBytes(EncryptedBase64);

// Ensure the combined data has at least Seed (16) + IV (16) + MAC (32) bytes
if Length(CombinedBytes) < (16 + 16 + 32) then
  raise Exception.Create('Invalid encrypted data: insufficient length');

// Extract SeedBytes (first 16 bytes)
SetLength(SeedBytes, 16);
Move(CombinedBytes[0], SeedBytes[0], 16);

// Extract IVBytes (next 16 bytes)
SetLength(IVBytes, 16);
Move(CombinedBytes[16], IVBytes[0], 16);

// Extract StoredMACString (last 32 bytes as HEX string)
SetString(StoredMACString, PAnsiChar(@CombinedBytes[Length(CombinedBytes) - 32]), 32);

// Extract CipherBytes (remaining bytes excluding Seed, IV, and MAC)
SetLength(CipherBytes, Length(CombinedBytes) - (16 + 16 + 32));
if Length(CipherBytes) > 0 then
  Move(CombinedBytes[32], CipherBytes[0], Length(CipherBytes));

// Debug output
MainForm.Memo1.Lines.Add('Decryption:');
MainForm.Memo1.Lines.Add('SeedBytes: ' + BytesToHex(SeedBytes));
MainForm.Memo1.Lines.Add('IVBytes: ' + BytesToHex(IVBytes));
MainForm.Memo1.Lines.Add('Ciphertext: ' + BytesToHex(CipherBytes));
MainForm.Memo1.Lines.Add('Stored MAC: ' + string(StoredMACString));

// Derive the key using KDF
CipherKeyBytes := TEncoding.UTF8.GetBytes(Password);
KeyKDF := THash_Whirlpool0.KDFx(
  CipherKeyBytes[0], Length(CipherKeyBytes),
  SeedBytes[0], Length(SeedBytes), 8
);

// Initialize the cipher in CBC mode with the derived key and IV
Cipher.Mode := cmCBCx;
Cipher.Init(RawByteString(KeyKDF), RawByteString(IVBytes), 0);

// Decrypt the CipherBytes to obtain PlainBytes
PlainBytes := Cipher.DecodeBytes(CipherBytes);

// Calculate the HMAC based on the processed CipherBytes
CalculatedMACString := Cipher.CalcMAC(TFormat_HEXL);
MainForm.Memo1.Lines.Add('Calculated MAC: ' + string(CalculatedMACString));

// Compare the stored HMAC with the calculated HMAC
if not CompareMem(@StoredMACString[1], @CalculatedMACString[1], 32) then
  raise Exception.Create('MAC verification failed. The encrypted data may have been tampered with.');

// Convert PlainBytes to a UTF-8 string
try
  DecryptedText := TEncoding.UTF8.GetString(PlainBytes);
except
  on E: Exception do
    raise Exception.Create('Decryption succeeded, but the decrypted data is not valid UTF-8: ' + E.Message);
end;

Result := DecryptedText;
Cipher.Done;

finally
Cipher.Free;
end;
end;

procedure TMainForm.ORM_Test1Click(Sender: TObject);
var
OriginalText, EncryptedString, DecryptedString: string;
begin
OriginalText := 'aBcé';
Memo1.Clear;
Memo1.Lines.Add('Original Text: ' + OriginalText);

EncryptedString := EncryptString(OriginalText, '#$GetIntoH^&%$');
Memo1.Lines.Add('Encrypted String: ' + EncryptedString);

DecryptedString := DecryptString(EncryptedString, '#$GetIntoH^&%$');
Memo1.Lines.Add('Decrypted String: ' + DecryptedString);

if DecryptedString = OriginalText then
Memo1.Lines.Add('Decryption successful: Strings match')
else
Memo1.Lines.Add('Decryption failed: Strings do not match');
end;

initialization
RandomSeed; // Initialize cryptographically secure random number generator in DECRandom.pas with random seed

finalization

end.