有两个问题。首先是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 单元测试。我不能给它一个时间表。