DELPHI 语言AES CBC模式加解密数据实现

   在多可文档系统中文件接口需要和其他系统实现用户统一登录,其他数据加密传输,要保障算法和数据的一致性    对系统接口使用有很大帮助。系统选择使用AES加密算法的CBC模式(128位密钥),实现各系统间加密数据的传输。多可提供各种语言的算法实现,以下是DELPHI 语言的具体算法实现(其他语言参考博主相关文章):
   加解密文本用16进制字符串表示,如果您需要base64编码请修改编码和解密部分即可。
 

(* ************************************************ *)
 AES 加解密单元
(* ************************************************ *)

unit ElAES;

interface

uses
    SysUtils, Windows, Classes;

resourcestring
    SInvalidInBufSize = 'Wrong decrypting data block';
    // 'Invalid buffer size for decryption';
    SReadError = 'Data read error';
    SWriteError = 'Data write error';
    SDecryptError = 'Data error while decrypting';
    SHeadInfoError = 'Data error while decrypting';
    SPassWordEffError = 'Secret password verification error';

type
    EAESError = class(Exception);

    PInteger = ^Integer;
    PLongWord = ^longword;

    TAESBuffer = array [0 .. 15] of Byte;
    TAESKey128 = array [0 .. 15] of Byte;
    TAESKey192 = array [0 .. 23] of Byte;
    TAESKey256 = array [0 .. 31] of Byte;
    TAESExpandedKey128 = array [0 .. 43] of longword;
    TAESExpandedKey192 = array [0 .. 53] of longword;
    TAESExpandedKey256 = array [0 .. 63] of longword;

    PAESBuffer = ^TAESBuffer;
    PAESKey128 = ^TAESKey128;
    PAESKey192 = ^TAESKey192;
    PAESKey256 = ^TAESKey256;
    PAESExpandedKey128 = ^TAESExpandedKey128;
    PAESExpandedKey192 = ^TAESExpandedKey192;
    PAESExpandedKey256 = ^TAESExpandedKey256;

    TKeyBit = (KB128 = 1, KB192 = 2, KB256 = 3, KB512 = 7, KB1024 = 15);

    TDoAesBuffer = procedure(Obj: TObject; const Buffer; const BufferLen: Longint) of object;
    TDoReadAesBuffer = procedure(Obj: TObject; var Buffer; var BufferLen: Longint) of object;

    TAES = class(TObject)
    private
        // FKeyType: TKeyBit;

        function Min(A, B: Integer): Integer;
        function StrToHex(Value: Ansistring): string;
        function HexToStr(Value: string): Ansistring;
        // function GetEff(S: string): Word;

        // Key expansion routines for encryption
        procedure ExpandAESKeyForEncryption(const Key: TAESKey128; var ExpandedKey: TAESExpandedKey128); overload;
        procedure ExpandAESKeyForEncryption(const Key: TAESKey192; var ExpandedKey: TAESExpandedKey192); overload;
        procedure ExpandAESKeyForEncryption(const Key: TAESKey256; var ExpandedKey: TAESExpandedKey256); overload;

        // Block encryption routines
        procedure EncryptAES(const InBuf: TAESBuffer; const Key: TAESExpandedKey128; var OutBuf: TAESBuffer); overload;
        procedure EncryptAES(const InBuf: TAESBuffer; const Key: TAESExpandedKey192; var OutBuf: TAESBuffer); overload;
        procedure EncryptAES(const InBuf: TAESBuffer; const Key: TAESExpandedKey256; var OutBuf: TAESBuffer); overload;

        // Key transformation routines for decryption
        procedure ExpandAESKeyForDecryption(var ExpandedKey: TAESExpandedKey128); overload;
        procedure ExpandAESKeyForDecryption(const Key: TAESKey128; var ExpandedKey: TAESExpandedKey128); overload;

        procedure ExpandAESKeyForDecryption(var ExpandedKey: TAESExpandedKey192); overload;
        procedure ExpandAESKeyForDecryption(const Key: TAESKey192; var ExpandedKey: TAESExpandedKey192); overload;

        procedure ExpandAESKeyForDecryption(var ExpandedKey: TAESExpandedKey256); overload;
        procedure ExpandAESKeyForDecryption(const Key: TAESKey256; var ExpandedKey: TAESExpandedKey256); overload;

        procedure DecryptAES(const InBuf: TAESBuffer; const Key: TAESExpandedKey128; var OutBuf: TAESBuffer); overload;
        procedure DecryptAES(const InBuf: TAESBuffer; const Key: TAESExpandedKey192; var OutBuf: TAESBuffer); overload;
        procedure DecryptAES(const InBuf: TAESBuffer; const Key: TAESExpandedKey256; var OutBuf: TAESBuffer); overload;

        procedure FormatKey_Encrypt(const Key: Ansistring; const KeyBit: TKeyBit; AESKey128: TAESKey128;
          AESKey192: TAESKey192; AESKey256: TAESKey256; var ExpandedKey128: TAESExpandedKey128;
          var ExpandedKey192: TAESExpandedKey192; var ExpandedKey256: TAESExpandedKey256);
        procedure FormatKey_Decrypt(const Key: Ansistring; const KeyBit: TKeyBit; AESKey128: TAESKey128;
          AESKey192: TAESKey192; AESKey256: TAESKey256; var ExpandedKey128: TAESExpandedKey128;
          var ExpandedKey192: TAESExpandedKey192; var ExpandedKey256: TAESExpandedKey256);
    public
        procedure AfterConstruction(); override;

        // 流加解密
        procedure EncryptAESStreamCBC(Source, Dest: TStream; Count: Int64; const InitVector: TAESBuffer;
          Key: Ansistring; KeyBit: TKeyBit = KB128);
        procedure DecryptAESStreamCBC(Source, Dest: TStream; Count: Int64; const InitVector: TAESBuffer;
          Key: Ansistring; KeyBit: TKeyBit = KB128);

    end;

    // IsUtf8Encode 是否对输入字符串进行 Utf8 转码
function EncryptStr_CBC(Value, Key: string; InitVector: TAESBuffer; KeyBit: TKeyBit = KB256;
  IsUtf8Encode: Boolean = False): string;
function DecryptStr_CBC(Value, Key: string; InitVector: TAESBuffer; KeyBit: TKeyBit = KB256;
  IsUtf8Decode: Boolean = False): string;

implementation

const
    // 版本号
    AesEdition_1_0 = 1;

    Rcon: array [1 .. 30] of longword = ($00000001, $00000002, $00000004, $00000008, $00000010, $00000020, $00000040,
      $00000080, $0000001B, $00000036, $0000006C, $000000D8, $000000AB, $0000004D, $0000009A, $0000002F, $0000005E,
      $000000BC, $00000063, $000000C6, $00000097, $00000035, $0000006A, $000000D4, $000000B3, $0000007D, $000000FA,
      $000000EF, $000000C5, $00000091);

    ForwardTable: array [0 .. 255] of longword = ($A56363C6, $847C7CF8, $997777EE, $8D7B7BF6, $0DF2F2FF, $BD6B6BD6,
      $B16F6FDE, $54C5C591, $50303060, $03010102, $A96767CE, $7D2B2B56, $19FEFEE7, $62D7D7B5, $E6ABAB4D, $9A7676EC,
      $45CACA8F, $9D82821F, $40C9C989, $877D7DFA, $15FAFAEF, $EB5959B2, $C947478E, $0BF0F0FB, $ECADAD41, $67D4D4B3,
      $FDA2A25F, $EAAFAF45, $BF9C9C23, $F7A4A453, $967272E4, $5BC0C09B, $C2B7B775, $1CFDFDE1, $AE93933D, $6A26264C,
      $5A36366C, $413F3F7E, $02F7F7F5, $4FCCCC83, $5C343468, $F4A5A551, $34E5E5D1, $08F1F1F9, $937171E2, $73D8D8AB,
      $53313162, $3F15152A, $0C040408, $52C7C795, $65232346, $5EC3C39D, $28181830, $A1969637, $0F05050A, $B59A9A2F,
      $0907070E, $36121224, $9B80801B, $3DE2E2DF, $26EBEBCD, $6927274E, $CDB2B27F, $9F7575EA, $1B090912, $9E83831D,
      $742C2C58, $2E1A1A34, $2D1B1B36, $B26E6EDC, $EE5A5AB4, $FBA0A05B, $F65252A4, $4D3B3B76, $61D6D6B7, $CEB3B37D,
      $7B292952, $3EE3E3DD, $712F2F5E, $97848413, $F55353A6, $68D1D1B9, $00000000, $2CEDEDC1, $60202040, $1FFCFCE3,
      $C8B1B179, $ED5B5BB6, $BE6A6AD4, $46CBCB8D, $D9BEBE67, $4B393972, $DE4A4A94, $D44C4C98, $E85858B0, $4ACFCF85,
      $6BD0D0BB, $2AEFEFC5, $E5AAAA4F, $16FBFBED, $C5434386, $D74D4D9A, $55333366, $94858511, $CF45458A, $10F9F9E9,
      $06020204, $817F7FFE, $F05050A0, $443C3C78, $BA9F9F25, $E3A8A84B, $F35151A2, $FEA3A35D, $C0404080, $8A8F8F05,
      $AD92923F, $BC9D9D21, $48383870, $04F5F5F1, $DFBCBC63, $C1B6B677, $75DADAAF, $63212142, $30101020, $1AFFFFE5,
      $0EF3F3FD, $6DD2D2BF, $4CCDCD81, $140C0C18, $35131326, $2FECECC3, $E15F5FBE, $A2979735, $CC444488, $3917172E,
      $57C4C493, $F2A7A755, $827E7EFC, $473D3D7A, $AC6464C8, $E75D5DBA, $2B191932, $957373E6, $A06060C0, $98818119,
      $D14F4F9E, $7FDCDCA3, $66222244, $7E2A2A54, $AB90903B, $8388880B, $CA46468C, $29EEEEC7, $D3B8B86B, $3C141428,
      $79DEDEA7, $E25E5EBC, $1D0B0B16, $76DBDBAD, $3BE0E0DB, $56323264, $4E3A3A74, $1E0A0A14, $DB494992, $0A06060C,
      $6C242448, $E45C5CB8, $5DC2C29F, $6ED3D3BD, $EFACAC43, $A66262C4, $A8919139, $A4959531, $37E4E4D3, $8B7979F2,
      $32E7E7D5, $43C8C88B, $5937376E, $B76D6DDA, $8C8D8D01, $64D5D5B1, $D24E4E9C, $E0A9A949, $B46C6CD8, $FA5656AC,
      $07F4F4F3, $25EAEACF, $AF6565CA, $8E7A7AF4, $E9AEAE47, $18080810, $D5BABA6F, $887878F0, $6F25254A, $722E2E5C,
      $241C1C38, $F1A6A657, $C7B4B473, $51C6C697, $23E8E8CB, $7CDDDDA1, $9C7474E8, $211F1F3E, $DD4B4B96, $DCBDBD61,
      $868B8B0D, $858A8A0F, $907070E0, $423E3E7C, $C4B5B571, $AA6666CC, $D8484890, $05030306, $01F6F6F7, $120E0E1C,
      $A36161C2, $5F35356A, $F95757AE, $D0B9B969, $91868617, $58C1C199, $271D1D3A, $B99E9E27, $38E1E1D9, $13F8F8EB,
      $B398982B, $33111122, $BB6969D2, $70D9D9A9, $898E8E07, $A7949433, $B69B9B2D, $221E1E3C, $92878715, $20E9E9C9,
      $49CECE87, $FF5555AA, $78282850, $7ADFDFA5, $8F8C8C03, $F8A1A159, $80898909, $170D0D1A, $DABFBF65, $31E6E6D7,
      $C6424284, $B86868D0, $C3414182, $B0999929, $772D2D5A, $110F0F1E, $CBB0B07B, $FC5454A8, $D6BBBB6D, $3A16162C);

    LastForwardTable: array [0 .. 255] of longword = ($00000063, $0000007C, $00000077, $0000007B, $000000F2, $0000006B,
      $0000006F, $000000C5, $00000030, $00000001, $00000067, $0000002B, $000000FE, $000000D7, $000000AB, $00000076,
      $000000CA, $00000082, $000000C9, $0000007D, $000000FA, $00000059, $00000047, $000000F0, $000000AD, $000000D4,
      $000000A2, $000000AF, $0000009C, $000000A4, $00000072, $000000C0, $000000B7, $000000FD, $00000093, $00000026,
      $00000036, $0000003F, $000000F7, $000000CC, $00000034, $000000A5, $000000E5, $000000F1, $00000071, $000000D8,
      $00000031, $00000015, $00000004, $000000C7, $00000023, $000000C3, $00000018, $00000096, $00000005, $0000009A,
      $00000007, $00000012, $00000080, $000000E2, $000000EB, $00000027, $000000B2, $00000075, $00000009, $00000083,
      $0000002C, $0000001A, $0000001B, $0000006E, $0000005A, $000000A0, $00000052, $0000003B, $000000D6, $000000B3,
      $00000029, $000000E3, $0000002F, $00000084, $00000053, $000000D1, $00000000, $000000ED, $00000020, $000000FC,
      $000000B1, $0000005B, $0000006A, $000000CB, $000000BE, $00000039, $0000004A, $0000004C, $00000058, $000000CF,
      $000000D0, $000000EF, $000000AA, $000000FB, $00000043, $0000004D, $00000033, $00000085, $00000045, $000000F9,
      $00000002, $0000007F, $00000050, $0000003C, $0000009F, $000000A8, $00000051, $000000A3, $00000040, $0000008F,
      $00000092, $0000009D, $00000038, $000000F5, $000000BC, $000000B6, $000000DA, $00000021, $00000010, $000000FF,
      $000000F3, $000000D2, $000000CD, $0000000C, $00000013, $000000EC, $0000005F, $00000097, $00000044, $00000017,
      $000000C4, $000000A7, $0000007E, $0000003D, $00000064, $0000005D, $00000019, $00000073, $00000060, $00000081,
      $0000004F, $000000DC, $00000022, $0000002A, $00000090, $00000088, $00000046, $000000EE, $000000B8, $00000014,
      $000000DE, $0000005E, $0000000B, $000000DB, $000000E0, $00000032, $0000003A, $0000000A, $00000049, $00000006,
      $00000024, $0000005C, $000000C2, $000000D3, $000000AC, $00000062, $00000091, $00000095, $000000E4, $00000079,
      $000000E7, $000000C8, $00000037, $0000006D, $0000008D, $000000D5, $0000004E, $000000A9, $0000006C, $00000056,
      $000000F4, $000000EA, $00000065, $0000007A, $000000AE, $00000008, $000000BA, $00000078, $00000025, $0000002E,
      $0000001C, $000000A6, $000000B4, $000000C6, $000000E8, $000000DD, $00000074, $0000001F, $0000004B, $000000BD,
      $0000008B, $0000008A, $00000070, $0000003E, $000000B5, $00000066, $00000048, $00000003, $000000F6, $0000000E,
      $00000061, $00000035, $00000057, $000000B9, $00000086, $000000C1, $0000001D, $0000009E, $000000E1, $000000F8,
      $00000098, $00000011, $00000069, $000000D9, $0000008E, $00000094, $0000009B, $0000001E, $00000087, $000000E9,
      $000000CE, $00000055, $00000028, $000000DF, $0000008C, $000000A1, $00000089, $0000000D, $000000BF, $000000E6,
      $00000042, $00000068, $00000041, $00000099, $0000002D, $0000000F, $000000B0, $00000054, $000000BB, $00000016);

    InverseTable: array [0 .. 255] of longword = ($50A7F451, $5365417E, $C3A4171A, $965E273A, $CB6BAB3B, $F1459D1F,
      $AB58FAAC, $9303E34B, $55FA3020, $F66D76AD, $9176CC88, $254C02F5, $FCD7E54F, $D7CB2AC5, $80443526, $8FA362B5,
      $495AB1DE, $671BBA25, $980EEA45, $E1C0FE5D, $02752FC3, $12F04C81, $A397468D, $C6F9D36B, $E75F8F03, $959C9215,
      $EB7A6DBF, $DA595295, $2D83BED4, $D3217458, $2969E049, $44C8C98E, $6A89C275, $78798EF4, $6B3E5899, $DD71B927,
      $B64FE1BE, $17AD88F0, $66AC20C9, $B43ACE7D, $184ADF63, $82311AE5, $60335197, $457F5362, $E07764B1, $84AE6BBB,
      $1CA081FE, $942B08F9, $58684870, $19FD458F, $876CDE94, $B7F87B52, $23D373AB, $E2024B72, $578F1FE3, $2AAB5566,
      $0728EBB2, $03C2B52F, $9A7BC586, $A50837D3, $F2872830, $B2A5BF23, $BA6A0302, $5C8216ED, $2B1CCF8A, $92B479A7,
      $F0F207F3, $A1E2694E, $CDF4DA65, $D5BE0506, $1F6234D1, $8AFEA6C4, $9D532E34, $A055F3A2, $32E18A05, $75EBF6A4,
      $39EC830B, $AAEF6040, $069F715E, $51106EBD, $F98A213E, $3D06DD96, $AE053EDD, $46BDE64D, $B58D5491, $055DC471,
      $6FD40604, $FF155060, $24FB9819, $97E9BDD6, $CC434089, $779ED967, $BD42E8B0, $888B8907, $385B19E7, $DBEEC879,
      $470A7CA1, $E90F427C, $C91E84F8, $00000000, $83868009, $48ED2B32, $AC70111E, $4E725A6C, $FBFF0EFD, $5638850F,
      $1ED5AE3D, $27392D36, $64D90F0A, $21A65C68, $D1545B9B, $3A2E3624, $B1670A0C, $0FE75793, $D296EEB4, $9E919B1B,
      $4FC5C080, $A220DC61, $694B775A, $161A121C, $0ABA93E2, $E52AA0C0, $43E0223C, $1D171B12, $0B0D090E, $ADC78BF2,
      $B9A8B62D, $C8A91E14, $8519F157, $4C0775AF, $BBDD99EE, $FD607FA3, $9F2601F7, $BCF5725C, $C53B6644, $347EFB5B,
      $7629438B, $DCC623CB, $68FCEDB6, $63F1E4B8, $CADC31D7, $10856342, $40229713, $2011C684, $7D244A85, $F83DBBD2,
      $1132F9AE, $6DA129C7, $4B2F9E1D, $F330B2DC, $EC52860D, $D0E3C177, $6C16B32B, $99B970A9, $FA489411, $2264E947,
      $C48CFCA8, $1A3FF0A0, $D82C7D56, $EF903322, $C74E4987, $C1D138D9, $FEA2CA8C, $360BD498, $CF81F5A6, $28DE7AA5,
      $268EB7DA, $A4BFAD3F, $E49D3A2C, $0D927850, $9BCC5F6A, $62467E54, $C2138DF6, $E8B8D890, $5EF7392E, $F5AFC382,
      $BE805D9F, $7C93D069, $A92DD56F, $B31225CF, $3B99ACC8, $A77D1810, $6E639CE8, $7BBB3BDB, $097826CD, $F418596E,
      $01B79AEC, $A89A4F83, $656E95E6, $7EE6FFAA, $08CFBC21, $E6E815EF, $D99BE7BA, $CE366F4A, $D4099FEA, $D67CB029,
      $AFB2A431, $31233F2A, $3094A5C6, $C066A235, $37BC4E74, $A6CA82FC, $B0D090E0, $15D8A733, $4A9804F1, $F7DAEC41,
      $0E50CD7F, $2FF69117, $8DD64D76, $4DB0EF43, $544DAACC, $DF0496E4, $E3B5D19E, $1B886A4C, $B81F2CC1, $7F516546,
      $04EA5E9D, $5D358C01, $737487FA, $2E410BFB, $5A1D67B3, $52D2DB92, $335610E9, $1347D66D, $8C61D79A, $7A0CA137,
      $8E14F859, $893C13EB, $EE27A9CE, $35C961B7, $EDE51CE1, $3CB1477A, $59DFD29C, $3F73F255, $79CE1418, $BF37C773,
      $EACDF753, $5BAAFD5F, $146F3DDF, $86DB4478, $81F3AFCA, $3EC468B9, $2C342438, $5F40A3C2, $72C31D16, $0C25E2BC,
      $8B493C28, $41950DFF, $7101A839, $DEB30C08, $9CE4B4D8, $90C15664, $6184CB7B, $70B632D5, $745C6C48, $4257B8D0);

    LastInverseTable: array [0 .. 255] of longword = ($00000052, $00000009, $0000006A, $000000D5, $00000030, $00000036,
      $000000A5, $00000038, $000000BF, $00000040, $000000A3, $0000009E, $00000081, $000000F3, $000000D7, $000000FB,
      $0000007C, $000000E3, $00000039, $00000082, $0000009B, $0000002F, $000000FF, $00000087, $00000034, $0000008E,
      $00000043, $00000044, $000000C4, $000000DE, $000000E9, $000000CB, $00000054, $0000007B, $00000094, $00000032,
      $000000A6, $000000C2, $00000023, $0000003D, $000000EE, $0000004C, $00000095, $0000000B, $00000042, $000000FA,
      $000000C3, $0000004E, $00000008, $0000002E, $000000A1, $00000066, $00000028, $000000D9, $00000024, $000000B2,
      $00000076, $0000005B, $000000A2, $00000049, $0000006D, $0000008B, $000000D1, $00000025, $00000072, $000000F8,
      $000000F6, $00000064, $00000086, $00000068, $00000098, $00000016, $000000D4, $000000A4, $0000005C, $000000CC,
      $0000005D, $00000065, $000000B6, $00000092, $0000006C, $00000070, $00000048, $00000050, $000000FD, $000000ED,
      $000000B9, $000000DA, $0000005E, $00000015, $00000046, $00000057, $000000A7, $0000008D, $0000009D, $00000084,
      $00000090, $000000D8, $000000AB, $00000000, $0000008C, $000000BC, $000000D3, $0000000A, $000000F7, $000000E4,
      $00000058, $00000005, $000000B8, $000000B3, $00000045, $00000006, $000000D0, $0000002C, $0000001E, $0000008F,
      $000000CA, $0000003F, $0000000F, $00000002, $000000C1, $000000AF, $000000BD, $00000003, $00000001, $00000013,
      $0000008A, $0000006B, $0000003A, $00000091, $00000011, $00000041, $0000004F, $00000067, $000000DC, $000000EA,
      $00000097, $000000F2, $000000CF, $000000CE, $000000F0, $000000B4, $000000E6, $00000073, $00000096, $000000AC,
      $00000074, $00000022, $000000E7, $000000AD, $00000035, $00000085, $000000E2, $000000F9, $00000037, $000000E8,
      $0000001C, $00000075, $000000DF, $0000006E, $00000047, $000000F1, $0000001A, $00000071, $0000001D, $00000029,
      $000000C5, $00000089, $0000006F, $000000B7, $00000062, $0000000E, $000000AA, $00000018, $000000BE, $0000001B,
      $000000FC, $00000056, $0000003E, $0000004B, $000000C6, $000000D2, $00000079, $00000020, $0000009A, $000000DB,
      $000000C0, $000000FE, $00000078, $000000CD, $0000005A, $000000F4, $0000001F, $000000DD, $000000A8, $00000033,
      $00000088, $00000007, $000000C7, $00000031, $000000B1, $00000012, $00000010, $00000059, $00000027, $00000080,
      $000000EC, $0000005F, $00000060, $00000051, $0000007F, $000000A9, $00000019, $000000B5, $0000004A, $0000000D,
      $0000002D, $000000E5, $0000007A, $0000009F, $00000093, $000000C9, $0000009C, $000000EF, $000000A0, $000000E0,
      $0000003B, $0000004D, $000000AE, $0000002A, $000000F5, $000000B0, $000000C8, $000000EB, $000000BB, $0000003C,
      $00000083, $00000053, $00000099, $00000061, $00000017, $0000002B, $00000004, $0000007E, $000000BA, $00000077,
      $000000D6, $00000026, $000000E1, $00000069, $00000014, $00000063, $00000055, $00000021, $0000000C, $0000007D);

