将 Delphi 2007 字符串加密程序转换为 Delphi XE

5

我们有一个Delphi 2007例程,用于加密表中的密码。该例程最初是从十年或更久前的CompuServe帖子中获取的,并且使用此例程加密的大量数据存在。

原始例程的核心是这个:

chr(ord(Str[I]) xor not(ord(Id[I mod length(Id) + 1])));

我知道将代码转换为Delphi XE会存在问题,因为涉及Unicode,所以我将该代码拆分成一个函数,并在备忘录中显示每个计算步骤:

function TfrmMain.EncodeDecode(AString: string): string;
const
  Hash: string = '^%12h2DBC3f41~~#6093fn7mY7eujEhbFD3DZ|R9aSDVvUY@dk79*7a-|-  Q';
var
  I: Integer;
  IMod: Integer;
  HMod: Char;
  OMod: Integer;
  AStrI: Char;
  OStrI: Integer;
  ResultStr: string;
  XOrNot: Integer;
  ChrXN: AnsiChar;
begin
  Memo1.Clear;
  Memo1.Lines.Add ('AStrI' + TAB + 'IMod' + TAB + 'HMod' +
    TAB + 'OMod' + TAB + 'OStrI' + TAB + 'XOrNot' + TAB + 'ChrXN');

  for I := 1 to Length (AString) do
  begin
    IMod := I mod Length (Hash) + 1;
    HMod := Hash [IMod];
    OMod := Ord (HMod);
    AStrI := AString[I];
    OStrI := Ord (AStrI);  // This is where things go south
    XOrNot := OStrI xor not OMod;
    ChrXN := AnsiChar (XOrNot);
    ResultStr := ResultStr + ChrXN;

    Memo1.Lines.Add (AStrI  + TAB +
      IntToStr (IMod)   + TAB +
      HMod              + TAB +
      IntToStr (OMod)   + TAB +
      IntToStr (OStrI)  + TAB +
      IntToStr (XOrNot) + TAB +
      ChrXN);
  end;
  Memo1.Lines.Add (ResultStr);
  Result := ResultStr;
end;

与 ROT13 相似,相同的例程用于加密和解密。如果我输入像 'ABCDEFGHI' 这样的字符串,Delphi 2007 版本可以获取结果加密字符串,再通过相同的例程运行它,并得到原始字符串。然而,Delphi XE 版本并不完全适用。我进行了一些调整(包含在上面),以改进它,但在 OstrI 步骤中它会崩溃。我认为这与对 (Wide) Char 执行 Ord 有关,但这是我能找到的最接近的。

非常感谢任何建议。


编辑

以下是原始 Delphi 2007 代码:

function EncodeDecode(Str: string): string;
const
  Id: string = '^%12h2DBC3f41~~#6093fn7mY7eujEhbFD3DZ|R9aSDVvUY@dk79*7a-|-  Q';
var
  I: Integer;
begin
  for I := 1 to Length (Str) do
    Str[I] := chr (ord (Str[I]) xor not (ord (Id[I mod Length (Id) + 1])));
  Result := Str;
end;

我们需要将现有软件的新版本不仅转换为Delphi XE,还需要将其转换为C#,以用于新的基于Web的前端。


更简洁地说:该函数是一个“自反函数”(=“它自己的反函数”)。 - Andreas Rejbrand
我还没有详细研究上面的代码,但我看到您正在混合使用 stringAnsiString(以及 charAnsiChar),在处理原始二进制数据时通常不是很好。但也许你已经意识到了这一点,并且只是按正确的方式执行任务? - Andreas Rejbrand
不要贴出你的代码不能工作的情况,你能否只发布D2007代码,我们中的一位将能够向你展示如何将其移植到XE。 - David Heffernan
1
@Eric:你真的知道如何把事情搞得复杂!;) - Andreas Rejbrand
@Eric 你需要关于C#的帮助吗?如果我是你,我会继续使用Delphi代码,并将其转换为array of byte而不是字符串。C#没有与AnsiChar和AnsiString等效的东西。一旦我有了Delphi的array of byte,我会切换到C#的byte[]。这个部分应该很简单。 - David Heffernan
显示剩余3条评论
1个回答

8
简单的方法是:
  1. 从Delphi 2007代码开始。
  2. string更改为AnsiString
  3. Char更改为AnsiChar
  4. 可能将Chr()更改为AnsiChar()
您的代码可能有更多细微差别。理想情况下,我想看到原始的Delphi 2007版本的代码。
发布原始代码后,我认为您可以在XE中使用此例程:
function EncodeDecode(const Str: AnsiString): AnsiString;
const
  Id: AnsiString = '^%12h2DBC3f41~~#6093fn7mY7eujEhbFD3DZ|R9aSDVvUY@dk79*7a-|-  Q';
var
  I: Integer;
begin
  Result := Str;
  for I := 1 to Length(Result) do
    Result[I] := AnsiChar(ord(Result[I]) xor not (ord(Id[I mod Length (Id) + 1])));
end;

请注意,我已将代码更改为将输入作为const字符串并使用Result作为工作缓冲区。这对于您的ANSI / Unicode需求来说并不是必要的,但对我来说感觉更自然!

3
这始终是一种使旧版 Delphi 代码在现代版本的 Delphi 中运行的方法。唯一(且明显的)缺点是您无法获得 Unicode 支持。 - Andreas Rejbrand
@Andreas 我想在这种情况下对于 OP 来说是可以的,因为 OP 的数据被锁定在仅限 ANSI 的文件中。 - David Heffernan
哇,我想得太多了。谢谢David的快速回答! - Eric S.
@David:为了进一步采纳你的建议,我建议将输入/输出值从AnsiString更改为RawByteString。在D2009之前,AnsiString对于编码字符所使用的代码页并没有做出任何假设。而在D2009及以后的版本中,它会做出假设,而RawByteString则继承了传递给它的任何Ansi字符串的代码页。 - Remy Lebeau
@David:base64 本身在任何代码页中都是安全的,因为它只使用 ASCII。但是,当 base64 解码为二进制数据时,如果将二进制数据存储在“AnsiString”或“RawByteString”中并传递,就有可能出现数据丢失。幸运的是,您可以在运行时使用 SetCodePage() 将代码页值存储在“RawByteString”中。对于“AnsiString”,您无法这样做(无论如何,不建议使用类型转换)。 - Remy Lebeau
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接