我目前正在测试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;
答案 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单元测试。我无法给出时间表。