Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/234.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php Delphi(FMX):Windows中的DCPCrypt2在Android/IOS中产生不同的结果_Php_Delphi_Encryption_Openssl_Rawbytestring - Fatal编程技术网

Php Delphi(FMX):Windows中的DCPCrypt2在Android/IOS中产生不同的结果

Php Delphi(FMX):Windows中的DCPCrypt2在Android/IOS中产生不同的结果,php,delphi,encryption,openssl,rawbytestring,Php,Delphi,Encryption,Openssl,Rawbytestring,我正在尝试编写一个函数,该函数在Delphi(RAD Studio 10.2)中返回与PHP中的以下代码相同的结果: <?php $method = 'AES-256-CTR'; $data = 'Hello, world!'; $key = 'bRuD5WYw5wd0rdHR9yLlM6wt2vteuini'; $vector = 'bf49ea9d61104d8c'; $crypt = openssl_encrypt($data, $method, $key, 0

我正在尝试编写一个函数,该函数在Delphi(RAD Studio 10.2)中返回与PHP中的以下代码相同的结果:

<?php
  $method = 'AES-256-CTR';
  $data = 'Hello, world!';
  $key = 'bRuD5WYw5wd0rdHR9yLlM6wt2vteuini';
  $vector = 'bf49ea9d61104d8c'; 
  $crypt = openssl_encrypt($data, $method, $key, 0, $vector);
  echo $crypt;
?>
事实上,这是可行的(在Windows中)。PHP和Pascal都返回:
pEP16OOxov9QDfraIg==

然而,如果我为Android编译相同的代码并在我的平板电脑上运行,我会得到一个非常不同的结果。为什么呢


我确实读过关于为fmx转换代码的文档,特别是关于字符串处理的文档,但我仍然不明白为什么。即使RawByteString是基于0而不是基于1的,我仍然会得到一个不同点(尝试使用[0]而不是[1])。RawByTestString没有附加代码页,对吗?所以这个问题不可能是由字符串转换引起的(我认为)。这是怎么回事?

Android字符串从位置0开始。您可以使用
low(Data)
返回字符串的第一个字符,库内部也使用位置1的字符串,该字符串不会在android或ios中运行。对于多平台,我们不应该对i:=1到长度(字符串)使用
,而应该对字符串中的l使用


我想我应该解决你的问题

在做了三天之后,我终于让它开始工作了。关键是完全消除字符串的使用,只在DCPCrypt中使用基于TBytes的例程。 下面的代码是一个测试程序,用于测试DCPCrypt支持的所有不同链接模式。我还添加了一个函数,该函数实现了我在这里找到的四种填充模式(用于CBC和ECB): 以及零填充和随机填充。 我选择不使用DCPCrypt自己的Base64函数,因为它们与FMX不兼容。相反,我使用System.NetEncoding单元中的对应项。 拜托,我认为自己只是一个普通的程序员,所以我希望真正的德尔菲沃兹在你们中间找到很多批评意见。不过没关系。如果有好的反馈,我会修改代码。 正如现在一样,代码可以工作并生成与PHP的openssl函数兼容的结果(使用CTR模式测试)。我只是在这里发布这篇文章,希望它可能对寻找与我相同的解决方案的人有用

    unit MainUnit;

    interface

    uses
      System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, System.NetEncoding,
      FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls, FMX.Layouts,
      FMX.ScrollBox, FMX.Memo, FMX.Edit, FMX.Controls.Presentation,
      DCPcrypt2, DCPsha256, DCPblockciphers, DCPrijndael;

    type
      TChainingMode = (cmCBC, cmCFB8bit, cmCFBblock, cmOFB, cmCTR, cmECB);
      TPaddingMode = (pmZeroPadding, pmANSIX923, pmISO10126, pmISO7816, pmPKCS7, pmRandomPadding);

    type
      TMainForm = class(TForm)
        ScrollBox: TScrollBox;
        KeySizeLabel: TLabel;
        ChainingLabel: TLabel;
        EncodingLabel: TLabel;
        PaddingLabel: TLabel;
        KeyLabel: TLabel;
        InitVectorLabel: TLabel;
        DataLabel: TLabel;
        DecryptedLabel: TLabel;
        CipherLabel: TLabel;
        EncryptedLabel: TLabel;
        rbRijndael: TRadioButton;
        rb128bit: TRadioButton;
        rb256bit: TRadioButton;
        rbANSI: TRadioButton;
        rbUTF8: TRadioButton;
        rbUnicode: TRadioButton;
        rbCBC: TRadioButton;
        rbOFB: TRadioButton;
        rbCTR: TRadioButton;
        rbECB: TRadioButton;
        rbCFB8bit: TRadioButton;
        rbCFBblock: TRadioButton;
        rbZeroPadding: TRadioButton;
        rbANSIX923: TRadioButton;
        rbISO10126: TRadioButton;
        rbISO7816: TRadioButton;
        rbPKCS7: TRadioButton;
        rbRandomPadding: TRadioButton;
        KeyEdit: TEdit;
        InitVectorEdit: TEdit;
        DataMemo: TMemo;
        EncryptedMemo: TMemo;
        DecryptedMemo: TMemo;
        EncryptButton: TButton;
        DecryptButton: TButton;
        procedure FormCreate(Sender: TObject);
        procedure EncryptButtonClick(Sender: TObject);
        procedure DecryptButtonClick(Sender: TObject);
      public
        procedure GetOptions(var Key: TBytes; var KeySize: integer; var InitVector: TBytes;
                  var Encoding: TEncoding; var ChainingMode: TChainingMode; var PaddingMode: TPaddingMode);
      end;

    var
      MainForm: TMainForm;

    implementation

    {$R *.fmx}
    {$R *.LgXhdpiPh.fmx ANDROID}

    function BytesToHex(B: TBytes): string;
    var
      I: integer;
    begin
      Result := '';
      for I := Low(B) to High(B) do Result := Result + IntToHex(B[I]) + ' ';
    end;

    procedure BytePadding(var Data: TBytes; BlockSize: integer; PaddingMode: TPaddingMode);
    // Supports: ANSI X.923, ISO 10126, ISO 7816, PKCS7, zero padding and random padding
    var
      I, DataBlocks, DataLength, PaddingStart, PaddingCount: integer;
    begin
      BlockSize := BlockSize div 8; // convert bits to bytes
      // Zero and Random padding do not use end-markers, so if Length(Data) is a multiple of BlockSize, no padding is needed
      if PaddingMode in [pmZeroPadding, pmRandomPadding] then
        if Length(Data) mod BlockSize = 0 then Exit;
      DataBlocks := (Length(Data) div BlockSize) + 1;
      DataLength := DataBlocks * BlockSize;
      PaddingCount := DataLength - Length(Data);
      // ANSIX923, ISO10126 and PKCS7 store the padding length in a 1 byte end-marker, so any padding length > $FF is not supported
      if PaddingMode in [pmANSIX923, pmISO10126, pmPKCS7] then
        if PaddingCount > $FF then Exit;
      PaddingStart := Length(Data);
      SetLength(Data, DataLength);
      case PaddingMode of
        pmZeroPadding, pmANSIX923, pmISO7816: // fill with $00 bytes
          FillChar(Data[PaddingStart], PaddingCount, 0);
        pmPKCS7: // fill with PaddingCount bytes
          FillChar(Data[PaddingStart], PaddingCount, PaddingCount);
        pmRandomPadding, pmISO10126: // fill with random bytes
          for I := PaddingStart to DataLength-1 do Data[I] := Random($FF);
      end;
      case PaddingMode of
        pmANSIX923, pmISO10126:
          Data[DataLength-1] := PaddingCount; // set end-marker with number of bytes added
        pmISO7816:
          Data[PaddingStart] := $80; // set fixed end-markder $80
      end;
    end;

    procedure EncryptAES(const Data: TBytes; var Crypt: TBytes; const Key: TBytes; KeySize: integer;
        const InitVector: TBytes; ChainingMode: TChainingMode; PaddingMode: TPaddingMode); overload;
    var
      Cipher: TDCP_rijndael;
    begin
      Cipher := TDCP_rijndael.Create(nil);
      try
        Cipher.Init(Key[0], KeySize, @InitVector[0]);
        // Copy Data => Crypt
        Crypt := Copy(Data, 0, Length(Data));
        // Padd Crypt to required length (for Block based algorithms)
        if ChainingMode in [cmCBC, cmECB] then
          BytePadding(Crypt, Cipher.BlockSize, PaddingMode);
        // Encrypt Crypt using the algorithm specified in ChainingMode
        case ChainingMode of
          cmCBC: Cipher.EncryptCBC(Crypt[0], Crypt[0], Length(Crypt));
          cmCFB8bit: Cipher.EncryptCFB8bit(Crypt[0], Crypt[0], Length(Crypt));
          cmCFBblock: Cipher.EncryptCFBblock(Crypt[0], Crypt[0], Length(Crypt));
          cmOFB: Cipher.EncryptOFB(Crypt[0], Crypt[0], Length(Crypt));
          cmCTR: Cipher.EncryptCTR(Crypt[0], Crypt[0], Length(Crypt));
          cmECB: Cipher.EncryptECB(Crypt[0], Crypt[0]);
        end;

      finally
        Cipher.Free;
      end;
    end;

    procedure DecryptAES(const Crypt: TBytes; var Data: TBytes; const Key: TBytes; KeySize: integer;
        const InitVector: TBytes; ChainingMode: TChainingMode; PaddingMode: TPaddingMode); overload;
    var
      Cipher: TDCP_rijndael;
      I: integer;
    begin
      Cipher := TDCP_rijndael.Create(nil);
      try
        Cipher.Init(Key[0], KeySize, @InitVector[0]);
        // Copy Crypt => Data
        Data := Copy(Crypt, 0, Length(Crypt));
        // Decrypt Data using the algorithm specified in ChainingMode
        case ChainingMode of
          cmCBC: Cipher.DecryptCBC(Data[0], Data[0], Length(Data));
          cmCFB8bit: Cipher.DecryptCFB8bit(Data[0], Data[0], Length(Data));
          cmCFBblock: Cipher.DecryptCFBblock(Data[0], Data[0], Length(Data));
          cmOFB: Cipher.DecryptOFB(Data[0], Data[0], Length(Data));
          cmCTR: Cipher.DecryptCTR(Data[0], Data[0], Length(Data));
          cmECB: Cipher.DecryptECB(Data[0], Data[0]);
        end;
        // Correct the length of Data, based on the used PaddingMode (only for Block based algorithms)
        if ChainingMode in [cmCBC, cmECB] then
          case PaddingMode of
            pmANSIX923, pmISO10126, pmPKCS7: // these modes store the original Padding count in the last byte
              SetLength(Data, Length(Data) - Data[Length(Data)-1]);
            pmISO7816: // this mode uses a fixed end-marker. Find it and correct length accordingly.
              for I := Length(Data)-1 downto 0 do
                if Data[I] = $80 then
                begin
                  SetLength(Data, I);
                  Break;
                end;
          end;

      finally
        Cipher.Free;
      end;
    end;

    procedure TMainForm.FormCreate(Sender: TObject);
    begin
      EncryptedMemo.Lines.Clear;
      DecryptedMemo.Lines.Clear;
    end;

    procedure TMainForm.GetOptions(var Key: TBytes; var KeySize: integer; var InitVector: TBytes;
              var Encoding: TEncoding; var ChainingMode: TChainingMode; var PaddingMode: TPaddingMode);
    begin
      KeySize := 256;
      Encoding := TEncoding.ANSI;
      ChainingMode := cmCBC;
      PaddingMode := pmPKCS7;

      if rb128bit.IsChecked then KeySize := 128;
      if rb256bit.IsChecked then KeySize := 256;

      if rbCBC.IsChecked then ChainingMode := cmCBC;
      if rbCFB8bit.IsChecked then ChainingMode := cmCFB8bit;
      if rbCFBblock.IsChecked then ChainingMode := cmCFBblock;
      if rbOFB.IsChecked then ChainingMode := cmOFB;
      if rbCTR.IsChecked then ChainingMode := cmCTR;
      if rbECB.IsChecked then ChainingMode := cmECB;

      if rbZeroPadding.IsChecked then PaddingMode := pmZeroPadding;
      if rbANSIX923.IsChecked then PaddingMode := pmANSIX923;
      if rbISO10126.IsChecked then PaddingMode := pmISO10126;
      if rbISO7816.IsChecked then PaddingMode := pmISO7816;
      if rbPKCS7.IsChecked then PaddingMode := pmPKCS7;
      if rbRandomPadding.IsChecked then PaddingMode := pmRandomPadding;

      if rbANSI.IsChecked then Encoding := TEncoding.ANSI;
      if rbUTF8.IsChecked then Encoding := TEncoding.UTF8;
      if rbUnicode.IsChecked then Encoding := TEncoding.Unicode;

      Key := Encoding.GetBytes(KeyEdit.Text);
      InitVector := Encoding.GetBytes(InitVectorEdit.Text);
    end;

    procedure TMainForm.EncryptButtonClick(Sender: TObject);
    var
      Keysize: integer;
      Encoding: TEncoding;
      ChainingMode: TChainingMode;
      PaddingMode: TPaddingMode;
      Key, InitVector, Data, Crypt: TBytes;
    begin
      GetOptions(Key, KeySize, InitVector, Encoding, ChainingMode, PaddingMode);
      Data := Encoding.GetBytes(DataMemo.Text);
      EncryptAES(Data, Crypt, Key, KeySize, InitVector, ChainingMode, PaddingMode);
      EncryptedMemo.Text := TNetEncoding.Base64.EncodeBytesToString(Crypt);
    end;

    procedure TMainForm.DecryptButtonClick(Sender: TObject);
    var
      Keysize: integer;
      Encoding: TEncoding;
      ChainingMode: TChainingMode;
      PaddingMode: TPaddingMode;
      Key, InitVector, Data, Crypt: TBytes;
    begin
      GetOptions(Key, KeySize, InitVector, Encoding, ChainingMode, PaddingMode);
      Crypt := TNetEncoding.Base64.DecodeStringToBytes(EncryptedMemo.Text);
      DecryptAES(Crypt, Data, Key, KeySize, InitVector, ChainingMode, PaddingMode);
      DecryptedMemo.Text := Encoding.GetString(Data);
    end;

    end.

选择一种文本编码,并明确说明它1。您是否尝试使用指针(键)指针(数据)而不是键[1],数据[1]?2.另外,请检查Crypt的内容-问题可能与base64转换有关。谢谢Kohull的评论!我确实读过Android/IOS中的0偏移量字符串。这就是我尝试[0]而不是[1]的原因。但这并没有解决问题。我现在明白为什么了。DCPcrypt在内部仍然假定字符串的偏移量为1。所以这是行不通的…所以我在所有DCPcrypt单元中添加了{$ZEROBASEDSTRINGS OFF},希望这能起到作用。不幸的是,事实并非如此。所以我有两个选择:1。检查所有DCPcrypt代码,使其与Android/IOS或2兼容。查找另一个可以执行AES 256编码的库。从选项2开始,您是否知道有一个库或单元可以进行AES 256编码,并且与Android/IOS兼容?Hi Kohull。谢谢你的帮助!我确实看了锁箱,以及我发现的许多其他锁箱。一旦你开始寻找,你会发现很多。但他们都有一些问题。最后,我求助于调整我的代码以使用DCPCrypt。我现在可以在Win32/64以及IOS和Android上的FMX中使用它了。我将在单独的消息中发布代码。
    unit MainUnit;

    interface

    uses
      System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, System.NetEncoding,
      FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls, FMX.Layouts,
      FMX.ScrollBox, FMX.Memo, FMX.Edit, FMX.Controls.Presentation,
      DCPcrypt2, DCPsha256, DCPblockciphers, DCPrijndael;

    type
      TChainingMode = (cmCBC, cmCFB8bit, cmCFBblock, cmOFB, cmCTR, cmECB);
      TPaddingMode = (pmZeroPadding, pmANSIX923, pmISO10126, pmISO7816, pmPKCS7, pmRandomPadding);

    type
      TMainForm = class(TForm)
        ScrollBox: TScrollBox;
        KeySizeLabel: TLabel;
        ChainingLabel: TLabel;
        EncodingLabel: TLabel;
        PaddingLabel: TLabel;
        KeyLabel: TLabel;
        InitVectorLabel: TLabel;
        DataLabel: TLabel;
        DecryptedLabel: TLabel;
        CipherLabel: TLabel;
        EncryptedLabel: TLabel;
        rbRijndael: TRadioButton;
        rb128bit: TRadioButton;
        rb256bit: TRadioButton;
        rbANSI: TRadioButton;
        rbUTF8: TRadioButton;
        rbUnicode: TRadioButton;
        rbCBC: TRadioButton;
        rbOFB: TRadioButton;
        rbCTR: TRadioButton;
        rbECB: TRadioButton;
        rbCFB8bit: TRadioButton;
        rbCFBblock: TRadioButton;
        rbZeroPadding: TRadioButton;
        rbANSIX923: TRadioButton;
        rbISO10126: TRadioButton;
        rbISO7816: TRadioButton;
        rbPKCS7: TRadioButton;
        rbRandomPadding: TRadioButton;
        KeyEdit: TEdit;
        InitVectorEdit: TEdit;
        DataMemo: TMemo;
        EncryptedMemo: TMemo;
        DecryptedMemo: TMemo;
        EncryptButton: TButton;
        DecryptButton: TButton;
        procedure FormCreate(Sender: TObject);
        procedure EncryptButtonClick(Sender: TObject);
        procedure DecryptButtonClick(Sender: TObject);
      public
        procedure GetOptions(var Key: TBytes; var KeySize: integer; var InitVector: TBytes;
                  var Encoding: TEncoding; var ChainingMode: TChainingMode; var PaddingMode: TPaddingMode);
      end;

    var
      MainForm: TMainForm;

    implementation

    {$R *.fmx}
    {$R *.LgXhdpiPh.fmx ANDROID}

    function BytesToHex(B: TBytes): string;
    var
      I: integer;
    begin
      Result := '';
      for I := Low(B) to High(B) do Result := Result + IntToHex(B[I]) + ' ';
    end;

    procedure BytePadding(var Data: TBytes; BlockSize: integer; PaddingMode: TPaddingMode);
    // Supports: ANSI X.923, ISO 10126, ISO 7816, PKCS7, zero padding and random padding
    var
      I, DataBlocks, DataLength, PaddingStart, PaddingCount: integer;
    begin
      BlockSize := BlockSize div 8; // convert bits to bytes
      // Zero and Random padding do not use end-markers, so if Length(Data) is a multiple of BlockSize, no padding is needed
      if PaddingMode in [pmZeroPadding, pmRandomPadding] then
        if Length(Data) mod BlockSize = 0 then Exit;
      DataBlocks := (Length(Data) div BlockSize) + 1;
      DataLength := DataBlocks * BlockSize;
      PaddingCount := DataLength - Length(Data);
      // ANSIX923, ISO10126 and PKCS7 store the padding length in a 1 byte end-marker, so any padding length > $FF is not supported
      if PaddingMode in [pmANSIX923, pmISO10126, pmPKCS7] then
        if PaddingCount > $FF then Exit;
      PaddingStart := Length(Data);
      SetLength(Data, DataLength);
      case PaddingMode of
        pmZeroPadding, pmANSIX923, pmISO7816: // fill with $00 bytes
          FillChar(Data[PaddingStart], PaddingCount, 0);
        pmPKCS7: // fill with PaddingCount bytes
          FillChar(Data[PaddingStart], PaddingCount, PaddingCount);
        pmRandomPadding, pmISO10126: // fill with random bytes
          for I := PaddingStart to DataLength-1 do Data[I] := Random($FF);
      end;
      case PaddingMode of
        pmANSIX923, pmISO10126:
          Data[DataLength-1] := PaddingCount; // set end-marker with number of bytes added
        pmISO7816:
          Data[PaddingStart] := $80; // set fixed end-markder $80
      end;
    end;

    procedure EncryptAES(const Data: TBytes; var Crypt: TBytes; const Key: TBytes; KeySize: integer;
        const InitVector: TBytes; ChainingMode: TChainingMode; PaddingMode: TPaddingMode); overload;
    var
      Cipher: TDCP_rijndael;
    begin
      Cipher := TDCP_rijndael.Create(nil);
      try
        Cipher.Init(Key[0], KeySize, @InitVector[0]);
        // Copy Data => Crypt
        Crypt := Copy(Data, 0, Length(Data));
        // Padd Crypt to required length (for Block based algorithms)
        if ChainingMode in [cmCBC, cmECB] then
          BytePadding(Crypt, Cipher.BlockSize, PaddingMode);
        // Encrypt Crypt using the algorithm specified in ChainingMode
        case ChainingMode of
          cmCBC: Cipher.EncryptCBC(Crypt[0], Crypt[0], Length(Crypt));
          cmCFB8bit: Cipher.EncryptCFB8bit(Crypt[0], Crypt[0], Length(Crypt));
          cmCFBblock: Cipher.EncryptCFBblock(Crypt[0], Crypt[0], Length(Crypt));
          cmOFB: Cipher.EncryptOFB(Crypt[0], Crypt[0], Length(Crypt));
          cmCTR: Cipher.EncryptCTR(Crypt[0], Crypt[0], Length(Crypt));
          cmECB: Cipher.EncryptECB(Crypt[0], Crypt[0]);
        end;

      finally
        Cipher.Free;
      end;
    end;

    procedure DecryptAES(const Crypt: TBytes; var Data: TBytes; const Key: TBytes; KeySize: integer;
        const InitVector: TBytes; ChainingMode: TChainingMode; PaddingMode: TPaddingMode); overload;
    var
      Cipher: TDCP_rijndael;
      I: integer;
    begin
      Cipher := TDCP_rijndael.Create(nil);
      try
        Cipher.Init(Key[0], KeySize, @InitVector[0]);
        // Copy Crypt => Data
        Data := Copy(Crypt, 0, Length(Crypt));
        // Decrypt Data using the algorithm specified in ChainingMode
        case ChainingMode of
          cmCBC: Cipher.DecryptCBC(Data[0], Data[0], Length(Data));
          cmCFB8bit: Cipher.DecryptCFB8bit(Data[0], Data[0], Length(Data));
          cmCFBblock: Cipher.DecryptCFBblock(Data[0], Data[0], Length(Data));
          cmOFB: Cipher.DecryptOFB(Data[0], Data[0], Length(Data));
          cmCTR: Cipher.DecryptCTR(Data[0], Data[0], Length(Data));
          cmECB: Cipher.DecryptECB(Data[0], Data[0]);
        end;
        // Correct the length of Data, based on the used PaddingMode (only for Block based algorithms)
        if ChainingMode in [cmCBC, cmECB] then
          case PaddingMode of
            pmANSIX923, pmISO10126, pmPKCS7: // these modes store the original Padding count in the last byte
              SetLength(Data, Length(Data) - Data[Length(Data)-1]);
            pmISO7816: // this mode uses a fixed end-marker. Find it and correct length accordingly.
              for I := Length(Data)-1 downto 0 do
                if Data[I] = $80 then
                begin
                  SetLength(Data, I);
                  Break;
                end;
          end;

      finally
        Cipher.Free;
      end;
    end;

    procedure TMainForm.FormCreate(Sender: TObject);
    begin
      EncryptedMemo.Lines.Clear;
      DecryptedMemo.Lines.Clear;
    end;

    procedure TMainForm.GetOptions(var Key: TBytes; var KeySize: integer; var InitVector: TBytes;
              var Encoding: TEncoding; var ChainingMode: TChainingMode; var PaddingMode: TPaddingMode);
    begin
      KeySize := 256;
      Encoding := TEncoding.ANSI;
      ChainingMode := cmCBC;
      PaddingMode := pmPKCS7;

      if rb128bit.IsChecked then KeySize := 128;
      if rb256bit.IsChecked then KeySize := 256;

      if rbCBC.IsChecked then ChainingMode := cmCBC;
      if rbCFB8bit.IsChecked then ChainingMode := cmCFB8bit;
      if rbCFBblock.IsChecked then ChainingMode := cmCFBblock;
      if rbOFB.IsChecked then ChainingMode := cmOFB;
      if rbCTR.IsChecked then ChainingMode := cmCTR;
      if rbECB.IsChecked then ChainingMode := cmECB;

      if rbZeroPadding.IsChecked then PaddingMode := pmZeroPadding;
      if rbANSIX923.IsChecked then PaddingMode := pmANSIX923;
      if rbISO10126.IsChecked then PaddingMode := pmISO10126;
      if rbISO7816.IsChecked then PaddingMode := pmISO7816;
      if rbPKCS7.IsChecked then PaddingMode := pmPKCS7;
      if rbRandomPadding.IsChecked then PaddingMode := pmRandomPadding;

      if rbANSI.IsChecked then Encoding := TEncoding.ANSI;
      if rbUTF8.IsChecked then Encoding := TEncoding.UTF8;
      if rbUnicode.IsChecked then Encoding := TEncoding.Unicode;

      Key := Encoding.GetBytes(KeyEdit.Text);
      InitVector := Encoding.GetBytes(InitVectorEdit.Text);
    end;

    procedure TMainForm.EncryptButtonClick(Sender: TObject);
    var
      Keysize: integer;
      Encoding: TEncoding;
      ChainingMode: TChainingMode;
      PaddingMode: TPaddingMode;
      Key, InitVector, Data, Crypt: TBytes;
    begin
      GetOptions(Key, KeySize, InitVector, Encoding, ChainingMode, PaddingMode);
      Data := Encoding.GetBytes(DataMemo.Text);
      EncryptAES(Data, Crypt, Key, KeySize, InitVector, ChainingMode, PaddingMode);
      EncryptedMemo.Text := TNetEncoding.Base64.EncodeBytesToString(Crypt);
    end;

    procedure TMainForm.DecryptButtonClick(Sender: TObject);
    var
      Keysize: integer;
      Encoding: TEncoding;
      ChainingMode: TChainingMode;
      PaddingMode: TPaddingMode;
      Key, InitVector, Data, Crypt: TBytes;
    begin
      GetOptions(Key, KeySize, InitVector, Encoding, ChainingMode, PaddingMode);
      Crypt := TNetEncoding.Base64.DecodeStringToBytes(EncryptedMemo.Text);
      DecryptAES(Crypt, Data, Key, KeySize, InitVector, ChainingMode, PaddingMode);
      DecryptedMemo.Text := Encoding.GetString(Data);
    end;

    end.