procedure TAES.AfterConstruction();
begin
    inherited;
    // FKeyType := kb128;
end;

function TAES.Min(A, B: Integer): Integer;
begin
    if A < B then
        Result := A
    else
        Result := B;
end;

procedure TAES.ExpandAESKeyForEncryption(const Key: TAESKey128; var ExpandedKey: TAESExpandedKey128);
var
    I, J: Integer;
    T: longword;
    W0, W1, W2, W3: longword;
begin
    ExpandedKey[0] := PLongWord(@Key[0])^;
    ExpandedKey[1] := PLongWord(@Key[4])^;
    ExpandedKey[2] := PLongWord(@Key[8])^;
    ExpandedKey[3] := PLongWord(@Key[12])^;
    I := 0;
    J := 1;
    repeat
        T := (ExpandedKey[I + 3] shl 24) or (ExpandedKey[I + 3] shr 8);
        W0 := LastForwardTable[Byte(T)];
        W1 := LastForwardTable[Byte(T shr 8)];
        W2 := LastForwardTable[Byte(T shr 16)];
        W3 := LastForwardTable[Byte(T shr 24)];

        ExpandedKey[I + 4] := ExpandedKey[I] xor (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16))
          xor ((W3 shl 24) or (W3 shr 8))) xor Rcon[J];
        Inc(J);
        ExpandedKey[I + 5] := ExpandedKey[I + 1] xor ExpandedKey[I + 4];
        ExpandedKey[I + 6] := ExpandedKey[I + 2] xor ExpandedKey[I + 5];
        ExpandedKey[I + 7] := ExpandedKey[I + 3] xor ExpandedKey[I + 6];
        Inc(I, 4);
    until I >= 40;
end;

procedure TAES.ExpandAESKeyForEncryption(const Key: TAESKey192; var ExpandedKey: TAESExpandedKey192);
var
    I, J: Integer;
    T: longword;
    W0, W1, W2, W3: longword;
begin
    ExpandedKey[0] := PLongWord(@Key[0])^;
    ExpandedKey[1] := PLongWord(@Key[4])^;
    ExpandedKey[2] := PLongWord(@Key[8])^;
    ExpandedKey[3] := PLongWord(@Key[12])^;
    ExpandedKey[4] := PLongWord(@Key[16])^;
    ExpandedKey[5] := PLongWord(@Key[20])^;
    I := 0;
    J := 1;
    repeat
        T := (ExpandedKey[I + 5] shl 24) or (ExpandedKey[I + 5] shr 8);
        W0 := LastForwardTable[Byte(T)];
        W1 := LastForwardTable[Byte(T shr 8)];
        W2 := LastForwardTable[Byte(T shr 16)];
        W3 := LastForwardTable[Byte(T shr 24)];
        ExpandedKey[I + 6] := ExpandedKey[I] xor (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16))
          xor ((W3 shl 24) or (W3 shr 8))) xor Rcon[J];
        Inc(J);
        ExpandedKey[I + 7] := ExpandedKey[I + 1] xor ExpandedKey[I + 6];
        ExpandedKey[I + 8] := ExpandedKey[I + 2] xor ExpandedKey[I + 7];
        ExpandedKey[I + 9] := ExpandedKey[I + 3] xor ExpandedKey[I + 8];
        ExpandedKey[I + 10] := ExpandedKey[I + 4] xor ExpandedKey[I + 9];
        ExpandedKey[I + 11] := ExpandedKey[I + 5] xor ExpandedKey[I + 10];
        Inc(I, 6);
    until I >= 46;
end;

procedure TAES.ExpandAESKeyForEncryption(const Key: TAESKey256; var ExpandedKey: TAESExpandedKey256);
var
    I, J: Integer;
    T: longword;
    W0, W1, W2, W3: longword;
begin
    ExpandedKey[0] := PLongWord(@Key[0])^;
    ExpandedKey[1] := PLongWord(@Key[4])^;
    ExpandedKey[2] := PLongWord(@Key[8])^;
    ExpandedKey[3] := PLongWord(@Key[12])^;
    ExpandedKey[4] := PLongWord(@Key[16])^;
    ExpandedKey[5] := PLongWord(@Key[20])^;
    ExpandedKey[6] := PLongWord(@Key[24])^;
    ExpandedKey[7] := PLongWord(@Key[28])^;
    I := 0;
    J := 1;
    repeat
        T := (ExpandedKey[I + 7] shl 24) or (ExpandedKey[I + 7] shr 8);
        W0 := LastForwardTable[Byte(T)];
        W1 := LastForwardTable[Byte(T shr 8)];
        W2 := LastForwardTable[Byte(T shr 16)];
        W3 := LastForwardTable[Byte(T shr 24)];
        ExpandedKey[I + 8] := ExpandedKey[I] xor (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16))
          xor ((W3 shl 24) or (W3 shr 8))) xor Rcon[J];
        Inc(J);
        ExpandedKey[I + 9] := ExpandedKey[I + 1] xor ExpandedKey[I + 8];
        ExpandedKey[I + 10] := ExpandedKey[I + 2] xor ExpandedKey[I + 9];
        ExpandedKey[I + 11] := ExpandedKey[I + 3] xor ExpandedKey[I + 10];
        W0 := LastForwardTable[Byte(ExpandedKey[I + 11])];
        W1 := LastForwardTable[Byte(ExpandedKey[I + 11] shr 8)];
        W2 := LastForwardTable[Byte(ExpandedKey[I + 11] shr 16)];
        W3 := LastForwardTable[Byte(ExpandedKey[I + 11] shr 24)];
        ExpandedKey[I + 12] := ExpandedKey[I + 4] xor (W0 xor ((W1 shl 8) or (W1 shr 24))
          xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)));
        ExpandedKey[I + 13] := ExpandedKey[I + 5] xor ExpandedKey[I + 12];
        ExpandedKey[I + 14] := ExpandedKey[I + 6] xor ExpandedKey[I + 13];
        ExpandedKey[I + 15] := ExpandedKey[I + 7] xor ExpandedKey[I + 14];
        Inc(I, 8);
    until I >= 52;
end;

procedure TAES.EncryptAES(const InBuf: TAESBuffer; const Key: TAESExpandedKey128; var OutBuf: TAESBuffer);
var
    T0, T1: array [0 .. 3] of longword;
    W0, W1, W2, W3: longword;
