In the code below, review and fix the mismatched Stored and calculated HMAC on the decryption method:

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;

// Base64ToBytes and BytesToBase64 Functions
function BytesToBase64(const Bytes: TBytes): string;
begin
  Result := TNetEncoding.Base64.EncodeBytesToString(Bytes);
end;

function Base64ToBytes(const Base64: string): TBytes;
begin
  Result := TNetEncoding.Base64.DecodeStringToBytes(Base64);
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
    CombinedBytes := Base64ToBytes(EncryptedBase64);
    if Length(CombinedBytes) < (16 + 16 + 32) then // 16 SeedBytes + 16 IVBytes + 32 MAC chars (HEXL format)
      raise Exception.Create('Invalid encrypted data: insufficient length');

    SetLength(SeedBytes, 16);
    Move(CombinedBytes[0], SeedBytes[0], 16);
    SetLength(IVBytes, 16);
    Move(CombinedBytes[16], IVBytes[0], 16);

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

    // Extract Ciphertext (remaining bytes, excluding MAC)
    SetLength(CipherBytes, Length(CombinedBytes) - (16 + 16 + 32));
    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));

    Cipher.Mode := cmCBCx;
    CipherKeyBytes := TEncoding.UTF8.GetBytes(Password);
    KeyKDF := THash_Whirlpool0.KDFx(CipherKeyBytes[0], Length(CipherKeyBytes), SeedBytes[0], Length(SeedBytes), 8);
    Cipher.Init(RawByteString(KeyKDF), RawByteString(IVBytes), 0);

    // Calculate MAC and verify
    CalculatedMACString := Cipher.CalcMAC(TFormat_HEXL);
    MainForm.Memo1.Lines.Add('Calculated MAC: ' + string(CalculatedMACString));

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

    PlainBytes := Cipher.DecodeBytes(CipherBytes);
    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.