无法使用LockBox3解密XXTEA加密字符串

时间:2017-08-04 16:00:14

标签: delphi encryption vcl lockbox-3

我目前正在测试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;

1 个答案:

答案 0 :(得分:1)

有两个问题。首先是XXTEA解密器存在缺陷。如果您不能等待修复发布,我已经发布了一个代码增量,您可以应用并重新编译以立即解决。我对XXTEA没有单元测试感到有点惊讶。这个库中的其他所有内容都有大量的单元测试,所以我也会对此进行研究。

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

无论如何,我在Lockbox-3 v3.7.0上做了一些测试。主页可以在http://lockbox.seanbdurkin.id.au/HomePage找到,源代码可以在https://github.com/SeanBDurkin/tplockbox找到。我用Delphi 10.2东京进行了测试;目标=的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单元测试。我无法给出时间表。