gpt4 book ai didi

string - 将 system.string 作为函数参数或常量传递的不同结果

转载 作者:行者123 更新时间:2023-12-03 15:54:18 27 4
gpt4 key购买 nike

我已经为一个非常奇怪的现象奋斗了几个小时。首先,我使用的是 TurboPower LockBox v10 加密库(使用 TLbRijndael),但我不相信这就是问题所在。我需要将 key 传递给加密/解密函数,因此我自然创建了如下函数:

function EncryptText(const S: String; const Key: String): String;
function DecryptText(const S: String; const Key: String): String;

奇怪的是,虽然加密似乎有效,但当我尝试解密时,它返回完全垃圾。因此,在我长达数小时的寻找原因的过程中,我发现的结果绝对让我困惑。当我使用定义为常量的加密 key 时,一切正常。但是在函数中传递完全相同的值(也是 system.string)作为参数,则不然。

总结一下:

  • 将 key 作为常量 (system.string) 传递时,一切正常。
  • 将 key 作为参数 (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.

enter image description here

正如您所看到的,当在函数中传递完全相同的值作为参数时,它每次都会产生不同的结果。让我重申一下,完全相同的值

我唯一的结论是,system.string 当用作常量 (const ENC_KEY = 'value';) 时,在幕后的大小或类型与当用作变量时。

当我查看 SetKey 过程时,它是一个简单的 Move 调用...

procedure TLbRijndael.SetKey(const Key);
begin
Move(Key, FKey, FKeySizeBytes);
end;

(其中 FKey字节数组 [0..31];)

这里出了什么问题以及如何解决?

最佳答案

procedure TLbRijndael.SetKey(const Key);
begin
Move(Key, FKey, FKeySizeBytes);
end;

你传递给这个无类型参数的内容就是问题所在。当您传递一个真正的常量时,文本就会被传递。当您传递字符串变量时,传递的是文本的地址,而不是文本本身。这是因为字符串变量实际上是指向文本的指针。

我相信您需要停止使用字符串变量作为键并提供二进制缓冲区。

考虑这个说明问题的程序:

{$APPTYPE CONSOLE}

uses
SysUtils;

procedure Foo(const Key);
var
buff: Pointer;
begin
Move(Key, buff, SizeOf(buff));
Writeln(Format('%p', [buff]));
end;

const
ENC_KEY = 'abcdefghijklmnopqrstubwxyz123456';

var
str: string = ENC_KEY;

begin
Foo(ENC_KEY);
Foo(str);
Writeln(Format('%p', [Pointer(str)]));
end.

在我的机器上输出是:

0062006100419D4800419D48

第一行是编码为 UTF-16LE 的文本 'ab'。第二行是 str 的地址,第三行确认了这一点。

我想强调区分文本和二进制的重要性。

关于string - 将 system.string 作为函数参数或常量传递的不同结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27933377/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com