代码之家  ›  专栏  ›  技术社区  ›  Adriaan Jutte

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

  •  1
  • Adriaan Jutte  · 技术社区  · 9 年前

    我目前正在测试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 回复  |  直到 9 年前
        1
  •  1
  •   Sean B. Durkin    8 年前

    有两个问题。首先,XXTEA解密程序中存在缺陷。如果您迫不及待地想发布修复程序,我已经发布了一个代码增量,您可以应用它并重新编译以获得即时解决方案。我有点惊讶,XXTEA没有单元测试。这个库中的其他所有内容都有大量的单元测试,所以我也将致力于此。

    ChainModeId ChainMode ). 这种差异是为了使设计时属性配置更容易。

    http://lockbox.seanbdurkin.id.au/HomePage 源代码来自 https://github.com/SeanBDurkin/tplockbox .我用Delphi 10.2 Tokyo进行了测试;目标=Win32。

    此外,如果有人想通过贡献已知答案测试(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;
    

    推荐文章