我为一个奇怪的现象奋斗了好几个小时。首先,我使用的是TurboPower LockBox v10加密库(使用TLbRijndael
),但我不认为这是问题所在。我需要向加密/解密函数传递一个密钥,所以我自然地创建了这样的函数:
function EncryptText(const S: String; const Key: String): String;
function DecryptText(const S: String; const Key: String): String;
奇怪的是,虽然加密 * 似乎 * 工作,当我试图解密,它返回完整的垃圾。所以,在我长达数小时的挖掘之旅中,我发现了绝对令我困惑的原因。当我使用定义为常量的加密密钥时,一切都正常工作。但是在函数中传递完全相同的值(也就是system.string
)作为参数时,它就不这样做了。
总结一下:
- 当把key作为常量(
system.string
)传递时,一切正常。 - 当密钥作为参数(
system.string
)传递时,结果是随机的和不正确的(并且解密失败)。
下面是一个演示,我把它放在一起来展示发生了什么(我的第三个测试应用程序试图弄清楚这一点):
program EncDecDemo;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.Classes, System.SysUtils,
LbCipher, LbClass, LbAsym, LbRSA;
const
ENC_KEY = 'abcdefghijklmnopqrstubwxyz123456';
var
EncComp: TLbRijndael;
function EncAsConst(const S: String): String;
begin
EncComp.SetKey(ENC_KEY); //<-- works as expected
Result:= EncComp.EncryptString(S);
end;
function DecAsConst(const S: String): String;
begin
EncComp.SetKey(ENC_KEY); //<-- works as expected
Result:= EncComp.DecryptString(S);
end;
function EncAsParam(const S: String; const Key: String): String;
begin
EncComp.SetKey(Key); //<-- produces random results
Result:= EncComp.EncryptString(S);
end;
function DecAsParam(const S: String; const Key: String): String;
begin
EncComp.SetKey(Key); //<-- produces random results
Result:= EncComp.DecryptString(S);
end;
var
InputStr: String;
EncrStr: String;
DecrStr: String;
Ctr: Integer;
begin
EncComp:= TLbRijndael.Create(nil);
try
EncComp.Encoding:= TEncoding.UTF8;
EncComp.KeySize:= ks256;
WriteLn('Enter a string to encrypt: ');
ReadLn(Input, InputStr);
WriteLn;
WriteLn('Encrypting as constants...');
EncrStr:= EncAsConst(InputStr);
DecrStr:= DecAsConst(EncrStr);
WriteLn('Pass 1: Enc = '+EncrStr+' Dec = '+DecrStr);
EncrStr:= EncAsConst(InputStr);
DecrStr:= DecAsConst(EncrStr);
WriteLn('Pass 2: Enc = '+EncrStr+' Dec = '+DecrStr);
EncrStr:= EncAsConst(InputStr);
DecrStr:= DecAsConst(EncrStr);
WriteLn('Pass 3: Enc = '+EncrStr+' Dec = '+DecrStr);
WriteLn;
WriteLn('Encrypting as parameters...');
EncrStr:= EncAsParam(InputStr, ENC_KEY);
WriteLn('Pass 1: Enc = '+EncrStr);
EncrStr:= EncAsParam(InputStr, ENC_KEY);
WriteLn('Pass 2: Enc = '+EncrStr);
EncrStr:= EncAsParam(InputStr, ENC_KEY);
WriteLn('Pass 3: Enc = '+EncrStr);
EncrStr:= EncAsParam(InputStr, ENC_KEY);
WriteLn('Pass 4: Enc = '+EncrStr);
EncrStr:= EncAsParam(InputStr, ENC_KEY);
WriteLn('Pass 5: Enc = '+EncrStr);
EncrStr:= EncAsParam(InputStr, ENC_KEY);
WriteLn('Pass 6: Enc = '+EncrStr);
WriteLn;
WriteLn('Press enter to exit');
ReadLn;
finally
EncComp.Free;
end;
end.
正如你所看到的,当在函数中传递完全相同的值作为参数时,它每次都会产生不同的结果。让我重申一下,* 完全相同的值 *。
我唯一的结论是,system.string
作为常量(const ENC_KEY = 'value';
)在幕后的大小或类型与作为变量使用时不同。
当我查看SetKey
过程的内部时,它是一个简单的Move
调用。..
procedure TLbRijndael.SetKey(const Key);
begin
Move(Key, FKey, FKeySizeBytes);
end;
(其中FKey
是array [0..31] of Byte;
)
这里出了什么问题,如何解决?
1条答案
按热度按时间zour9fqk1#
传递给这个非类型化参数的内容就是问题所在。当你传递一个true常量时,文本被传递。传递字符串变量时,传递的是文本的地址,而不是文本本身。这是因为字符串变量实际上是指向文本的指针。
我相信您需要停止使用字符串变量作为键,并提供一个二进制缓冲区。
下面的程序说明了这个问题:
在我的机器上,输出是:
第一行是编码为UTF-16 LE的文本
'ab'
。第二行是str
的地址,由第三行确认。我想强调文本和二进制之间区别的重要性。