1

我目前正在测试 Lockbox3,并且在尝试使用 XXTEA 密码进行简单的字符串加密和解密时遇到了问题。我正在使用 Delphi 10.1 Berlin 并使用 GetIt 安装了最新版本的 Lockbox3!我的测试应用程序针对 Win32 (VCL)。

问题是加密工作正常,但是当我尝试解密字符串时,抛出异常:“目标多字节代码页中不存在 Unicode 字符的映射。”。我不确定是什么问题?

procedure TForm1.btnEncryptClick(Sender: TObject);
var
    PlainText : string;
   CipherText : string;
    CryptoLib : TCryptographicLibrary;
        Codec : TCodec;
begin
    try
      CryptoLib := TCryptographicLibrary.Create(nil);
      Codec := TCodec.Create(nil);
      Codec.CryptoLibrary := CryptoLib;
      Codec.StreamCipherId := 'native.XXTEA.Large.Littleend';
      Codec.ChainMode := 'native.CBC';
      Codec.Password := 'password';
      PlainText := Edit1.Text;
      Codec.EncryptString( PlainText, CipherText, Tencoding.UTF8 );
      Codec.Burn;
    finally
      Codec.Free;
      CryptoLib.Free;
      Edit2.Text := CipherText;
    end;
end;

procedure TForm1.btnDecryptClick(Sender: TObject);
var
     PlainText : string;
    CipherText : string;
     CryptoLib : TCryptographicLibrary;
         Codec : TCodec;
begin
    try
      CryptoLib := TCryptographicLibrary.Create(nil);
      Codec := TCodec.Create(nil);
      Codec.CryptoLibrary := CryptoLib;
      Codec.StreamCipherId := 'native.XXTEA.Large.Littleend';
      Codec.ChainMode := 'native.CBC';
      Codec.Password := 'password';
      CipherText := Edit2.Text;
      Codec.DecryptString( PlainText, CipherText, Tencoding.UTF8 );
      Codec.Burn;
    finally
      Codec.Free;
      CryptoLib.Free;
      Edit1.Text := PlainText;
    end;
end;
4

1 回答 1

1

有两个问题。首先是XXTEA解密器存在缺陷。如果您等不及发布修复程序,我已经发布了一个代码增量,您可以应用并重新编译以获得即时解决方案。我有点惊讶 XXTEA 没有单元测试。这个库中的其他所有东西都有大量的单元测试,所以我也会努力。

第二个问题是在运行时设置的编解码器属性名称与设计时属性名称略有不同。(ChainModeId不是ChainMode)。不同之处在于使设计时属性配置更容易。

无论如何,我在 Lockbox-3 v3.7.0 上做了一些测试。主页可以在http://lockbox.seanbdurkin.id.au/HomePage找到,源代码来自https://github.com/SeanBDurkin/tplockbox。我用 Delphi 10.2 Tokyo 测试过;目标=Win32。

清单 1 给出了测试程序(一个单文件控制台程序),清单 2 给出了修复程序。该修复是对方法过程 TXXTEA_LargeBlock_LE_Decryptor.End_Decrypt() 的更新,可以在单元 TPLB3.XXTEA 中找到。GetIt 版本的单位名称会略有不同。话虽如此,对于 XXTEA,等到单元测试发布后可能会更安全。

此外,如果有人想通过贡献已知答案测试 (KAT) 来提供帮助,那对所有人都有好处。

清单一:一个测试程序

program TestLockBox;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  TPLB3.CryptographicLibrary,
  TPLB3.Codec,
  TPLB3.Random,
  TPLB3.Constants;

var
  sMessage: string;
  sCipher: string;
  sRecon: string;

const
      CipherId    = XXTEA_Large_ProgId;  IsBlockMode = False;
  //  CipherId    = Twofish_ProgId;      IsBlockMode = True;
  ChainMode   = 'native.CBC';
  Password    = 'password';
  Seed        = 1;

function TForm1_btnEncryptClick( const sPlainText: string): string;
var
    PlainText : string;
   CipherText : string;
    CryptoLib : TCryptographicLibrary;
        Codec : TCodec;
begin
    try
      CryptoLib := TCryptographicLibrary.Create(nil);
      Codec := TCodec.Create(nil);
      Codec.CryptoLibrary := CryptoLib;
      if IsBlockMode then
          begin
          Codec.StreamCipherId := BlockCipher_ProgId;
          Codec.BlockCipherId  := CipherId
          end
        else
          Codec.StreamCipherId := CipherId;
      Codec.ChainModeId    := ChainMode;
      Codec.Password := Password;
      PlainText := sPlainText;
      Codec.EncryptString( PlainText, CipherText, Tencoding.UTF8 );
      Codec.Burn;
    finally
      Codec.Free;
      CryptoLib.Free;
      result := CipherText;
    end;
