Delphi Firemonkey LockBox3 AES-CBC, ПК и Android результат отличается? - PullRequest
0 голосов
/ 01 января 2019

Мне нужна библиотека AES для Devolop Firemonkey Moblie App.Я тестировал ElAES и LockBox3, все отлично работает на ПК, но на FMX Android обе библиотеки возвращают неверный зашифрованный текст.

Тестовые данные (AES128CBC PKCS5Padding):

plainText: 'plainText'  - edtPlaintext.Text
key: '0000000000000000' - edtKey.Text
IV: '0000000000000000' - edtIV.Text
cipherText:  hex - 'DD0A2A20616162697B8B4DF53483F1D2',
             base64 - '3QoqIGFhYml7i031NIPx0g==' 

Тестовый код:

Это проверка кода на LockBox3, связанная с: https://github.com/TurboPack/LockBox3, функция 'EncryptMemory' каждый раз возвращает нефиксированный зашифрованный текст на Android, что-то нужно заметить?

uses uTPLb_Codec, uTPLb_CryptographicLibrary, uTPLb_Constants, uTPLb_StreamUtils;

type
  TCustomPadder = class(TObject)
  private
    FIV: TBytes;
  public
    constructor Create(const AIV: TBytes);
    procedure OnSetIV(Value: TMemoryStream);
  end;

constructor TCustomPadder.Create(const AIV: TBytes);
begin
  FIV := AIV
end;

procedure TCustomPadder.OnSetIV(Value: TMemoryStream);
begin
  Value.Size := Length(FIV);
  Value.Position := 0;
  Value.WriteBuffer(FIV, Length(FIV))
end;

function NewCodec(key: TBytes): TCodec;
var
  codec: TCodec;
  cryptographicLibrary: TCryptographicLibrary;
  keyStream: TStream;
  padder: TCustomPadder;
begin
  cryptographicLibrary := TCryptographicLibrary.Create(nil);
  // basic
  codec := TCodec.Create(nil);
  codec.BlockCipherId := Format(AES_ProgId, [128]);
  codec.ChainModeId := CBC_ProgId;
  codec.CryptoLibrary := cryptographicLibrary;
  codec.StreamCipherId := BlockCipher_ProgId;
  // extend
  padder := TCustomPadder.Create(bytesof('0000000000000000'));
  keyStream := TMemoryStream.Create;
  keyStream.WriteBuffer(key, Length(key));
  keyStream.Position := 0;
  codec.OnSetIV := padder.OnSetIV;
  codec.InitFromStream(keyStream);
  result := codec;
end;

function PKCS5Padding(ciphertext: string; blocksize: integer): string;
var
  builder: TStringBuilder;
  padding: integer;
  i: integer;
begin
  builder := TStringBuilder.Create(ciphertext);
  padding := blocksize - (builder.Length mod blocksize);
  for i := 1 to padding do
  begin
    builder.Append(Char(padding));
  end;
  result := builder.ToString;
  builder.DisposeOf;
end;

function BytesToHexStr(bytes: TBytes): string;
var
  i: integer;
begin
  result := '';
  for i := 0 to Length(bytes) - 1 do
    result := result + bytes[i].ToHexString(2);
end;

procedure TformAEST.btnEncryptClick(Sender: TObject);
var
  codec: TCodec;
  plainBytes, cipherBytes: TBytes;
  cipherMemory: TStream;
  cipherBytesLen: integer;
begin

  cipherMemory := TMemoryStream.Create;

  plainBytes := bytesof(PKCS5Padding(edtPlaintext.Text, 16));

  codec := NewCodec(bytesof(edtKey.Text));
  codec.Begin_EncryptMemory(cipherMemory);
  codec.EncryptMemory(plainBytes, Length(plainBytes));
  codec.End_EncryptMemory;

  cipherMemory.Position := 8;
  cipherBytesLen := cipherMemory.Size - 8;
  SetLength(cipherBytes, cipherBytesLen);
  cipherMemory.ReadBuffer(cipherBytes, cipherBytesLen);
  edtCiphertext.Text := BytesToHexStr(cipherBytes);
end;

1 Ответ

0 голосов
/ 01 января 2019

Шифрование и дешифрование работают с необработанными байтами, а не с символами.

При шифровании строк Unicode, особенно на разных платформах, необходимо кодировать символы в байты, используя согласованное байтовое кодирование передзатем шифрование этих байтов.

И при дешифровании строк Unicode обязательно используйте ту же самую кодировку байтов при преобразовании расшифрованных байтов обратно в символы.

В вашем коде вы используете BytesOf() для кодирования символов Юникода в байты.Внутренне BytesOf() использует TEncoding.Default в качестве кодировки, которая TEncoding.ANSI на ПК с Windows, но TEncoding.UTF8 на других платформах.Таким образом, если ваши входные строки содержат не-ASCII-символы, вы получите другие результаты.

Я предлагаю заменить BytesOf() на TEncoding.UTF8.GetBytes() на всех платформах:

plainBytes := TEncoding.UTF8.GetBytes(PKCS5Padding(edtPlaintext.Text, 16));

codec := NewCodec(TEncoding.UTF8.GetBytes(edtKey.Text));
...