【问题标题】:Delphi ORD function not returning expected valueDelphi ORD函数未返回预期值
【发布时间】:2019-11-14 09:29:33
【问题描述】:

我有 2 个函数,一个用于加密,另一个用于解密字符串,它们使用 Ord() 函数。除了使用扩展的 Ascii 代码外,它工作得很好。

如果我使用字母 ê(Ascii 代码 136),Ord() 函数会返回 234,而我预期它会返回 136。

如果我对加密字符串运行解密,我得到的结果与原始字符串不同,ê 变成了 j。

有人可以帮忙解决这个问题吗?

procedure TForm1.btnEncryptClick(Sender: TObject);
var
  sTempString : string;
  iIndex,
  i: integer;
begin
  sTempString  := edtOriginalString.Text ;
  for iIndex := 1 to length(sTempString) do
  begin
    i := ord(sTempString[iIndex]);
    i := i shl 1;
    sTempString[iIndex] := Char(i);
  end;
  edtEncryptedString.Text := sTempString;
end;

procedure TForm1.btnDecryptClick(Sender: TObject);
var
  sTempString : string;
  iIndex,
  i : integer;
begin
  sTempString  := edtEncryptedString.Text ;
  for iIndex := 1 to length(sTempString) do
  begin
    i := ord(sTempString[iIndex]);
    i := i shr 1;
    sTempString[iIndex] := char(i);
  end;
  edtDecryptedString.Text := sTempString;
end;

【问题讨论】:

  • 您使用的是哪个版本的 Delphi?这实际上很重要,因为 Delphi 字符串在 Delphi 2009 及更高版本中默认为 Unicode。
  • 这个错误是在旧的 Delphi 6 应用程序中发现的
  • $EA 到 $6A(ê 到 j)意味着您正在丢失最重要的位。这是因为 char 是 D6 中的字节大小。您不能对大于 127 的字符使用该加密。
  • i := (i shl 1) + (i shr 7) 用于加密旋转字节并保留 lsb 中的 msb。对于解密,执行相反的操作。

标签: delphi


【解决方案1】:

如果我使用字母 ê(Ascii 代码 136)

不,这实际上是错误的。 ASCII 只有 128 个字符(0 到 127)。

但是,ê 是 Unicode 字符 U+00EA:带圆形的拉丁小写字母 E。

而 EA(十六进制)确实是 234(十进制)。


Delphi 字符和字符串在 Delphi 2009 之前为 8 位,在 Delphi 2009 及更高版本中为 Unicode。

所以在你的情况下,Delphi 6,一个字符是 8 位的。

因此,您的左移将使您丢失最高有效位 (MSB),并且您不可能希望将其取回。

确实,如果我们以 ê (234) 为例,我们有

1110 1010 (ê)

将位向左移动一步,我们得到

1101 0100

将位向右移动一步,我们得到

0110 1010 (j).

因此,我们丢失了信息。


但是,您的方法适用于 ASCII 字符 (不适用于 127 以上的任何字符,因为它们都有一个作为 MSB(因此即使 Ord 在您的情况下确实返回了 136,它也不起作用)。


因此,如果您想支持 127 以上的字符,则需要放弃或重新设计“加密”方法。例如,您可以旋转位而不是移位它们。或者你可以反转它们(使用not)。

如果你选择旋转而不是移位,你会得到这个:

1110 1010 (ê)
rotate left:
1101 0101
rotate back (right):
1110 1010 (ê)

虽然它与您的实际问题无关,但您可能仍然想知道为什么 Ord 没有像您预期的那样返回 136。

好吧,在 Unicode 之前(主要是在 1990 年代和更早的时期),只是有许多不同的(不兼容的)字符编码。通常,8 位编码/代码页(字符 0..255)包括 ASCII 字符(0..127),然后对剩余的字符(128..255)做出自己的选择。由于 ê 不是 ASCII 字符,这意味着这些“扩展 ASCII”代码页中只有一些可能包含 ê,而在包含 ê 的代码页中,实际数值可能会有很大差异。

换句话说,您的来源声称 ê 是 136,而您的 Delphi 程序使用不同的 8 位代码页。

在Unicode的现代世界中,这种问题已经不存在了。

【讨论】:

  • 好的,那我该如何按照asciitable.com处理扩展ASCII码?
  • 你没有。您使用 Unicode。也许是 UTF-8。而且您还需要了解加密是针对字节而不是文本进行的。不要期望将字符串直接加密为字符串。该过程通常是这样的。 1. 将明文转换为字节。 2. 将字节加密为更多字节。 3. 将这些字节转换为 base64 编码文本。
  • 当然大卫是对的:这根本不是“加密”,只是“混淆”。从“加密”文本中获取原始纯文本非常容易。
  • asciitable.com 似乎不是一个值得信赖的资源。没有单一的“扩展 ASCII 代码页”,而是有很多,所以最终表格非常具有误导性。这甚至可能不是最常见的此类代码页(可能是 Windows 1252)!无论如何,今天根本不应该使用传统的 8 位代码页。页面顶部的文字也不准确。
猜你喜欢
  • 1970-01-01
  • 2012-08-16
  • 2013-02-24
  • 1970-01-01
  • 2012-01-21
  • 2018-12-05
  • 2018-12-05
  • 2013-09-04
  • 2016-02-13
相关资源
最近更新 更多