end;

function TForm1_btnDecryptClick( const sCipherText: string): string;
var
     PlainText : string;
    CipherText : string;
     CryptoLib : TCryptographicLibrary;
         Codec : TCodec;
begin
    try
      CryptoLib := TCryptographicLibrary.Create(nil);
      Codec := TCodec.Create(nil);
      Codec.CryptoLibrary := CryptoLib;
      if IsBlockMode then
          begin
          Codec.StreamCipherId := BlockCipher_ProgId;
          Codec.BlockCipherId  := CipherId
          end
        else
          Codec.StreamCipherId := CipherId;
      Codec.ChainModeId    := ChainMode;
      Codec.Password := Password;
      CipherText := sCipherText;
      Codec.DecryptString( PlainText, CipherText, Tencoding.UTF8 );
      Codec.Burn;
    finally
      Codec.Free;
      CryptoLib.Free;
      result := PlainText;
    end;
end;

begin
  if Seed = -1 then
      TRandomStream.Instance.Randomize
    else
      TRandomStream.Instance.Seed := Seed;
  try
    sMessage := 'Your lips are smoother than vasoline.';
    WriteLn( 'Plaintext="' + sMessage + '"');
    sCipher  := TForm1_btnEncryptClick( sMessage);
    WriteLn( 'Base64 representation of ciphertext=' + sCipher);
    sRecon := TForm1_btnDecryptClick( sCipher);
    WriteLn( 'The reconstructed plaintext = "' + sRecon + '"');
    if sMessage = sRecon then
        WriteLn( 'Test result = PASS')
      else
        WriteLn( 'Test result = FAIL')
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  WriteLn('Press Enter to close the program.');
  ReadLn;
end.

清单二:修复

procedure TXXTEA_LargeBlock_LE_Decryptor.End_Decrypt;
var
  RequiredSizeDecrease: integer;
  L: integer;
  PlaintextArray, CiphertextArray: TLongWordDynArray;
begin
if FisBuffering then
    begin
    if FBufLen = 0 then exit;
//    c <= 211 ==>
//      2.2.1 Decrypt the message as one XXTEA block.
//      2.2.2 De-salt the decrypted plaintext. That is to say discard the last
//        8 bytes at the head of the decrypted plaintext.
//      2.2.3 De-pad the message out at the tail. The number of pad bytes to
//        remove is the value of the last byte.
    L := FBufLen div 4;
    SetLength( CiphertextArray, L); // Setup longword array.
    SetLength( PlaintextArray , L);
      begin
      // XXTEA only valid if blocksize is at least 2 longwords.
      // With the padding, this should ALWAYS be the case.
      // Otherwise the ciphertext message is invalid.
      Move( FBuffer[0], CiphertextArray[0], FBufLen); // Convert padded message to longwords.
      XXTEA_Decrypt( FKey.FNativeKey, CiphertextArray, PlaintextArray); // One-block encryption.
      end;
    FBufLen := L * 4;
    if FBufLen >= 8 then
        Dec( FBufLen, 8) // de-salt
      else
        FBufLen := 0;
    if FBufLen > 0 then  // Calculate pad.
        begin
        if Length( FBuffer) < FBufLen then
          SetLength( FBuffer, FBufLen);
        Move( PlaintextArray[0], FBuffer[0], FBufLen);
        RequiredSizeDecrease := FBuffer[FBufLen-1]
        end
      else
        RequiredSizeDecrease := 0;
    if FBufLen >= RequiredSizeDecrease then
        Dec( FBufLen, RequiredSizeDecrease) // de-pad
      else
        FBufLen := 0;
    if FBufLen > 0 then
      FPlainText.Write( FBuffer[0], FBufLen)
    end
  else
    begin
    FFixedDec.End_Decrypt;
    FOutputBuffer.EndStreaming; // Discard last 12 bytes
    FreeAndNil( FOutputBuffer)
    end;
FFixedDec := nil;
FFixedCipher := nil
end;

下一个版本将是 3.8.0,将包括 XXTEA 修复和 XXTEA 单元测试。我不能给它一个时间表。

于 2017-08-07T12:59:09.860 回答