【问题标题】:DCPcrypt Hashing German UmlautsDCPcrypt 散列德语变音符号
【发布时间】:2016-06-16 13:07:17
【问题描述】:

我正在使用 DCPcrypt 和 SHA512 对字符串进行哈希处理。

我正在使用 Warren Postma https://bitbucket.org/wpostma/dcpcrypt2010 的版本

它工作正常。然而,它与德语变音符号如 ä、ö、ü 以及可能的其他 unicode 失败。

我正在使用这样的库:

function TForm1.genhash(str: string): string;
var
  Hash  : TDCP_sha512;
  Digest: array[0..63] of byte;
  i: integer;
  s: string;
begin
  s:= '';
  hash  := TDCP_sha512.Create(nil);
  if hash<>nil then
  begin
    try
      Hash.Init;
      Hash.UpdateStr(str);
      Hash.Final(Digest);

      for i:= 0 to length(Digest)-1 do
        s:= s + IntToHex(Digest[i],2);

    finally
      hash.free;
    end;

  end;
  Result := s;
end;

当我输入字母 ä 时,我希望输出是:

64868C5784A6004E675BCF405F549369BF607CD3269C0CAC1711E21BA9F40A5ABBF0C7535856E7CF77EA55A072DD04AA89EEA361E95F497AA965309B50587157

我在这些网站上进行了检查: http://hashgenerator.de/ http://passwordsgenerator.net/sha512-hash-generator/

但是我得到:

1A7F725BD18E062020A646D4639F264891368863160A74DF2BFC069C4DADE04E6FA854A2474166EED0914B922A9D8BE0C89858D437DDD7FBCA5C9C89FC07323A

所以我的问题是: 如何使用 DCPcrypt 库为德语变音符号生成哈希?谢谢

【问题讨论】:

    标签: delphi delphi-10-seattle


    【解决方案1】:

    这一定是人们使用散列和加密时最常犯的一个错误。这些算法对二进制数据进行操作,但您正在传递文本。某处必须将该文本编码为二进制。以及应该使用什么编码。您怎么知道您的图书馆使用与在线工具相同的工具?你没有。

    所以,这里有一条规则供您遵循。永远不要散列文本。只是不要这样做。使用定义明确、明确选择的编码将文本编码为二进制。并对其进行哈希处理。我建议您将其编码为 UTF-8 并对其进行哈希处理。所以,TEncoding.UTF8.GetBytes(...) 是你的朋友。

    现在,看看这里的实际细节,你正在调用这个方法:

    procedure UpdateStr(const Str: RawByteString);
    

    RawByteString 参数表示您的 Unicode 文本正在转换为 ANSI 字符串,具有默认的系统代码页。我敢肯定这不是你打算发生的。事实上,编译器是这样说的:

    [dcc32 警告] W1058 隐式字符串转换,可能会丢失从“字符串”到“RawByteString”的数据

    所以编译器告诉你你做错了什么。您确实必须注意编译器消息。

    现在,您可以致电 UpdateUnicodeStr 而不是 UpdateStr。但同样,你怎么知道使用了什么编码?它恰好是原生内部编码,UTF-16LE。

    但是,让我们遵循我从不编码文本的规则。

    {$APPTYPE CONSOLE}
    
    uses
      SysUtils, Classes, DCPsha512;
    
    function genhash(str: string): string;
    var
      Bytes: TBytes;
      Hash: TDCP_sha512;
      Digest: array[0..63] of byte;
    begin
      Bytes := TEncoding.UTF8.GetBytes(str); // encode text as UTF-8 bytes
    
      hash := TDCP_sha512.Create(nil);
      try
        Hash.Init;
        Hash.Update(Pointer(Bytes)^, Length(Bytes));
        Hash.Final(Digest);
      finally
        hash.Free;
      end;
    
      // convert the digest to a hex hash string
      SetLength(Result, Length(Digest)*2);
      BinToHex(Digest, PChar(Result), Length(Digest));
    end;
    
    begin
      Writeln(genhash('ä'));
      Readln;
    end.
    

    输出

    64868C5784A6004E675BCF405F549369BF607CD3269C0CAC1711E21BA9F40A5ABBF0C7535856E7CF77EA55A072DD04AA89EEA361E95F497AA965309B50587157

    请注意,我以其他方式简化了代码。我删除了本地字符串变量并直接使用Result。我使用Classes 单元中的BinToHex 进行摘要到十六进制的转换。我也修改了这段代码:

    hash := TDCP_sha512.Create(nil);
    if hash<>nil then
      ....
    

    删除不需要的if 语句。如果构造函数失败,则会引发异常。

    请遵守我的规则,永远不要散列文本。它会很好地为您服务!

    【讨论】:

    • 感谢大卫的出色回答。欣赏解释,肯定学到了一些东西!
    • 太棒了。谢谢你的问题。很高兴能清楚地说明问题,并有机会最终写下困扰我一段时间的内容。我希望我们可以利用这个问答来传播关于二进制和文本与散列和加密的信息!
    猜你喜欢
    • 1970-01-01
    • 2016-01-21
    • 2013-02-09
    • 1970-01-01
    • 2021-09-28
    • 2013-12-25
    • 2011-11-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多