begin
    // initializing
    T0[0] := PLongWord(@InBuf[0])^ xor Key[0];
    T0[1] := PLongWord(@InBuf[4])^ xor Key[1];
    T0[2] := PLongWord(@InBuf[8])^ xor Key[2];
    T0[3] := PLongWord(@InBuf[12])^ xor Key[3];
    // performing transformation 9 times
    // round 1
    W0 := ForwardTable[Byte(T0[0])];
    W1 := ForwardTable[Byte(T0[1] shr 8)];
    W2 := ForwardTable[Byte(T0[2] shr 16)];
    W3 := ForwardTable[Byte(T0[3] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[4];
    W0 := ForwardTable[Byte(T0[1])];
    W1 := ForwardTable[Byte(T0[2] shr 8)];
    W2 := ForwardTable[Byte(T0[3] shr 16)];
    W3 := ForwardTable[Byte(T0[0] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[5];
    W0 := ForwardTable[Byte(T0[2])];
    W1 := ForwardTable[Byte(T0[3] shr 8)];
    W2 := ForwardTable[Byte(T0[0] shr 16)];
    W3 := ForwardTable[Byte(T0[1] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[6];
    W0 := ForwardTable[Byte(T0[3])];
    W1 := ForwardTable[Byte(T0[0] shr 8)];
    W2 := ForwardTable[Byte(T0[1] shr 16)];
    W3 := ForwardTable[Byte(T0[2] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[7];
    // round 2
    W0 := ForwardTable[Byte(T1[0])];
    W1 := ForwardTable[Byte(T1[1] shr 8)];
    W2 := ForwardTable[Byte(T1[2] shr 16)];
    W3 := ForwardTable[Byte(T1[3] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[8];
    W0 := ForwardTable[Byte(T1[1])];
    W1 := ForwardTable[Byte(T1[2] shr 8)];
    W2 := ForwardTable[Byte(T1[3] shr 16)];
    W3 := ForwardTable[Byte(T1[0] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[9];
    W0 := ForwardTable[Byte(T1[2])];
    W1 := ForwardTable[Byte(T1[3] shr 8)];
    W2 := ForwardTable[Byte(T1[0] shr 16)];
    W3 := ForwardTable[Byte(T1[1] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[10];
    W0 := ForwardTable[Byte(T1[3])];
    W1 := ForwardTable[Byte(T1[0] shr 8)];
    W2 := ForwardTable[Byte(T1[1] shr 16)];
    W3 := ForwardTable[Byte(T1[2] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[11];
    // round 3
    W0 := ForwardTable[Byte(T0[0])];
    W1 := ForwardTable[Byte(T0[1] shr 8)];
    W2 := ForwardTable[Byte(T0[2] shr 16)];
    W3 := ForwardTable[Byte(T0[3] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[12];
    W0 := ForwardTable[Byte(T0[1])];
    W1 := ForwardTable[Byte(T0[2] shr 8)];
    W2 := ForwardTable[Byte(T0[3] shr 16)];
    W3 := ForwardTable[Byte(T0[0] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[13];
    W0 := ForwardTable[Byte(T0[2])];
    W1 := ForwardTable[Byte(T0[3] shr 8)];
    W2 := ForwardTable[Byte(T0[0] shr 16)];
    W3 := ForwardTable[Byte(T0[1] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[14];
    W0 := ForwardTable[Byte(T0[3])];
    W1 := ForwardTable[Byte(T0[0] shr 8)];
    W2 := ForwardTable[Byte(T0[1] shr 16)];
    W3 := ForwardTable[Byte(T0[2] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[15];
    // round 4
    W0 := ForwardTable[Byte(T1[0])];
    W1 := ForwardTable[Byte(T1[1] shr 8)];
    W2 := ForwardTable[Byte(T1[2] shr 16)];
    W3 := ForwardTable[Byte(T1[3] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[16];
    W0 := ForwardTable[Byte(T1[1])];
    W1 := ForwardTable[Byte(T1[2] shr 8)];
    W2 := ForwardTable[Byte(T1[3] shr 16)];
    W3 := ForwardTable[Byte(T1[0] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[17];
    W0 := ForwardTable[Byte(T1[2])];
    W1 := ForwardTable[Byte(T1[3] shr 8)];
    W2 := ForwardTable[Byte(T1[0] shr 16)];
    W3 := ForwardTable[Byte(T1[1] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[18];
    W0 := ForwardTable[Byte(T1[3])];
    W1 := ForwardTable[Byte(T1[0] shr 8)];
    W2 := ForwardTable[Byte(T1[1] shr 16)];
    W3 := ForwardTable[Byte(T1[2] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[19];
    // round 5
    W0 := ForwardTable[Byte(T0[0])];
    W1 := ForwardTable[Byte(T0[1] shr 8)];
    W2 := ForwardTable[Byte(T0[2] shr 16)];
    W3 := ForwardTable[Byte(T0[3] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[20];
    W0 := ForwardTable[Byte(T0[1])];
    W1 := ForwardTable[Byte(T0[2] shr 8)];
    W2 := ForwardTable[Byte(T0[3] shr 16)];
    W3 := ForwardTable[Byte(T0[0] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[21];
    W0 := ForwardTable[Byte(T0[2])];
    W1 := ForwardTable[Byte(T0[3] shr 8)];
    W2 := ForwardTable[Byte(T0[0] shr 16)];
    W3 := ForwardTable[Byte(T0[1] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[22];
    W0 := ForwardTable[Byte(T0[3])];
    W1 := ForwardTable[Byte(T0[0] shr 8)];
    W2 := ForwardTable[Byte(T0[1] shr 16)];
    W3 := ForwardTable[Byte(T0[2] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[23];
    // round 6
    W0 := ForwardTable[Byte(T1[0])];
    W1 := ForwardTable[Byte(T1[1] shr 8)];
    W2 := ForwardTable[Byte(T1[2] shr 16)];
    W3 := ForwardTable[Byte(T1[3] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[24];
    W0 := ForwardTable[Byte(T1[1])];
    W1 := ForwardTable[Byte(T1[2] shr 8)];
    W2 := ForwardTable[Byte(T1[3] shr 16)];
    W3 := ForwardTable[Byte(T1[0] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[25];
    W0 := ForwardTable[Byte(T1[2])];
    W1 := ForwardTable[Byte(T1[3] shr 8)];
    W2 := ForwardTable[Byte(T1[0] shr 16)];
    W3 := ForwardTable[Byte(T1[1] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[26];
    W0 := ForwardTable[Byte(T1[3])];
    W1 := ForwardTable[Byte(T1[0] shr 8)];
    W2 := ForwardTable[Byte(T1[1] shr 16)];
    W3 := ForwardTable[Byte(T1[2] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[27];
    // round 7
    W0 := ForwardTable[Byte(T0[0])];
    W1 := ForwardTable[Byte(T0[1] shr 8)];
    W2 := ForwardTable[Byte(T0[2] shr 16)];
    W3 := ForwardTable[Byte(T0[3] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[28];
    W0 := ForwardTable[Byte(T0[1])];
    W1 := ForwardTable[Byte(T0[2] shr 8)];
    W2 := ForwardTable[Byte(T0[3] shr 16)];
    W3 := ForwardTable[Byte(T0[0] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[29];
    W0 := ForwardTable[Byte(T0[2])];
    W1 := ForwardTable[Byte(T0[3] shr 8)];
    W2 := ForwardTable[Byte(T0[0] shr 16)];
    W3 := ForwardTable[Byte(T0[1] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[30];
    W0 := ForwardTable[Byte(T0[3])];
    W1 := ForwardTable[Byte(T0[0] shr 8)];
    W2 := ForwardTable[Byte(T0[1] shr 16)];
    W3 := ForwardTable[Byte(T0[2] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[31];
    // round 8
    W0 := ForwardTable[Byte(T1[0])];
    W1 := ForwardTable[Byte(T1[1] shr 8)];
    W2 := ForwardTable[Byte(T1[2] shr 16)];
    W3 := ForwardTable[Byte(T1[3] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[32];
    W0 := ForwardTable[Byte(T1[1])];
    W1 := ForwardTable[Byte(T1[2] shr 8)];
    W2 := ForwardTable[Byte(T1[3] shr 16)];
    W3 := ForwardTable[Byte(T1[0] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[33];
    W0 := ForwardTable[Byte(T1[2])];
    W1 := ForwardTable[Byte(T1[3] shr 8)];
    W2 := ForwardTable[Byte(T1[0] shr 16)];
    W3 := ForwardTable[Byte(T1[1] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[34];
    W0 := ForwardTable[Byte(T1[3])];
    W1 := ForwardTable[Byte(T1[0] shr 8)];
    W2 := ForwardTable[Byte(T1[1] shr 16)];
    W3 := ForwardTable[Byte(T1[2] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[35];
    // round 9
    W0 := ForwardTable[Byte(T0[0])];
    W1 := ForwardTable[Byte(T0[1] shr 8)];
    W2 := ForwardTable[Byte(T0[2] shr 16)];
    W3 := ForwardTable[Byte(T0[3] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[36];
    W0 := ForwardTable[Byte(T0[1])];
    W1 := ForwardTable[Byte(T0[2] shr 8)];
    W2 := ForwardTable[Byte(T0[3] shr 16)];
    W3 := ForwardTable[Byte(T0[0] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[37];
    W0 := ForwardTable[Byte(T0[2])];
    W1 := ForwardTable[Byte(T0[3] shr 8)];
    W2 := ForwardTable[Byte(T0[0] shr 16)];
    W3 := ForwardTable[Byte(T0[1] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[38];
    W0 := ForwardTable[Byte(T0[3])];
    W1 := ForwardTable[Byte(T0[0] shr 8)];
    W2 := ForwardTable[Byte(T0[1] shr 16)];
    W3 := ForwardTable[Byte(T0[2] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[39];
    // last round of transformations
    W0 := LastForwardTable[Byte(T1[0])];
    W1 := LastForwardTable[Byte(T1[1] shr 8)];
    W2 := LastForwardTable[Byte(T1[2] shr 16)];
    W3 := LastForwardTable[Byte(T1[3] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[40];
    W0 := LastForwardTable[Byte(T1[1])];
    W1 := LastForwardTable[Byte(T1[2] shr 8)];
    W2 := LastForwardTable[Byte(T1[3] shr 16)];
    W3 := LastForwardTable[Byte(T1[0] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[41];
    W0 := LastForwardTable[Byte(T1[2])];
    W1 := LastForwardTable[Byte(T1[3] shr 8)];
    W2 := LastForwardTable[Byte(T1[0] shr 16)];
    W3 := LastForwardTable[Byte(T1[1] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[42];
    W0 := LastForwardTable[Byte(T1[3])];
    W1 := LastForwardTable[Byte(T1[0] shr 8)];
    W2 := LastForwardTable[Byte(T1[1] shr 16)];
    W3 := LastForwardTable[Byte(T1[2] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[43];
    // finalizing
    PLongWord(@OutBuf[0])^ := T0[0];
    PLongWord(@OutBuf[4])^ := T0[1];
    PLongWord(@OutBuf[8])^ := T0[2];
    PLongWord(@OutBuf[12])^ := T0[3];
end;

procedure TAES.EncryptAES(const InBuf: TAESBuffer; const Key: TAESExpandedKey192; var OutBuf: TAESBuffer);
var
    T0, T1: array [0 .. 3] of longword;
    W0, W1, W2, W3: longword;
begin
    // initializing
    T0[0] := PLongWord(@InBuf[0])^ xor Key[0];
    T0[1] := PLongWord(@InBuf[4])^ xor Key[1];
    T0[2] := PLongWord(@InBuf[8])^ xor Key[2];
    T0[3] := PLongWord(@InBuf[12])^ xor Key[3];
    // performing transformation 11 times
    // round 1
    W0 := ForwardTable[Byte(T0[0])];
    W1 := ForwardTable[Byte(T0[1] shr 8)];
    W2 := ForwardTable[Byte(T0[2] shr 16)];
    W3 := ForwardTable[Byte(T0[3] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[4];
    W0 := ForwardTable[Byte(T0[1])];
    W1 := ForwardTable[Byte(T0[2] shr 8)];
    W2 := ForwardTable[Byte(T0[3] shr 16)];
    W3 := ForwardTable[Byte(T0[0] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[5];
    W0 := ForwardTable[Byte(T0[2])];
    W1 := ForwardTable[Byte(T0[3] shr 8)];
    W2 := ForwardTable[Byte(T0[0] shr 16)];
    W3 := ForwardTable[Byte(T0[1] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[6];
    W0 := ForwardTable[Byte(T0[3])];
    W1 := ForwardTable[Byte(T0[0] shr 8)];
    W2 := ForwardTable[Byte(T0[1] shr 16)];
    W3 := ForwardTable[Byte(T0[2] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[7];
    // round 2
    W0 := ForwardTable[Byte(T1[0])];
    W1 := ForwardTable[Byte(T1[1] shr 8)];
    W2 := ForwardTable[Byte(T1[2] shr 16)];
    W3 := ForwardTable[Byte(T1[3] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[8];
    W0 := ForwardTable[Byte(T1[1])];
    W1 := ForwardTable[Byte(T1[2] shr 8)];
    W2 := ForwardTable[Byte(T1[3] shr 16)];
    W3 := ForwardTable[Byte(T1[0] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[9];
    W0 := ForwardTable[Byte(T1[2])];
    W1 := ForwardTable[Byte(T1[3] shr 8)];
    W2 := ForwardTable[Byte(T1[0] shr 16)];
    W3 := ForwardTable[Byte(T1[1] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[10];
    W0 := ForwardTable[Byte(T1[3])];
    W1 := ForwardTable[Byte(T1[0] shr 8)];
    W2 := ForwardTable[Byte(T1[1] shr 16)];
    W3 := ForwardTable[Byte(T1[2] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[11];
    // round 3
    W0 := ForwardTable[Byte(T0[0])];
    W1 := ForwardTable[Byte(T0[1] shr 8)];
    W2 := ForwardTable[Byte(T0[2] shr 16)];
    W3 := ForwardTable[Byte(T0[3] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[12];
    W0 := ForwardTable[Byte(T0[1])];
    W1 := ForwardTable[Byte(T0[2] shr 8)];
    W2 := ForwardTable[Byte(T0[3] shr 16)];
    W3 := ForwardTable[Byte(T0[0] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[13];
    W0 := ForwardTable[Byte(T0[2])];
    W1 := ForwardTable[Byte(T0[3] shr 8)];
    W2 := ForwardTable[Byte(T0[0] shr 16)];
    W3 := ForwardTable[Byte(T0[1] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[14];
    W0 := ForwardTable[Byte(T0[3])];
    W1 := ForwardTable[Byte(T0[0] shr 8)];
    W2 := ForwardTable[Byte(T0[1] shr 16)];
    W3 := ForwardTable[Byte(T0[2] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[15];
    // round 4
    W0 := ForwardTable[Byte(T1[0])];
    W1 := ForwardTable[Byte(T1[1] shr 8)];
    W2 := ForwardTable[Byte(T1[2] shr 16)];
    W3 := ForwardTable[Byte(T1[3] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[16];
    W0 := ForwardTable[Byte(T1[1])];
    W1 := ForwardTable[Byte(T1[2] shr 8)];
    W2 := ForwardTable[Byte(T1[3] shr 16)];
    W3 := ForwardTable[Byte(T1[0] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[17];
    W0 := ForwardTable[Byte(T1[2])];
    W1 := ForwardTable[Byte(T1[3] shr 8)];
    W2 := ForwardTable[Byte(T1[0] shr 16)];
    W3 := ForwardTable[Byte(T1[1] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[18];
    W0 := ForwardTable[Byte(T1[3])];
    W1 := ForwardTable[Byte(T1[0] shr 8)];
    W2 := ForwardTable[Byte(T1[1] shr 16)];
    W3 := ForwardTable[Byte(T1[2] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[19];
    // round 5
    W0 := ForwardTable[Byte(T0[0])];
    W1 := ForwardTable[Byte(T0[1] shr 8)];
    W2 := ForwardTable[Byte(T0[2] shr 16)];
    W3 := ForwardTable[Byte(T0[3] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[20];
    W0 := ForwardTable[Byte(T0[1])];
    W1 := ForwardTable[Byte(T0[2] shr 8)];
    W2 := ForwardTable[Byte(T0[3] shr 16)];
    W3 := ForwardTable[Byte(T0[0] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[21];
    W0 := ForwardTable[Byte(T0[2])];
    W1 := ForwardTable[Byte(T0[3] shr 8)];
    W2 := ForwardTable[Byte(T0[0] shr 16)];
    W3 := ForwardTable[Byte(T0[1] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[22];
    W0 := ForwardTable[Byte(T0[3])];
    W1 := ForwardTable[Byte(T0[0] shr 8)];
    W2 := ForwardTable[Byte(T0[1] shr 16)];
    W3 := ForwardTable[Byte(T0[2] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[23];
    // round 6
    W0 := ForwardTable[Byte(T1[0])];
    W1 := ForwardTable[Byte(T1[1] shr 8)];
    W2 := ForwardTable[Byte(T1[2] shr 16)];
    W3 := ForwardTable[Byte(T1[3] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[24];
    W0 := ForwardTable[Byte(T1[1])];
    W1 := ForwardTable[Byte(T1[2] shr 8)];
    W2 := ForwardTable[Byte(T1[3] shr 16)];
    W3 := ForwardTable[Byte(T1[0] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[25];
    W0 := ForwardTable[Byte(T1[2])];
    W1 := ForwardTable[Byte(T1[3] shr 8)];
    W2 := ForwardTable[Byte(T1[0] shr 16)];
    W3 := ForwardTable[Byte(T1[1] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[26];
    W0 := ForwardTable[Byte(T1[3])];
    W1 := ForwardTable[Byte(T1[0] shr 8)];
    W2 := ForwardTable[Byte(T1[1] shr 16)];
    W3 := ForwardTable[Byte(T1[2] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[27];
    // round 7
    W0 := ForwardTable[Byte(T0[0])];
    W1 := ForwardTable[Byte(T0[1] shr 8)];
    W2 := ForwardTable[Byte(T0[2] shr 16)];
    W3 := ForwardTable[Byte(T0[3] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[28];
    W0 := ForwardTable[Byte(T0[1])];
    W1 := ForwardTable[Byte(T0[2] shr 8)];
    W2 := ForwardTable[Byte(T0[3] shr 16)];
    W3 := ForwardTable[Byte(T0[0] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[29];
    W0 := ForwardTable[Byte(T0[2])];
    W1 := ForwardTable[Byte(T0[3] shr 8)];
    W2 := ForwardTable[Byte(T0[0] shr 16)];
    W3 := ForwardTable[Byte(T0[1] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[30];
    W0 := ForwardTable[Byte(T0[3])];
    W1 := ForwardTable[Byte(T0[0] shr 8)];
    W2 := ForwardTable[Byte(T0[1] shr 16)];
    W3 := ForwardTable[Byte(T0[2] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[31];
    // round 8
    W0 := ForwardTable[Byte(T1[0])];
    W1 := ForwardTable[Byte(T1[1] shr 8)];
    W2 := ForwardTable[Byte(T1[2] shr 16)];
    W3 := ForwardTable[Byte(T1[3] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[32];
    W0 := ForwardTable[Byte(T1[1])];
    W1 := ForwardTable[Byte(T1[2] shr 8)];
    W2 := ForwardTable[Byte(T1[3] shr 16)];
    W3 := ForwardTable[Byte(T1[0] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[33];
    W0 := ForwardTable[Byte(T1[2])];
    W1 := ForwardTable[Byte(T1[3] shr 8)];
    W2 := ForwardTable[Byte(T1[0] shr 16)];
    W3 := ForwardTable[Byte(T1[1] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[34];
    W0 := ForwardTable[Byte(T1[3])];
    W1 := ForwardTable[Byte(T1[0] shr 8)];
    W2 := ForwardTable[Byte(T1[1] shr 16)];
    W3 := ForwardTable[Byte(T1[2] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[35];
    // round 9
    W0 := ForwardTable[Byte(T0[0])];
    W1 := ForwardTable[Byte(T0[1] shr 8)];
    W2 := ForwardTable[Byte(T0[2] shr 16)];
    W3 := ForwardTable[Byte(T0[3] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[36];
    W0 := ForwardTable[Byte(T0[1])];
    W1 := ForwardTable[Byte(T0[2] shr 8)];
    W2 := ForwardTable[Byte(T0[3] shr 16)];
    W3 := ForwardTable[Byte(T0[0] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[37];
    W0 := ForwardTable[Byte(T0[2])];
    W1 := ForwardTable[Byte(T0[3] shr 8)];
    W2 := ForwardTable[Byte(T0[0] shr 16)];
    W3 := ForwardTable[Byte(T0[1] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[38];
    W0 := ForwardTable[Byte(T0[3])];
    W1 := ForwardTable[Byte(T0[0] shr 8)];
    W2 := ForwardTable[Byte(T0[1] shr 16)];
    W3 := ForwardTable[Byte(T0[2] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[39];
    // round 10
    W0 := ForwardTable[Byte(T1[0])];
    W1 := ForwardTable[Byte(T1[1] shr 8)];
    W2 := ForwardTable[Byte(T1[2] shr 16)];
    W3 := ForwardTable[Byte(T1[3] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[40];
    W0 := ForwardTable[Byte(T1[1])];
    W1 := ForwardTable[Byte(T1[2] shr 8)];
    W2 := ForwardTable[Byte(T1[3] shr 16)];
    W3 := ForwardTable[Byte(T1[0] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[41];
    W0 := ForwardTable[Byte(T1[2])];
    W1 := ForwardTable[Byte(T1[3] shr 8)];
    W2 := ForwardTable[Byte(T1[0] shr 16)];
    W3 := ForwardTable[Byte(T1[1] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[42];
    W0 := ForwardTable[Byte(T1[3])];
    W1 := ForwardTable[Byte(T1[0] shr 8)];
    W2 := ForwardTable[Byte(T1[1] shr 16)];
    W3 := ForwardTable[Byte(T1[2] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[43];
    // round 11
    W0 := ForwardTable[Byte(T0[0])];
    W1 := ForwardTable[Byte(T0[1] shr 8)];
    W2 := ForwardTable[Byte(T0[2] shr 16)];
    W3 := ForwardTable[Byte(T0[3] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[44];
    W0 := ForwardTable[Byte(T0[1])];
    W1 := ForwardTable[Byte(T0[2] shr 8)];
    W2 := ForwardTable[Byte(T0[3] shr 16)];
    W3 := ForwardTable[Byte(T0[0] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[45];
    W0 := ForwardTable[Byte(T0[2])];
    W1 := ForwardTable[Byte(T0[3] shr 8)];
    W2 := ForwardTable[Byte(T0[0] shr 16)];
    W3 := ForwardTable[Byte(T0[1] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[46];
    W0 := ForwardTable[Byte(T0[3])];
    W1 := ForwardTable[Byte(T0[0] shr 8)];
    W2 := ForwardTable[Byte(T0[1] shr 16)];
    W3 := ForwardTable[Byte(T0[2] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[47];
    // last round of transformations
    W0 := LastForwardTable[Byte(T1[0])];
    W1 := LastForwardTable[Byte(T1[1] shr 8)];
    W2 := LastForwardTable[Byte(T1[2] shr 16)];
    W3 := LastForwardTable[Byte(T1[3] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[48];
    W0 := LastForwardTable[Byte(T1[1])];
    W1 := LastForwardTable[Byte(T1[2] shr 8)];
    W2 := LastForwardTable[Byte(T1[3] shr 16)];
    W3 := LastForwardTable[Byte(T1[0] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[49];
    W0 := LastForwardTable[Byte(T1[2])];
    W1 := LastForwardTable[Byte(T1[3] shr 8)];
    W2 := LastForwardTable[Byte(T1[0] shr 16)];
    W3 := LastForwardTable[Byte(T1[1] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[50];
    W0 := LastForwardTable[Byte(T1[3])];
    W1 := LastForwardTable[Byte(T1[0] shr 8)];
    W2 := LastForwardTable[Byte(T1[1] shr 16)];
    W3 := LastForwardTable[Byte(T1[2] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[51];
    // finalizing
    PLongWord(@OutBuf[0])^ := T0[0];
    PLongWord(@OutBuf[4])^ := T0[1];
    PLongWord(@OutBuf[8])^ := T0[2];
    PLongWord(@OutBuf[12])^ := T0[3];
end;

procedure TAES.EncryptAES(const InBuf: TAESBuffer; const Key: TAESExpandedKey256; var OutBuf: TAESBuffer);
var
    T0, T1: array [0 .. 3] of longword;
    W0, W1, W2, W3: longword;
begin
    // initializing
    T0[0] := PLongWord(@InBuf[0])^ xor Key[0];
    T0[1] := PLongWord(@InBuf[4])^ xor Key[1];
    T0[2] := PLongWord(@InBuf[8])^ xor Key[2];
    T0[3] := PLongWord(@InBuf[12])^ xor Key[3];
    // performing transformation 13 times
    // round 1
    W0 := ForwardTable[Byte(T0[0])];
    W1 := ForwardTable[Byte(T0[1] shr 8)];
    W2 := ForwardTable[Byte(T0[2] shr 16)];
    W3 := ForwardTable[Byte(T0[3] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[4];
    W0 := ForwardTable[Byte(T0[1])];
    W1 := ForwardTable[Byte(T0[2] shr 8)];
    W2 := ForwardTable[Byte(T0[3] shr 16)];
    W3 := ForwardTable[Byte(T0[0] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[5];
    W0 := ForwardTable[Byte(T0[2])];
    W1 := ForwardTable[Byte(T0[3] shr 8)];
    W2 := ForwardTable[Byte(T0[0] shr 16)];
    W3 := ForwardTable[Byte(T0[1] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[6];
    W0 := ForwardTable[Byte(T0[3])];
    W1 := ForwardTable[Byte(T0[0] shr 8)];
    W2 := ForwardTable[Byte(T0[1] shr 16)];
    W3 := ForwardTable[Byte(T0[2] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[7];
    // round 2
    W0 := ForwardTable[Byte(T1[0])];
    W1 := ForwardTable[Byte(T1[1] shr 8)];
    W2 := ForwardTable[Byte(T1[2] shr 16)];
    W3 := ForwardTable[Byte(T1[3] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[8];
    W0 := ForwardTable[Byte(T1[1])];
    W1 := ForwardTable[Byte(T1[2] shr 8)];
    W2 := ForwardTable[Byte(T1[3] shr 16)];
    W3 := ForwardTable[Byte(T1[0] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[9];
    W0 := ForwardTable[Byte(T1[2])];
    W1 := ForwardTable[Byte(T1[3] shr 8)];
    W2 := ForwardTable[Byte(T1[0] shr 16)];
    W3 := ForwardTable[Byte(T1[1] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[10];
    W0 := ForwardTable[Byte(T1[3])];
    W1 := ForwardTable[Byte(T1[0] shr 8)];
    W2 := ForwardTable[Byte(T1[1] shr 16)];
    W3 := ForwardTable[Byte(T1[2] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[11];
    // round 3
    W0 := ForwardTable[Byte(T0[0])];
    W1 := ForwardTable[Byte(T0[1] shr 8)];
    W2 := ForwardTable[Byte(T0[2] shr 16)];
    W3 := ForwardTable[Byte(T0[3] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[12];
    W0 := ForwardTable[Byte(T0[1])];
    W1 := ForwardTable[Byte(T0[2] shr 8)];
    W2 := ForwardTable[Byte(T0[3] shr 16)];
    W3 := ForwardTable[Byte(T0[0] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[13];
    W0 := ForwardTable[Byte(T0[2])];
    W1 := ForwardTable[Byte(T0[3] shr 8)];
    W2 := ForwardTable[Byte(T0[0] shr 16)];
    W3 := ForwardTable[Byte(T0[1] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[14];
    W0 := ForwardTable[Byte(T0[3])];
    W1 := ForwardTable[Byte(T0[0] shr 8)];
    W2 := ForwardTable[Byte(T0[1] shr 16)];
    W3 := ForwardTable[Byte(T0[2] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[15];
    // round 4
    W0 := ForwardTable[Byte(T1[0])];
    W1 := ForwardTable[Byte(T1[1] shr 8)];
    W2 := ForwardTable[Byte(T1[2] shr 16)];
    W3 := ForwardTable[Byte(T1[3] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[16];
    W0 := ForwardTable[Byte(T1[1])];
    W1 := ForwardTable[Byte(T1[2] shr 8)];
    W2 := ForwardTable[Byte(T1[3] shr 16)];
    W3 := ForwardTable[Byte(T1[0] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[17];
    W0 := ForwardTable[Byte(T1[2])];
    W1 := ForwardTable[Byte(T1[3] shr 8)];
    W2 := ForwardTable[Byte(T1[0] shr 16)];
    W3 := ForwardTable[Byte(T1[1] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[18];
    W0 := ForwardTable[Byte(T1[3])];
    W1 := ForwardTable[Byte(T1[0] shr 8)];
    W2 := ForwardTable[Byte(T1[1] shr 16)];
    W3 := ForwardTable[Byte(T1[2] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[19];
    // round 5
    W0 := ForwardTable[Byte(T0[0])];
    W1 := ForwardTable[Byte(T0[1] shr 8)];
    W2 := ForwardTable[Byte(T0[2] shr 16)];
    W3 := ForwardTable[Byte(T0[3] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[20];
    W0 := ForwardTable[Byte(T0[1])];
    W1 := ForwardTable[Byte(T0[2] shr 8)];
    W2 := ForwardTable[Byte(T0[3] shr 16)];
    W3 := ForwardTable[Byte(T0[0] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[21];
    W0 := ForwardTable[Byte(T0[2])];
    W1 := ForwardTable[Byte(T0[3] shr 8)];
    W2 := ForwardTable[Byte(T0[0] shr 16)];
    W3 := ForwardTable[Byte(T0[1] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[22];
    W0 := ForwardTable[Byte(T0[3])];
    W1 := ForwardTable[Byte(T0[0] shr 8)];
    W2 := ForwardTable[Byte(T0[1] shr 16)];
    W3 := ForwardTable[Byte(T0[2] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[23];
    // round 6
    W0 := ForwardTable[Byte(T1[0])];
    W1 := ForwardTable[Byte(T1[1] shr 8)];
    W2 := ForwardTable[Byte(T1[2] shr 16)];
    W3 := ForwardTable[Byte(T1[3] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[24];
    W0 := ForwardTable[Byte(T1[1])];
    W1 := ForwardTable[Byte(T1[2] shr 8)];
    W2 := ForwardTable[Byte(T1[3] shr 16)];
    W3 := ForwardTable[Byte(T1[0] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[25];
    W0 := ForwardTable[Byte(T1[2])];
    W1 := ForwardTable[Byte(T1[3] shr 8)];
    W2 := ForwardTable[Byte(T1[0] shr 16)];
    W3 := ForwardTable[Byte(T1[1] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[26];
    W0 := ForwardTable[Byte(T1[3])];
    W1 := ForwardTable[Byte(T1[0] shr 8)];
    W2 := ForwardTable[Byte(T1[1] shr 16)];
    W3 := ForwardTable[Byte(T1[2] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[27];
    // round 7
    W0 := ForwardTable[Byte(T0[0])];
    W1 := ForwardTable[Byte(T0[1] shr 8)];
    W2 := ForwardTable[Byte(T0[2] shr 16)];
    W3 := ForwardTable[Byte(T0[3] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[28];
    W0 := ForwardTable[Byte(T0[1])];
    W1 := ForwardTable[Byte(T0[2] shr 8)];
    W2 := ForwardTable[Byte(T0[3] shr 16)];
    W3 := ForwardTable[Byte(T0[0] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[29];
    W0 := ForwardTable[Byte(T0[2])];
    W1 := ForwardTable[Byte(T0[3] shr 8)];
    W2 := ForwardTable[Byte(T0[0] shr 16)];
    W3 := ForwardTable[Byte(T0[1] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[30];
    W0 := ForwardTable[Byte(T0[3])];
    W1 := ForwardTable[Byte(T0[0] shr 8)];
    W2 := ForwardTable[Byte(T0[1] shr 16)];
    W3 := ForwardTable[Byte(T0[2] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[31];
    // round 8
    W0 := ForwardTable[Byte(T1[0])];
    W1 := ForwardTable[Byte(T1[1] shr 8)];
    W2 := ForwardTable[Byte(T1[2] shr 16)];
    W3 := ForwardTable[Byte(T1[3] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[32];
    W0 := ForwardTable[Byte(T1[1])];
    W1 := ForwardTable[Byte(T1[2] shr 8)];
    W2 := ForwardTable[Byte(T1[3] shr 16)];
    W3 := ForwardTable[Byte(T1[0] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[33];
    W0 := ForwardTable[Byte(T1[2])];
    W1 := ForwardTable[Byte(T1[3] shr 8)];
    W2 := ForwardTable[Byte(T1[0] shr 16)];
    W3 := ForwardTable[Byte(T1[1] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[34];
    W0 := ForwardTable[Byte(T1[3])];
    W1 := ForwardTable[Byte(T1[0] shr 8)];
    W2 := ForwardTable[Byte(T1[1] shr 16)];
    W3 := ForwardTable[Byte(T1[2] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[35];
    // round 9
    W0 := ForwardTable[Byte(T0[0])];
    W1 := ForwardTable[Byte(T0[1] shr 8)];
    W2 := ForwardTable[Byte(T0[2] shr 16)];
    W3 := ForwardTable[Byte(T0[3] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[36];
    W0 := ForwardTable[Byte(T0[1])];
    W1 := ForwardTable[Byte(T0[2] shr 8)];
    W2 := ForwardTable[Byte(T0[3] shr 16)];
    W3 := ForwardTable[Byte(T0[0] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[37];
    W0 := ForwardTable[Byte(T0[2])];
    W1 := ForwardTable[Byte(T0[3] shr 8)];
    W2 := ForwardTable[Byte(T0[0] shr 16)];
    W3 := ForwardTable[Byte(T0[1] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[38];
    W0 := ForwardTable[Byte(T0[3])];
    W1 := ForwardTable[Byte(T0[0] shr 8)];
    W2 := ForwardTable[Byte(T0[1] shr 16)];
    W3 := ForwardTable[Byte(T0[2] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[39];
    // round 10
    W0 := ForwardTable[Byte(T1[0])];
    W1 := ForwardTable[Byte(T1[1] shr 8)];
    W2 := ForwardTable[Byte(T1[2] shr 16)];
    W3 := ForwardTable[Byte(T1[3] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[40];
    W0 := ForwardTable[Byte(T1[1])];
    W1 := ForwardTable[Byte(T1[2] shr 8)];
    W2 := ForwardTable[Byte(T1[3] shr 16)];
    W3 := ForwardTable[Byte(T1[0] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[41];
    W0 := ForwardTable[Byte(T1[2])];
    W1 := ForwardTable[Byte(T1[3] shr 8)];
    W2 := ForwardTable[Byte(T1[0] shr 16)];
    W3 := ForwardTable[Byte(T1[1] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[42];
    W0 := ForwardTable[Byte(T1[3])];
    W1 := ForwardTable[Byte(T1[0] shr 8)];
    W2 := ForwardTable[Byte(T1[1] shr 16)];
    W3 := ForwardTable[Byte(T1[2] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[43];
    // round 11
    W0 := ForwardTable[Byte(T0[0])];
    W1 := ForwardTable[Byte(T0[1] shr 8)];
    W2 := ForwardTable[Byte(T0[2] shr 16)];
    W3 := ForwardTable[Byte(T0[3] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[44];
    W0 := ForwardTable[Byte(T0[1])];
    W1 := ForwardTable[Byte(T0[2] shr 8)];
    W2 := ForwardTable[Byte(T0[3] shr 16)];
    W3 := ForwardTable[Byte(T0[0] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[45];
    W0 := ForwardTable[Byte(T0[2])];
    W1 := ForwardTable[Byte(T0[3] shr 8)];
    W2 := ForwardTable[Byte(T0[0] shr 16)];
    W3 := ForwardTable[Byte(T0[1] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[46];
    W0 := ForwardTable[Byte(T0[3])];
    W1 := ForwardTable[Byte(T0[0] shr 8)];
    W2 := ForwardTable[Byte(T0[1] shr 16)];
    W3 := ForwardTable[Byte(T0[2] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[47];
    // round 12
    W0 := ForwardTable[Byte(T1[0])];
    W1 := ForwardTable[Byte(T1[1] shr 8)];
    W2 := ForwardTable[Byte(T1[2] shr 16)];
    W3 := ForwardTable[Byte(T1[3] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[48];
    W0 := ForwardTable[Byte(T1[1])];
    W1 := ForwardTable[Byte(T1[2] shr 8)];
    W2 := ForwardTable[Byte(T1[3] shr 16)];
    W3 := ForwardTable[Byte(T1[0] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[49];
    W0 := ForwardTable[Byte(T1[2])];
    W1 := ForwardTable[Byte(T1[3] shr 8)];
    W2 := ForwardTable[Byte(T1[0] shr 16)];
    W3 := ForwardTable[Byte(T1[1] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[50];
    W0 := ForwardTable[Byte(T1[3])];
    W1 := ForwardTable[Byte(T1[0] shr 8)];
    W2 := ForwardTable[Byte(T1[1] shr 16)];
    W3 := ForwardTable[Byte(T1[2] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[51];
    // round 13
    W0 := ForwardTable[Byte(T0[0])];
    W1 := ForwardTable[Byte(T0[1] shr 8)];
    W2 := ForwardTable[Byte(T0[2] shr 16)];
    W3 := ForwardTable[Byte(T0[3] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[52];
    W0 := ForwardTable[Byte(T0[1])];
    W1 := ForwardTable[Byte(T0[2] shr 8)];
    W2 := ForwardTable[Byte(T0[3] shr 16)];
    W3 := ForwardTable[Byte(T0[0] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[53];
    W0 := ForwardTable[Byte(T0[2])];
    W1 := ForwardTable[Byte(T0[3] shr 8)];
    W2 := ForwardTable[Byte(T0[0] shr 16)];
    W3 := ForwardTable[Byte(T0[1] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[54];
    W0 := ForwardTable[Byte(T0[3])];
    W1 := ForwardTable[Byte(T0[0] shr 8)];
    W2 := ForwardTable[Byte(T0[1] shr 16)];
    W3 := ForwardTable[Byte(T0[2] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[55];
    // last round of transformations
    W0 := LastForwardTable[Byte(T1[0])];
    W1 := LastForwardTable[Byte(T1[1] shr 8)];
    W2 := LastForwardTable[Byte(T1[2] shr 16)];
    W3 := LastForwardTable[Byte(T1[3] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[56];
    W0 := LastForwardTable[Byte(T1[1])];
    W1 := LastForwardTable[Byte(T1[2] shr 8)];
    W2 := LastForwardTable[Byte(T1[3] shr 16)];
    W3 := LastForwardTable[Byte(T1[0] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[57];
    W0 := LastForwardTable[Byte(T1[2])];
    W1 := LastForwardTable[Byte(T1[3] shr 8)];
    W2 := LastForwardTable[Byte(T1[0] shr 16)];
    W3 := LastForwardTable[Byte(T1[1] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[58];
    W0 := LastForwardTable[Byte(T1[3])];
    W1 := LastForwardTable[Byte(T1[0] shr 8)];
    W2 := LastForwardTable[Byte(T1[1] shr 16)];
    W3 := LastForwardTable[Byte(T1[2] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[59];
    // finalizing
    PLongWord(@OutBuf[0])^ := T0[0];
    PLongWord(@OutBuf[4])^ := T0[1];
    PLongWord(@OutBuf[8])^ := T0[2];
    PLongWord(@OutBuf[12])^ := T0[3];
end;

procedure TAES.ExpandAESKeyForDecryption(var ExpandedKey: TAESExpandedKey128);
var
    I: Integer;
    U, F2, F4, F8, F9: longword;
begin
    for I := 1 to 9 do begin
        F9 := ExpandedKey[I * 4];
        U := F9 and $80808080;
        F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        U := F2 and $80808080;
        F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        U := F4 and $80808080;
        F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        F9 := F9 xor F8;
        ExpandedKey[I * 4] := F2 xor F4 xor F8 xor (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8))
          xor (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24));
        F9 := ExpandedKey[I * 4 + 1];
        U := F9 and $80808080;
        F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        U := F2 and $80808080;
        F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        U := F4 and $80808080;
        F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        F9 := F9 xor F8;
        ExpandedKey[I * 4 + 1] := F2 xor F4 xor F8 xor (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8))
          xor (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24));
        F9 := ExpandedKey[I * 4 + 2];
        U := F9 and $80808080;
        F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        U := F2 and $80808080;
        F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        U := F4 and $80808080;
        F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        F9 := F9 xor F8;
        ExpandedKey[I * 4 + 2] := F2 xor F4 xor F8 xor (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8))
          xor (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24));
        F9 := ExpandedKey[I * 4 + 3];
        U := F9 and $80808080;
        F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        U := F2 and $80808080;
        F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        U := F4 and $80808080;
        F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        F9 := F9 xor F8;
        ExpandedKey[I * 4 + 3] := F2 xor F4 xor F8 xor (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8))
          xor (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24));
    end;
end;

procedure TAES.ExpandAESKeyForDecryption(const Key: TAESKey128; var ExpandedKey: TAESExpandedKey128);
begin
    ExpandAESKeyForEncryption(Key, ExpandedKey);
    ExpandAESKeyForDecryption(ExpandedKey);
end;

procedure TAES.ExpandAESKeyForDecryption(var ExpandedKey: TAESExpandedKey192);
var
    I: Integer;
    U, F2, F4, F8, F9: longword;
begin
    for I := 1 to 11 do begin
        F9 := ExpandedKey[I * 4];
        U := F9 and $80808080;
        F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        U := F2 and $80808080;
        F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        U := F4 and $80808080;
        F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        F9 := F9 xor F8;
        ExpandedKey[I * 4] := F2 xor F4 xor F8 xor (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8))
          xor (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24));
        F9 := ExpandedKey[I * 4 + 1];
        U := F9 and $80808080;
        F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        U := F2 and $80808080;
        F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        U := F4 and $80808080;
        F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        F9 := F9 xor F8;
        ExpandedKey[I * 4 + 1] := F2 xor F4 xor F8 xor (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8))
          xor (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24));
        F9 := ExpandedKey[I * 4 + 2];
        U := F9 and $80808080;
        F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        U := F2 and $80808080;
        F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        U := F4 and $80808080;
        F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        F9 := F9 xor F8;
        ExpandedKey[I * 4 + 2] := F2 xor F4 xor F8 xor (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8))
          xor (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24));
        F9 := ExpandedKey[I * 4 + 3];
        U := F9 and $80808080;
        F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        U := F2 and $80808080;
        F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        U := F4 and $80808080;
        F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        F9 := F9 xor F8;
        ExpandedKey[I * 4 + 3] := F2 xor F4 xor F8 xor (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8))
          xor (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24));
    end;
end;

procedure TAES.ExpandAESKeyForDecryption(const Key: TAESKey192; var ExpandedKey: TAESExpandedKey192);
begin
    ExpandAESKeyForEncryption(Key, ExpandedKey);
    ExpandAESKeyForDecryption(ExpandedKey);
end;

procedure TAES.ExpandAESKeyForDecryption(var ExpandedKey: TAESExpandedKey256);
var
    I: Integer;
    U, F2, F4, F8, F9: longword;
begin
    for I := 1 to 13 do begin
        F9 := ExpandedKey[I * 4];
        U := F9 and $80808080;
        F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        U := F2 and $80808080;
        F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        U := F4 and $80808080;
        F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        F9 := F9 xor F8;
        ExpandedKey[I * 4] := F2 xor F4 xor F8 xor (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8))
          xor (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24));
        F9 := ExpandedKey[I * 4 + 1];
        U := F9 and $80808080;
        F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        U := F2 and $80808080;
        F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        U := F4 and $80808080;
        F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        F9 := F9 xor F8;
        ExpandedKey[I * 4 + 1] := F2 xor F4 xor F8 xor (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8))
          xor (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24));
        F9 := ExpandedKey[I * 4 + 2];
        U := F9 and $80808080;
        F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        U := F2 and $80808080;
        F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        U := F4 and $80808080;
        F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        F9 := F9 xor F8;
        ExpandedKey[I * 4 + 2] := F2 xor F4 xor F8 xor (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8))
          xor (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24));
        F9 := ExpandedKey[I * 4 + 3];
        U := F9 and $80808080;
        F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        U := F2 and $80808080;
        F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        U := F4 and $80808080;
        F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B);
        F9 := F9 xor F8;
        ExpandedKey[I * 4 + 3] := F2 xor F4 xor F8 xor (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8))
          xor (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24));
    end;
end;

procedure TAES.ExpandAESKeyForDecryption(const Key: TAESKey256; var ExpandedKey: TAESExpandedKey256);
begin
    ExpandAESKeyForEncryption(Key, ExpandedKey);
    ExpandAESKeyForDecryption(ExpandedKey);
end;

procedure TAES.DecryptAES(const InBuf: TAESBuffer; const Key: TAESExpandedKey128; var OutBuf: TAESBuffer);
var
    T0, T1: array [0 .. 3] of longword;
    W0, W1, W2, W3: longword;
begin
    // initializing
    T0[0] := PLongWord(@InBuf[0])^ xor Key[40];
    T0[1] := PLongWord(@InBuf[4])^ xor Key[41];
    T0[2] := PLongWord(@InBuf[8])^ xor Key[42];
    T0[3] := PLongWord(@InBuf[12])^ xor Key[43];
    // performing transformations 9 times
    // round 1
    W0 := InverseTable[Byte(T0[0])];
    W1 := InverseTable[Byte(T0[3] shr 8)];
    W2 := InverseTable[Byte(T0[2] shr 16)];
    W3 := InverseTable[Byte(T0[1] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[36];
    W0 := InverseTable[Byte(T0[1])];
    W1 := InverseTable[Byte(T0[0] shr 8)];
    W2 := InverseTable[Byte(T0[3] shr 16)];
    W3 := InverseTable[Byte(T0[2] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[37];
    W0 := InverseTable[Byte(T0[2])];
    W1 := InverseTable[Byte(T0[1] shr 8)];
    W2 := InverseTable[Byte(T0[0] shr 16)];
    W3 := InverseTable[Byte(T0[3] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[38];
    W0 := InverseTable[Byte(T0[3])];
    W1 := InverseTable[Byte(T0[2] shr 8)];
    W2 := InverseTable[Byte(T0[1] shr 16)];
    W3 := InverseTable[Byte(T0[0] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[39];
    // round 2
    W0 := InverseTable[Byte(T1[0])];
    W1 := InverseTable[Byte(T1[3] shr 8)];
    W2 := InverseTable[Byte(T1[2] shr 16)];
    W3 := InverseTable[Byte(T1[1] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[32];
    W0 := InverseTable[Byte(T1[1])];
    W1 := InverseTable[Byte(T1[0] shr 8)];
    W2 := InverseTable[Byte(T1[3] shr 16)];
    W3 := InverseTable[Byte(T1[2] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[33];
    W0 := InverseTable[Byte(T1[2])];
    W1 := InverseTable[Byte(T1[1] shr 8)];
    W2 := InverseTable[Byte(T1[0] shr 16)];
    W3 := InverseTable[Byte(T1[3] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[34];
    W0 := InverseTable[Byte(T1[3])];
    W1 := InverseTable[Byte(T1[2] shr 8)];
    W2 := InverseTable[Byte(T1[1] shr 16)];
    W3 := InverseTable[Byte(T1[0] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[35];
    // round 3
    W0 := InverseTable[Byte(T0[0])];
    W1 := InverseTable[Byte(T0[3] shr 8)];
    W2 := InverseTable[Byte(T0[2] shr 16)];
    W3 := InverseTable[Byte(T0[1] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[28];
    W0 := InverseTable[Byte(T0[1])];
    W1 := InverseTable[Byte(T0[0] shr 8)];
    W2 := InverseTable[Byte(T0[3] shr 16)];
    W3 := InverseTable[Byte(T0[2] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[29];
    W0 := InverseTable[Byte(T0[2])];
    W1 := InverseTable[Byte(T0[1] shr 8)];
    W2 := InverseTable[Byte(T0[0] shr 16)];
    W3 := InverseTable[Byte(T0[3] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[30];
    W0 := InverseTable[Byte(T0[3])];
    W1 := InverseTable[Byte(T0[2] shr 8)];
    W2 := InverseTable[Byte(T0[1] shr 16)];
    W3 := InverseTable[Byte(T0[0] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[31];
    // round 4
    W0 := InverseTable[Byte(T1[0])];
    W1 := InverseTable[Byte(T1[3] shr 8)];
    W2 := InverseTable[Byte(T1[2] shr 16)];
    W3 := InverseTable[Byte(T1[1] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[24];
    W0 := InverseTable[Byte(T1[1])];
    W1 := InverseTable[Byte(T1[0] shr 8)];
    W2 := InverseTable[Byte(T1[3] shr 16)];
    W3 := InverseTable[Byte(T1[2] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[25];
    W0 := InverseTable[Byte(T1[2])];
    W1 := InverseTable[Byte(T1[1] shr 8)];
    W2 := InverseTable[Byte(T1[0] shr 16)];
    W3 := InverseTable[Byte(T1[3] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[26];
    W0 := InverseTable[Byte(T1[3])];
    W1 := InverseTable[Byte(T1[2] shr 8)];
    W2 := InverseTable[Byte(T1[1] shr 16)];
    W3 := InverseTable[Byte(T1[0] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[27];
    // round 5
    W0 := InverseTable[Byte(T0[0])];
    W1 := InverseTable[Byte(T0[3] shr 8)];
    W2 := InverseTable[Byte(T0[2] shr 16)];
    W3 := InverseTable[Byte(T0[1] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[20];
    W0 := InverseTable[Byte(T0[1])];
    W1 := InverseTable[Byte(T0[0] shr 8)];
    W2 := InverseTable[Byte(T0[3] shr 16)];
    W3 := InverseTable[Byte(T0[2] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[21];
    W0 := InverseTable[Byte(T0[2])];
    W1 := InverseTable[Byte(T0[1] shr 8)];
    W2 := InverseTable[Byte(T0[0] shr 16)];
    W3 := InverseTable[Byte(T0[3] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[22];
    W0 := InverseTable[Byte(T0[3])];
    W1 := InverseTable[Byte(T0[2] shr 8)];
    W2 := InverseTable[Byte(T0[1] shr 16)];
    W3 := InverseTable[Byte(T0[0] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[23];
    // round 6
    W0 := InverseTable[Byte(T1[0])];
    W1 := InverseTable[Byte(T1[3] shr 8)];
    W2 := InverseTable[Byte(T1[2] shr 16)];
    W3 := InverseTable[Byte(T1[1] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[16];
    W0 := InverseTable[Byte(T1[1])];
    W1 := InverseTable[Byte(T1[0] shr 8)];
    W2 := InverseTable[Byte(T1[3] shr 16)];
    W3 := InverseTable[Byte(T1[2] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[17];
    W0 := InverseTable[Byte(T1[2])];
    W1 := InverseTable[Byte(T1[1] shr 8)];
    W2 := InverseTable[Byte(T1[0] shr 16)];
    W3 := InverseTable[Byte(T1[3] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[18];
    W0 := InverseTable[Byte(T1[3])];
    W1 := InverseTable[Byte(T1[2] shr 8)];
    W2 := InverseTable[Byte(T1[1] shr 16)];
    W3 := InverseTable[Byte(T1[0] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[19];
    // round 7
    W0 := InverseTable[Byte(T0[0])];
    W1 := InverseTable[Byte(T0[3] shr 8)];
    W2 := InverseTable[Byte(T0[2] shr 16)];
    W3 := InverseTable[Byte(T0[1] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[12];
    W0 := InverseTable[Byte(T0[1])];
    W1 := InverseTable[Byte(T0[0] shr 8)];
    W2 := InverseTable[Byte(T0[3] shr 16)];
    W3 := InverseTable[Byte(T0[2] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[13];
    W0 := InverseTable[Byte(T0[2])];
    W1 := InverseTable[Byte(T0[1] shr 8)];
    W2 := InverseTable[Byte(T0[0] shr 16)];
    W3 := InverseTable[Byte(T0[3] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[14];
    W0 := InverseTable[Byte(T0[3])];
    W1 := InverseTable[Byte(T0[2] shr 8)];
    W2 := InverseTable[Byte(T0[1] shr 16)];
    W3 := InverseTable[Byte(T0[0] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[15];
    // round 8
    W0 := InverseTable[Byte(T1[0])];
    W1 := InverseTable[Byte(T1[3] shr 8)];
    W2 := InverseTable[Byte(T1[2] shr 16)];
    W3 := InverseTable[Byte(T1[1] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[8];
    W0 := InverseTable[Byte(T1[1])];
    W1 := InverseTable[Byte(T1[0] shr 8)];
    W2 := InverseTable[Byte(T1[3] shr 16)];
    W3 := InverseTable[Byte(T1[2] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[9];
    W0 := InverseTable[Byte(T1[2])];
    W1 := InverseTable[Byte(T1[1] shr 8)];
    W2 := InverseTable[Byte(T1[0] shr 16)];
    W3 := InverseTable[Byte(T1[3] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[10];
    W0 := InverseTable[Byte(T1[3])];
    W1 := InverseTable[Byte(T1[2] shr 8)];
    W2 := InverseTable[Byte(T1[1] shr 16)];
    W3 := InverseTable[Byte(T1[0] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[11];
    // round 9
    W0 := InverseTable[Byte(T0[0])];
    W1 := InverseTable[Byte(T0[3] shr 8)];
    W2 := InverseTable[Byte(T0[2] shr 16)];
    W3 := InverseTable[Byte(T0[1] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[4];
    W0 := InverseTable[Byte(T0[1])];
    W1 := InverseTable[Byte(T0[0] shr 8)];
    W2 := InverseTable[Byte(T0[3] shr 16)];
    W3 := InverseTable[Byte(T0[2] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[5];
    W0 := InverseTable[Byte(T0[2])];
    W1 := InverseTable[Byte(T0[1] shr 8)];
    W2 := InverseTable[Byte(T0[0] shr 16)];
    W3 := InverseTable[Byte(T0[3] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[6];
    W0 := InverseTable[Byte(T0[3])];
    W1 := InverseTable[Byte(T0[2] shr 8)];
    W2 := InverseTable[Byte(T0[1] shr 16)];
    W3 := InverseTable[Byte(T0[0] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[7];
    // last round of transformations
    W0 := LastInverseTable[Byte(T1[0])];
    W1 := LastInverseTable[Byte(T1[3] shr 8)];
    W2 := LastInverseTable[Byte(T1[2] shr 16)];
    W3 := LastInverseTable[Byte(T1[1] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[0];
    W0 := LastInverseTable[Byte(T1[1])];
    W1 := LastInverseTable[Byte(T1[0] shr 8)];
    W2 := LastInverseTable[Byte(T1[3] shr 16)];
    W3 := LastInverseTable[Byte(T1[2] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[1];
    W0 := LastInverseTable[Byte(T1[2])];
    W1 := LastInverseTable[Byte(T1[1] shr 8)];
    W2 := LastInverseTable[Byte(T1[0] shr 16)];
    W3 := LastInverseTable[Byte(T1[3] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[2];
    W0 := LastInverseTable[Byte(T1[3])];
    W1 := LastInverseTable[Byte(T1[2] shr 8)];
    W2 := LastInverseTable[Byte(T1[1] shr 16)];
    W3 := LastInverseTable[Byte(T1[0] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[3];
    // finalizing
    PLongWord(@OutBuf[0])^ := T0[0];
    PLongWord(@OutBuf[4])^ := T0[1];
    PLongWord(@OutBuf[8])^ := T0[2];
    PLongWord(@OutBuf[12])^ := T0[3];
end;

procedure TAES.DecryptAES(const InBuf: TAESBuffer; const Key: TAESExpandedKey192; var OutBuf: TAESBuffer);
var
    T0, T1: array [0 .. 3] of longword;
    W0, W1, W2, W3: longword;
begin
    // initializing
    T0[0] := PLongWord(@InBuf[0])^ xor Key[48];
    T0[1] := PLongWord(@InBuf[4])^ xor Key[49];
    T0[2] := PLongWord(@InBuf[8])^ xor Key[50];
    T0[3] := PLongWord(@InBuf[12])^ xor Key[51];
    // performing transformations 11 times
    // round 1
    W0 := InverseTable[Byte(T0[0])];
    W1 := InverseTable[Byte(T0[3] shr 8)];
    W2 := InverseTable[Byte(T0[2] shr 16)];
    W3 := InverseTable[Byte(T0[1] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[44];
    W0 := InverseTable[Byte(T0[1])];
    W1 := InverseTable[Byte(T0[0] shr 8)];
    W2 := InverseTable[Byte(T0[3] shr 16)];
    W3 := InverseTable[Byte(T0[2] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[45];
    W0 := InverseTable[Byte(T0[2])];
    W1 := InverseTable[Byte(T0[1] shr 8)];
    W2 := InverseTable[Byte(T0[0] shr 16)];
    W3 := InverseTable[Byte(T0[3] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[46];
    W0 := InverseTable[Byte(T0[3])];
    W1 := InverseTable[Byte(T0[2] shr 8)];
    W2 := InverseTable[Byte(T0[1] shr 16)];
    W3 := InverseTable[Byte(T0[0] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[47];
    // round 2
    W0 := InverseTable[Byte(T1[0])];
    W1 := InverseTable[Byte(T1[3] shr 8)];
    W2 := InverseTable[Byte(T1[2] shr 16)];
    W3 := InverseTable[Byte(T1[1] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[40];
    W0 := InverseTable[Byte(T1[1])];
    W1 := InverseTable[Byte(T1[0] shr 8)];
    W2 := InverseTable[Byte(T1[3] shr 16)];
    W3 := InverseTable[Byte(T1[2] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[41];
    W0 := InverseTable[Byte(T1[2])];
    W1 := InverseTable[Byte(T1[1] shr 8)];
    W2 := InverseTable[Byte(T1[0] shr 16)];
    W3 := InverseTable[Byte(T1[3] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[42];
    W0 := InverseTable[Byte(T1[3])];
    W1 := InverseTable[Byte(T1[2] shr 8)];
    W2 := InverseTable[Byte(T1[1] shr 16)];
    W3 := InverseTable[Byte(T1[0] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[43];
    // round 3
    W0 := InverseTable[Byte(T0[0])];
    W1 := InverseTable[Byte(T0[3] shr 8)];
    W2 := InverseTable[Byte(T0[2] shr 16)];
    W3 := InverseTable[Byte(T0[1] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[36];
    W0 := InverseTable[Byte(T0[1])];
    W1 := InverseTable[Byte(T0[0] shr 8)];
    W2 := InverseTable[Byte(T0[3] shr 16)];
    W3 := InverseTable[Byte(T0[2] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[37];
    W0 := InverseTable[Byte(T0[2])];
    W1 := InverseTable[Byte(T0[1] shr 8)];
    W2 := InverseTable[Byte(T0[0] shr 16)];
    W3 := InverseTable[Byte(T0[3] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[38];
    W0 := InverseTable[Byte(T0[3])];
    W1 := InverseTable[Byte(T0[2] shr 8)];
    W2 := InverseTable[Byte(T0[1] shr 16)];
    W3 := InverseTable[Byte(T0[0] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[39];
    // round 4
    W0 := InverseTable[Byte(T1[0])];
    W1 := InverseTable[Byte(T1[3] shr 8)];
    W2 := InverseTable[Byte(T1[2] shr 16)];
    W3 := InverseTable[Byte(T1[1] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[32];
    W0 := InverseTable[Byte(T1[1])];
    W1 := InverseTable[Byte(T1[0] shr 8)];
    W2 := InverseTable[Byte(T1[3] shr 16)];
    W3 := InverseTable[Byte(T1[2] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[33];
    W0 := InverseTable[Byte(T1[2])];
    W1 := InverseTable[Byte(T1[1] shr 8)];
    W2 := InverseTable[Byte(T1[0] shr 16)];
    W3 := InverseTable[Byte(T1[3] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[34];
    W0 := InverseTable[Byte(T1[3])];
    W1 := InverseTable[Byte(T1[2] shr 8)];
    W2 := InverseTable[Byte(T1[1] shr 16)];
    W3 := InverseTable[Byte(T1[0] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[35];
    // round 5
    W0 := InverseTable[Byte(T0[0])];
    W1 := InverseTable[Byte(T0[3] shr 8)];
    W2 := InverseTable[Byte(T0[2] shr 16)];
    W3 := InverseTable[Byte(T0[1] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[28];
    W0 := InverseTable[Byte(T0[1])];
    W1 := InverseTable[Byte(T0[0] shr 8)];
    W2 := InverseTable[Byte(T0[3] shr 16)];
    W3 := InverseTable[Byte(T0[2] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[29];
    W0 := InverseTable[Byte(T0[2])];
    W1 := InverseTable[Byte(T0[1] shr 8)];
    W2 := InverseTable[Byte(T0[0] shr 16)];
    W3 := InverseTable[Byte(T0[3] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[30];
    W0 := InverseTable[Byte(T0[3])];
    W1 := InverseTable[Byte(T0[2] shr 8)];
    W2 := InverseTable[Byte(T0[1] shr 16)];
    W3 := InverseTable[Byte(T0[0] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[31];
    // round 6
    W0 := InverseTable[Byte(T1[0])];
    W1 := InverseTable[Byte(T1[3] shr 8)];
    W2 := InverseTable[Byte(T1[2] shr 16)];
    W3 := InverseTable[Byte(T1[1] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[24];
    W0 := InverseTable[Byte(T1[1])];
    W1 := InverseTable[Byte(T1[0] shr 8)];
    W2 := InverseTable[Byte(T1[3] shr 16)];
    W3 := InverseTable[Byte(T1[2] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[25];
    W0 := InverseTable[Byte(T1[2])];
    W1 := InverseTable[Byte(T1[1] shr 8)];
    W2 := InverseTable[Byte(T1[0] shr 16)];
    W3 := InverseTable[Byte(T1[3] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[26];
    W0 := InverseTable[Byte(T1[3])];
    W1 := InverseTable[Byte(T1[2] shr 8)];
    W2 := InverseTable[Byte(T1[1] shr 16)];
    W3 := InverseTable[Byte(T1[0] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[27];
    // round 7
    W0 := InverseTable[Byte(T0[0])];
    W1 := InverseTable[Byte(T0[3] shr 8)];
    W2 := InverseTable[Byte(T0[2] shr 16)];
    W3 := InverseTable[Byte(T0[1] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[20];
    W0 := InverseTable[Byte(T0[1])];
    W1 := InverseTable[Byte(T0[0] shr 8)];
    W2 := InverseTable[Byte(T0[3] shr 16)];
    W3 := InverseTable[Byte(T0[2] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[21];
    W0 := InverseTable[Byte(T0[2])];
    W1 := InverseTable[Byte(T0[1] shr 8)];
    W2 := InverseTable[Byte(T0[0] shr 16)];
    W3 := InverseTable[Byte(T0[3] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[22];
    W0 := InverseTable[Byte(T0[3])];
    W1 := InverseTable[Byte(T0[2] shr 8)];
    W2 := InverseTable[Byte(T0[1] shr 16)];
    W3 := InverseTable[Byte(T0[0] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[23];
    // round 8
    W0 := InverseTable[Byte(T1[0])];
    W1 := InverseTable[Byte(T1[3] shr 8)];
    W2 := InverseTable[Byte(T1[2] shr 16)];
    W3 := InverseTable[Byte(T1[1] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[16];
    W0 := InverseTable[Byte(T1[1])];
    W1 := InverseTable[Byte(T1[0] shr 8)];
    W2 := InverseTable[Byte(T1[3] shr 16)];
    W3 := InverseTable[Byte(T1[2] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[17];
    W0 := InverseTable[Byte(T1[2])];
    W1 := InverseTable[Byte(T1[1] shr 8)];
    W2 := InverseTable[Byte(T1[0] shr 16)];
    W3 := InverseTable[Byte(T1[3] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[18];
    W0 := InverseTable[Byte(T1[3])];
    W1 := InverseTable[Byte(T1[2] shr 8)];
    W2 := InverseTable[Byte(T1[1] shr 16)];
    W3 := InverseTable[Byte(T1[0] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[19];
    // round 9
    W0 := InverseTable[Byte(T0[0])];
    W1 := InverseTable[Byte(T0[3] shr 8)];
    W2 := InverseTable[Byte(T0[2] shr 16)];
    W3 := InverseTable[Byte(T0[1] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[12];
    W0 := InverseTable[Byte(T0[1])];
    W1 := InverseTable[Byte(T0[0] shr 8)];
    W2 := InverseTable[Byte(T0[3] shr 16)];
    W3 := InverseTable[Byte(T0[2] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[13];
    W0 := InverseTable[Byte(T0[2])];
    W1 := InverseTable[Byte(T0[1] shr 8)];
    W2 := InverseTable[Byte(T0[0] shr 16)];
    W3 := InverseTable[Byte(T0[3] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[14];
    W0 := InverseTable[Byte(T0[3])];
    W1 := InverseTable[Byte(T0[2] shr 8)];
    W2 := InverseTable[Byte(T0[1] shr 16)];
    W3 := InverseTable[Byte(T0[0] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[15];
    // round 10
    W0 := InverseTable[Byte(T1[0])];
    W1 := InverseTable[Byte(T1[3] shr 8)];
    W2 := InverseTable[Byte(T1[2] shr 16)];
    W3 := InverseTable[Byte(T1[1] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[8];
    W0 := InverseTable[Byte(T1[1])];
    W1 := InverseTable[Byte(T1[0] shr 8)];
    W2 := InverseTable[Byte(T1[3] shr 16)];
    W3 := InverseTable[Byte(T1[2] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[9];
    W0 := InverseTable[Byte(T1[2])];
    W1 := InverseTable[Byte(T1[1] shr 8)];
    W2 := InverseTable[Byte(T1[0] shr 16)];
    W3 := InverseTable[Byte(T1[3] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[10];
    W0 := InverseTable[Byte(T1[3])];
    W1 := InverseTable[Byte(T1[2] shr 8)];
    W2 := InverseTable[Byte(T1[1] shr 16)];
    W3 := InverseTable[Byte(T1[0] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[11];
    // round 11
    W0 := InverseTable[Byte(T0[0])];
    W1 := InverseTable[Byte(T0[3] shr 8)];
    W2 := InverseTable[Byte(T0[2] shr 16)];
    W3 := InverseTable[Byte(T0[1] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[4];
    W0 := InverseTable[Byte(T0[1])];
    W1 := InverseTable[Byte(T0[0] shr 8)];
    W2 := InverseTable[Byte(T0[3] shr 16)];
    W3 := InverseTable[Byte(T0[2] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[5];
    W0 := InverseTable[Byte(T0[2])];
    W1 := InverseTable[Byte(T0[1] shr 8)];
    W2 := InverseTable[Byte(T0[0] shr 16)];
    W3 := InverseTable[Byte(T0[3] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[6];
    W0 := InverseTable[Byte(T0[3])];
    W1 := InverseTable[Byte(T0[2] shr 8)];
    W2 := InverseTable[Byte(T0[1] shr 16)];
    W3 := InverseTable[Byte(T0[0] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[7];
    // last round of transformations
    W0 := LastInverseTable[Byte(T1[0])];
    W1 := LastInverseTable[Byte(T1[3] shr 8)];
    W2 := LastInverseTable[Byte(T1[2] shr 16)];
    W3 := LastInverseTable[Byte(T1[1] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[0];
    W0 := LastInverseTable[Byte(T1[1])];
    W1 := LastInverseTable[Byte(T1[0] shr 8)];
    W2 := LastInverseTable[Byte(T1[3] shr 16)];
    W3 := LastInverseTable[Byte(T1[2] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[1];
    W0 := LastInverseTable[Byte(T1[2])];
    W1 := LastInverseTable[Byte(T1[1] shr 8)];
    W2 := LastInverseTable[Byte(T1[0] shr 16)];
    W3 := LastInverseTable[Byte(T1[3] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[2];
    W0 := LastInverseTable[Byte(T1[3])];
    W1 := LastInverseTable[Byte(T1[2] shr 8)];
    W2 := LastInverseTable[Byte(T1[1] shr 16)];
    W3 := LastInverseTable[Byte(T1[0] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[3];
    // finalizing
    PLongWord(@OutBuf[0])^ := T0[0];
    PLongWord(@OutBuf[4])^ := T0[1];
    PLongWord(@OutBuf[8])^ := T0[2];
    PLongWord(@OutBuf[12])^ := T0[3];
end;

procedure TAES.DecryptAES(const InBuf: TAESBuffer; const Key: TAESExpandedKey256; var OutBuf: TAESBuffer);
var
    T0, T1: array [0 .. 3] of longword;
    W0, W1, W2, W3: longword;
begin
    // initializing
    T0[0] := PLongWord(@InBuf[0])^ xor Key[56];
    T0[1] := PLongWord(@InBuf[4])^ xor Key[57];
    T0[2] := PLongWord(@InBuf[8])^ xor Key[58];
    T0[3] := PLongWord(@InBuf[12])^ xor Key[59];
    // performing transformations 13 times
    // round 1
    W0 := InverseTable[Byte(T0[0])];
    W1 := InverseTable[Byte(T0[3] shr 8)];
    W2 := InverseTable[Byte(T0[2] shr 16)];
    W3 := InverseTable[Byte(T0[1] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[52];
    W0 := InverseTable[Byte(T0[1])];
    W1 := InverseTable[Byte(T0[0] shr 8)];
    W2 := InverseTable[Byte(T0[3] shr 16)];
    W3 := InverseTable[Byte(T0[2] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[53];
    W0 := InverseTable[Byte(T0[2])];
    W1 := InverseTable[Byte(T0[1] shr 8)];
    W2 := InverseTable[Byte(T0[0] shr 16)];
    W3 := InverseTable[Byte(T0[3] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[54];
    W0 := InverseTable[Byte(T0[3])];
    W1 := InverseTable[Byte(T0[2] shr 8)];
    W2 := InverseTable[Byte(T0[1] shr 16)];
    W3 := InverseTable[Byte(T0[0] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[55];
    // round 2
    W0 := InverseTable[Byte(T1[0])];
    W1 := InverseTable[Byte(T1[3] shr 8)];
    W2 := InverseTable[Byte(T1[2] shr 16)];
    W3 := InverseTable[Byte(T1[1] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[48];
    W0 := InverseTable[Byte(T1[1])];
    W1 := InverseTable[Byte(T1[0] shr 8)];
    W2 := InverseTable[Byte(T1[3] shr 16)];
    W3 := InverseTable[Byte(T1[2] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[49];
    W0 := InverseTable[Byte(T1[2])];
    W1 := InverseTable[Byte(T1[1] shr 8)];
    W2 := InverseTable[Byte(T1[0] shr 16)];
    W3 := InverseTable[Byte(T1[3] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[50];
    W0 := InverseTable[Byte(T1[3])];
    W1 := InverseTable[Byte(T1[2] shr 8)];
    W2 := InverseTable[Byte(T1[1] shr 16)];
    W3 := InverseTable[Byte(T1[0] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[51];
    // round 3
    W0 := InverseTable[Byte(T0[0])];
    W1 := InverseTable[Byte(T0[3] shr 8)];
    W2 := InverseTable[Byte(T0[2] shr 16)];
    W3 := InverseTable[Byte(T0[1] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[44];
    W0 := InverseTable[Byte(T0[1])];
    W1 := InverseTable[Byte(T0[0] shr 8)];
    W2 := InverseTable[Byte(T0[3] shr 16)];
    W3 := InverseTable[Byte(T0[2] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[45];
    W0 := InverseTable[Byte(T0[2])];
    W1 := InverseTable[Byte(T0[1] shr 8)];
    W2 := InverseTable[Byte(T0[0] shr 16)];
    W3 := InverseTable[Byte(T0[3] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[46];
    W0 := InverseTable[Byte(T0[3])];
    W1 := InverseTable[Byte(T0[2] shr 8)];
    W2 := InverseTable[Byte(T0[1] shr 16)];
    W3 := InverseTable[Byte(T0[0] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[47];
    // round 4
    W0 := InverseTable[Byte(T1[0])];
    W1 := InverseTable[Byte(T1[3] shr 8)];
    W2 := InverseTable[Byte(T1[2] shr 16)];
    W3 := InverseTable[Byte(T1[1] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[40];
    W0 := InverseTable[Byte(T1[1])];
    W1 := InverseTable[Byte(T1[0] shr 8)];
    W2 := InverseTable[Byte(T1[3] shr 16)];
    W3 := InverseTable[Byte(T1[2] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[41];
    W0 := InverseTable[Byte(T1[2])];
    W1 := InverseTable[Byte(T1[1] shr 8)];
    W2 := InverseTable[Byte(T1[0] shr 16)];
    W3 := InverseTable[Byte(T1[3] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[42];
    W0 := InverseTable[Byte(T1[3])];
    W1 := InverseTable[Byte(T1[2] shr 8)];
    W2 := InverseTable[Byte(T1[1] shr 16)];
    W3 := InverseTable[Byte(T1[0] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[43];
    // round 5
    W0 := InverseTable[Byte(T0[0])];
    W1 := InverseTable[Byte(T0[3] shr 8)];
    W2 := InverseTable[Byte(T0[2] shr 16)];
    W3 := InverseTable[Byte(T0[1] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[36];
    W0 := InverseTable[Byte(T0[1])];
    W1 := InverseTable[Byte(T0[0] shr 8)];
    W2 := InverseTable[Byte(T0[3] shr 16)];
    W3 := InverseTable[Byte(T0[2] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[37];
    W0 := InverseTable[Byte(T0[2])];
    W1 := InverseTable[Byte(T0[1] shr 8)];
    W2 := InverseTable[Byte(T0[0] shr 16)];
    W3 := InverseTable[Byte(T0[3] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[38];
    W0 := InverseTable[Byte(T0[3])];
    W1 := InverseTable[Byte(T0[2] shr 8)];
    W2 := InverseTable[Byte(T0[1] shr 16)];
    W3 := InverseTable[Byte(T0[0] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[39];
    // round 6
    W0 := InverseTable[Byte(T1[0])];
    W1 := InverseTable[Byte(T1[3] shr 8)];
    W2 := InverseTable[Byte(T1[2] shr 16)];
    W3 := InverseTable[Byte(T1[1] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[32];
    W0 := InverseTable[Byte(T1[1])];
    W1 := InverseTable[Byte(T1[0] shr 8)];
    W2 := InverseTable[Byte(T1[3] shr 16)];
    W3 := InverseTable[Byte(T1[2] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[33];
    W0 := InverseTable[Byte(T1[2])];
    W1 := InverseTable[Byte(T1[1] shr 8)];
    W2 := InverseTable[Byte(T1[0] shr 16)];
    W3 := InverseTable[Byte(T1[3] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[34];
    W0 := InverseTable[Byte(T1[3])];
    W1 := InverseTable[Byte(T1[2] shr 8)];
    W2 := InverseTable[Byte(T1[1] shr 16)];
    W3 := InverseTable[Byte(T1[0] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[35];
    // round 7
    W0 := InverseTable[Byte(T0[0])];
    W1 := InverseTable[Byte(T0[3] shr 8)];
    W2 := InverseTable[Byte(T0[2] shr 16)];
    W3 := InverseTable[Byte(T0[1] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[28];
    W0 := InverseTable[Byte(T0[1])];
    W1 := InverseTable[Byte(T0[0] shr 8)];
    W2 := InverseTable[Byte(T0[3] shr 16)];
    W3 := InverseTable[Byte(T0[2] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[29];
    W0 := InverseTable[Byte(T0[2])];
    W1 := InverseTable[Byte(T0[1] shr 8)];
    W2 := InverseTable[Byte(T0[0] shr 16)];
    W3 := InverseTable[Byte(T0[3] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[30];
    W0 := InverseTable[Byte(T0[3])];
    W1 := InverseTable[Byte(T0[2] shr 8)];
    W2 := InverseTable[Byte(T0[1] shr 16)];
    W3 := InverseTable[Byte(T0[0] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[31];
    // round 8
    W0 := InverseTable[Byte(T1[0])];
    W1 := InverseTable[Byte(T1[3] shr 8)];
    W2 := InverseTable[Byte(T1[2] shr 16)];
    W3 := InverseTable[Byte(T1[1] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[24];
    W0 := InverseTable[Byte(T1[1])];
    W1 := InverseTable[Byte(T1[0] shr 8)];
    W2 := InverseTable[Byte(T1[3] shr 16)];
    W3 := InverseTable[Byte(T1[2] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[25];
    W0 := InverseTable[Byte(T1[2])];
    W1 := InverseTable[Byte(T1[1] shr 8)];
    W2 := InverseTable[Byte(T1[0] shr 16)];
    W3 := InverseTable[Byte(T1[3] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[26];
    W0 := InverseTable[Byte(T1[3])];
    W1 := InverseTable[Byte(T1[2] shr 8)];
    W2 := InverseTable[Byte(T1[1] shr 16)];
    W3 := InverseTable[Byte(T1[0] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[27];
    // round 9
    W0 := InverseTable[Byte(T0[0])];
    W1 := InverseTable[Byte(T0[3] shr 8)];
    W2 := InverseTable[Byte(T0[2] shr 16)];
    W3 := InverseTable[Byte(T0[1] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[20];
    W0 := InverseTable[Byte(T0[1])];
    W1 := InverseTable[Byte(T0[0] shr 8)];
    W2 := InverseTable[Byte(T0[3] shr 16)];
    W3 := InverseTable[Byte(T0[2] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[21];
    W0 := InverseTable[Byte(T0[2])];
    W1 := InverseTable[Byte(T0[1] shr 8)];
    W2 := InverseTable[Byte(T0[0] shr 16)];
    W3 := InverseTable[Byte(T0[3] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[22];
    W0 := InverseTable[Byte(T0[3])];
    W1 := InverseTable[Byte(T0[2] shr 8)];
    W2 := InverseTable[Byte(T0[1] shr 16)];
    W3 := InverseTable[Byte(T0[0] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[23];
    // round 10
    W0 := InverseTable[Byte(T1[0])];
    W1 := InverseTable[Byte(T1[3] shr 8)];
    W2 := InverseTable[Byte(T1[2] shr 16)];
    W3 := InverseTable[Byte(T1[1] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[16];
    W0 := InverseTable[Byte(T1[1])];
    W1 := InverseTable[Byte(T1[0] shr 8)];
    W2 := InverseTable[Byte(T1[3] shr 16)];
    W3 := InverseTable[Byte(T1[2] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[17];
    W0 := InverseTable[Byte(T1[2])];
    W1 := InverseTable[Byte(T1[1] shr 8)];
    W2 := InverseTable[Byte(T1[0] shr 16)];
    W3 := InverseTable[Byte(T1[3] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[18];
    W0 := InverseTable[Byte(T1[3])];
    W1 := InverseTable[Byte(T1[2] shr 8)];
    W2 := InverseTable[Byte(T1[1] shr 16)];
    W3 := InverseTable[Byte(T1[0] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[19];
    // round 11
    W0 := InverseTable[Byte(T0[0])];
    W1 := InverseTable[Byte(T0[3] shr 8)];
    W2 := InverseTable[Byte(T0[2] shr 16)];
    W3 := InverseTable[Byte(T0[1] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[12];
    W0 := InverseTable[Byte(T0[1])];
    W1 := InverseTable[Byte(T0[0] shr 8)];
    W2 := InverseTable[Byte(T0[3] shr 16)];
    W3 := InverseTable[Byte(T0[2] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[13];
    W0 := InverseTable[Byte(T0[2])];
    W1 := InverseTable[Byte(T0[1] shr 8)];
    W2 := InverseTable[Byte(T0[0] shr 16)];
    W3 := InverseTable[Byte(T0[3] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[14];
    W0 := InverseTable[Byte(T0[3])];
    W1 := InverseTable[Byte(T0[2] shr 8)];
    W2 := InverseTable[Byte(T0[1] shr 16)];
    W3 := InverseTable[Byte(T0[0] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[15];
    // round 12
    W0 := InverseTable[Byte(T1[0])];
    W1 := InverseTable[Byte(T1[3] shr 8)];
    W2 := InverseTable[Byte(T1[2] shr 16)];
    W3 := InverseTable[Byte(T1[1] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[8];
    W0 := InverseTable[Byte(T1[1])];
    W1 := InverseTable[Byte(T1[0] shr 8)];
    W2 := InverseTable[Byte(T1[3] shr 16)];
    W3 := InverseTable[Byte(T1[2] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[9];
    W0 := InverseTable[Byte(T1[2])];
    W1 := InverseTable[Byte(T1[1] shr 8)];
    W2 := InverseTable[Byte(T1[0] shr 16)];
    W3 := InverseTable[Byte(T1[3] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[10];
    W0 := InverseTable[Byte(T1[3])];
    W1 := InverseTable[Byte(T1[2] shr 8)];
    W2 := InverseTable[Byte(T1[1] shr 16)];
    W3 := InverseTable[Byte(T1[0] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[11];
    // round 13
    W0 := InverseTable[Byte(T0[0])];
    W1 := InverseTable[Byte(T0[3] shr 8)];
    W2 := InverseTable[Byte(T0[2] shr 16)];
    W3 := InverseTable[Byte(T0[1] shr 24)];
    T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[4];
    W0 := InverseTable[Byte(T0[1])];
    W1 := InverseTable[Byte(T0[0] shr 8)];
    W2 := InverseTable[Byte(T0[3] shr 16)];
    W3 := InverseTable[Byte(T0[2] shr 24)];
    T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[5];
    W0 := InverseTable[Byte(T0[2])];
    W1 := InverseTable[Byte(T0[1] shr 8)];
    W2 := InverseTable[Byte(T0[0] shr 16)];
    W3 := InverseTable[Byte(T0[3] shr 24)];
    T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[6];
    W0 := InverseTable[Byte(T0[3])];
    W1 := InverseTable[Byte(T0[2] shr 8)];
    W2 := InverseTable[Byte(T0[1] shr 16)];
    W3 := InverseTable[Byte(T0[0] shr 24)];
    T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[7];
    // last round of transformations
    W0 := LastInverseTable[Byte(T1[0])];
    W1 := LastInverseTable[Byte(T1[3] shr 8)];
    W2 := LastInverseTable[Byte(T1[2] shr 16)];
    W3 := LastInverseTable[Byte(T1[1] shr 24)];
    T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[0];
    W0 := LastInverseTable[Byte(T1[1])];
    W1 := LastInverseTable[Byte(T1[0] shr 8)];
    W2 := LastInverseTable[Byte(T1[3] shr 16)];
    W3 := LastInverseTable[Byte(T1[2] shr 24)];
    T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[1];
    W0 := LastInverseTable[Byte(T1[2])];
    W1 := LastInverseTable[Byte(T1[1] shr 8)];
    W2 := LastInverseTable[Byte(T1[0] shr 16)];
    W3 := LastInverseTable[Byte(T1[3] shr 24)];
    T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[2];
    W0 := LastInverseTable[Byte(T1[3])];
    W1 := LastInverseTable[Byte(T1[2] shr 8)];
    W2 := LastInverseTable[Byte(T1[1] shr 16)];
    W3 := LastInverseTable[Byte(T1[0] shr 24)];
    T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8)))
      xor Key[3];
    // finalizing
    PLongWord(@OutBuf[0])^ := T0[0];
    PLongWord(@OutBuf[4])^ := T0[1];
    PLongWord(@OutBuf[8])^ := T0[2];
    PLongWord(@OutBuf[12])^ := T0[3];
end;

procedure TAES.FormatKey_Encrypt(const Key: Ansistring; const KeyBit: TKeyBit; AESKey128: TAESKey128;
  AESKey192: TAESKey192; AESKey256: TAESKey256; var ExpandedKey128: TAESExpandedKey128;
  var ExpandedKey192: TAESExpandedKey192; var ExpandedKey256: TAESExpandedKey256);
begin
    // kb128, kb192, kb256
    if KeyBit = KB128 then begin
        FillChar(AESKey128, SizeOf(AESKey128), 0);
        Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key)));
        ExpandAESKeyForEncryption(AESKey128, ExpandedKey128);
    end;

    if KeyBit = KB192 then begin
        FillChar(AESKey192, SizeOf(AESKey192), 0);
        Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key)));
        ExpandAESKeyForEncryption(AESKey192, ExpandedKey192);
    end;

    if KeyBit = KB256 then begin
        FillChar(AESKey256, SizeOf(AESKey256), 0);
        Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key)));
        ExpandAESKeyForEncryption(AESKey256, ExpandedKey256);
    end;
end;

procedure TAES.FormatKey_Decrypt(const Key: Ansistring; const KeyBit: TKeyBit; AESKey128: TAESKey128;
  AESKey192: TAESKey192; AESKey256: TAESKey256; var ExpandedKey128: TAESExpandedKey128;
  var ExpandedKey192: TAESExpandedKey192; var ExpandedKey256: TAESExpandedKey256);
begin
    // kb128, kb192, kb256
    if KeyBit = KB128 then begin
        FillChar(AESKey128, SizeOf(AESKey128), 0);
        Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key)));
        ExpandAESKeyForDecryption(AESKey128, ExpandedKey128);
    end;

    if KeyBit = KB192 then begin
        FillChar(AESKey192, SizeOf(AESKey192), 0);
        Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key)));
        ExpandAESKeyForDecryption(AESKey192, ExpandedKey192);
    end;

    if KeyBit = KB256 then begin
        FillChar(AESKey256, SizeOf(AESKey256), 0);
        Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key)));
        ExpandAESKeyForDecryption(AESKey256, ExpandedKey256);
    end;
end;

procedure TAES.EncryptAESStreamCBC(Source, Dest: TStream; Count: Int64; const InitVector: TAESBuffer; Key: Ansistring;
  KeyBit: TKeyBit = KB128);
var
    AESKey128: TAESKey128;
    AESKey192: TAESKey192;
    AESKey256: TAESKey256;

    ExpandedKey128: TAESExpandedKey128;
    ExpandedKey192: TAESExpandedKey192;
    ExpandedKey256: TAESExpandedKey256;

    TempIn, TempOut, Vector: TAESBuffer;
    Done: Int64;
begin
    if Count = 0 then
        Count := Source.Size - Source.Position;
    if (Count = 0) or (Count > Source.Size - Source.Position) then
        Exit;
    Vector := InitVector;

    // kb128, kb192, kb256
    FormatKey_Encrypt(Key, KeyBit, AESKey128, AESKey192, AESKey256, ExpandedKey128, ExpandedKey192, ExpandedKey256);

    while Count >= SizeOf(TAESBuffer) do begin
        Done := Source.Read(TempIn[0], SizeOf(TempIn));
        if Done < SizeOf(TempIn) then
            raise EStreamError.Create(SReadError);
        PLongWord(@TempIn[0])^ := PLongWord(@TempIn[0])^ xor PLongWord(@Vector[0])^;
        PLongWord(@TempIn[4])^ := PLongWord(@TempIn[4])^ xor PLongWord(@Vector[4])^;
        PLongWord(@TempIn[8])^ := PLongWord(@TempIn[8])^ xor PLongWord(@Vector[8])^;
        PLongWord(@TempIn[12])^ := PLongWord(@TempIn[12])^ xor PLongWord(@Vector[12])^;

        if KeyBit = KB128 then
            EncryptAES(TempIn, ExpandedKey128, TempOut);
        if KeyBit = KB192 then
            EncryptAES(TempIn, ExpandedKey192, TempOut);
        if KeyBit = KB256 then
            EncryptAES(TempIn, ExpandedKey256, TempOut);

        Done := Dest.Write(TempOut, SizeOf(TempOut));
        if Done < SizeOf(TempOut) then
            raise EStreamError.Create(SWriteError);
        Vector := TempOut;
        Dec(Count, SizeOf(TAESBuffer));
    end;

    if Count > 0 then begin
        Done := Source.Read(TempIn, Count);
        if Done < Count then
            raise EStreamError.Create(SReadError);
        FillChar(TempIn[Count], SizeOf(TAESBuffer) - Count, 0);
        PLongWord(@TempIn[0])^ := PLongWord(@TempIn[0])^ xor PLongWord(@Vector[0])^;
        PLongWord(@TempIn[4])^ := PLongWord(@TempIn[4])^ xor PLongWord(@Vector[4])^;
        PLongWord(@TempIn[8])^ := PLongWord(@TempIn[8])^ xor PLongWord(@Vector[8])^;
        PLongWord(@TempIn[12])^ := PLongWord(@TempIn[12])^ xor PLongWord(@Vector[12])^;

        if KeyBit = KB128 then
            EncryptAES(TempIn, ExpandedKey128, TempOut);
        if KeyBit = KB192 then
            EncryptAES(TempIn, ExpandedKey192, TempOut);
        if KeyBit = KB256 then
            EncryptAES(TempIn, ExpandedKey256, TempOut);

        Done := Dest.Write(TempOut[0], SizeOf(TempOut));
        if Done < SizeOf(TempOut) then
            raise EStreamError.Create(SWriteError);
    end;
end;

procedure TAES.DecryptAESStreamCBC(Source, Dest: TStream; Count: Int64; const InitVector: TAESBuffer; Key: Ansistring;
  KeyBit: TKeyBit = KB128);
var
    AESKey128: TAESKey128;
    AESKey192: TAESKey192;
    AESKey256: TAESKey256;

    ExpandedKey128: TAESExpandedKey128;
    ExpandedKey192: TAESExpandedKey192;
    ExpandedKey256: TAESExpandedKey256;

    TempIn, TempOut: TAESBuffer;
    Vector1, Vector2: TAESBuffer;
    Done: Int64;
begin
    if Count = 0 then
        Count := Source.Size - Source.Position;
    if (Count = 0) or (Count > Source.Size - Source.Position) then
        Exit;
    if (Count mod SizeOf(TAESBuffer)) > 0 then
        raise EAESError.Create(SInvalidInBufSize);

    FormatKey_Decrypt(Key, KeyBit, AESKey128, AESKey192, AESKey256, ExpandedKey128, ExpandedKey192, ExpandedKey256);

    Vector1 := InitVector;
    while Count >= SizeOf(TAESBuffer) do begin
        Done := Source.Read(TempIn[0], SizeOf(TempIn));
        if Done < SizeOf(TempIn) then
            raise EStreamError(SReadError);
        Vector2 := TempIn;

        if KeyBit = KB128 then
            DecryptAES(TempIn, ExpandedKey128, TempOut);
        if KeyBit = KB192 then
            DecryptAES(TempIn, ExpandedKey192, TempOut);
        if KeyBit = KB256 then
            DecryptAES(TempIn, ExpandedKey256, TempOut);

        PLongWord(@TempOut[0])^ := PLongWord(@TempOut[0])^ xor PLongWord(@Vector1[0])^;
        PLongWord(@TempOut[4])^ := PLongWord(@TempOut[4])^ xor PLongWord(@Vector1[4])^;
        PLongWord(@TempOut[8])^ := PLongWord(@TempOut[8])^ xor PLongWord(@Vector1[8])^;
        PLongWord(@TempOut[12])^ := PLongWord(@TempOut[12])^ xor PLongWord(@Vector1[12])^;
        Done := Dest.Write(TempOut[0], SizeOf(TempOut));
        if Done < SizeOf(TempOut) then
            raise EStreamError(SWriteError);
        Vector1 := Vector2;
        Dec(Count, SizeOf(TAESBuffer));
    end;
end;

function TAES.StrToHex(Value: Ansistring): string;
begin
    SetLength(Result, 2 * Length(Value));
    BinToHex(PAnsiChar(Value), PChar(Result), Length(Value));
end;

function TAES.HexToStr(Value: string): Ansistring;
begin
    SetLength(Result, Length(Value) div 2);
    HexToBin(PChar(Value), PAnsiChar(Result), Length(Value));
end;

function EncryptStr_CBC(Value, Key: string; InitVector: TAESBuffer; KeyBit: TKeyBit = KB256;
  IsUtf8Encode: Boolean = False): string;

const
    Convert: array [0 .. 15] of WideChar = '0123456789ABCDEF';
var
    Source, Dest: TBytesStream;
    Aes: TAES;
    I: Integer;
    P: PAnsiChar;
    Bt: Byte;
    KeyBytes, InRaws: Ansistring;

begin
    Result := '';
    if Value = '' then
        Exit;

    Source := TBytesStream.Create();
    Dest := TBytesStream.Create();
    Aes := TAES.Create();
    try
        // utf8 编码
        if IsUtf8Encode then begin
            InRaws := Utf8Encode(Value);
            KeyBytes := Utf8Encode(Key);
        end
        else begin
            InRaws := Ansistring(Value);
            KeyBytes := Ansistring(Key);
        end;
        //
        Source.Write(InRaws[1], Length(InRaws));
        Source.Position := 0;
        try
            Aes.EncryptAESStreamCBC(Source, Dest, Source.Size, InitVector, KeyBytes, KeyBit);
            //
            Dest.Position := 0;
            P := PAnsiChar(Dest.Memory);
            //
            SetLength(Result, 2 * Dest.Size);
            for I := 0 to Dest.Size - 1 do begin
                Bt := Byte(P^);
                Result[I * 2 + 1] := Convert[Bt shr 4];
                Result[I * 2 + 2] := Convert[Bt and $F];
                Inc(P);
            end;
        except
        end;
    finally
        Aes.Free();
        Dest.Free();
        Source.Free();
    end;
end;

//
function DecryptStr_CBC(Value, Key: string; InitVector: TAESBuffer; KeyBit: TKeyBit = KB256;
  IsUtf8Decode: Boolean = False): string;
var
    Source, Dest: TStream;
    Aes: TAES;
    S: Ansistring;
    OutRaws, KeyBytes: Ansistring;

begin
    Result := '';
    if Value = '' then
        Exit;

    Source := TMemoryStream.Create();
    Dest := TMemoryStream.Create();
    Aes := TAES.Create();
    try
        KeyBytes := Utf8Encode(Key);
        if IsUtf8Decode then
            KeyBytes := Utf8Encode(Key)
        else
            KeyBytes := Ansistring(Key);

        //
        SetLength(S, Length(Value) div 2);
        HexToBin(PChar(Value), PAnsiChar(S), Length(Value));
        //
        Source.Write(S[1], Length(S));
        Source.Position := 0;
        try
            Aes.DecryptAESStreamCBC(Source, Dest, Source.Size, InitVector, KeyBytes, KeyBit);
            //
            Dest.Position := 0;
            SetLength(OutRaws, Dest.Size);
            Dest.Read(OutRaws[1], Dest.Size);
            //
            if IsUtf8Decode then
                Result := Utf8ToWideString(OutRaws)
            else
                Result := string(OutRaws);
        except
        end;
    finally
        Aes.Free();
        Dest.Free();
        Source.Free();
    end;
end;

end.
 

//工程调用代码如下:
program Project1;

{$APPTYPE CONSOLE}
{$R *.res}

uses
    System.SysUtils,
    ElAES in 'ElAES.pas';

const
    // 初始化向量  = 1234567890ABCDEF
    InitVector: TAESBuffer = (49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 65, 66, 67, 68, 69, 70);

procedure Test();
var
    S, S2: string;
begin
    // 加密
    S := EncryptStr_CBC('多可文档管理系统', '2018201820182018', InitVector, KB128, True);
    Writeln(S);
    // 解密
    S2 := DecryptStr_CBC(S, '2018201820182018', InitVector, KB128, True);
    Writeln(S2);
end;

begin
    try
        Test();
    except
        on E: Exception do
            Writeln(E.ClassName, ': ', E.Message);
    end;
end.