【问题标题】:MD5 Hashing in Delphi 2009Delphi 2009 中的 MD5 哈希
【发布时间】:2008-12-25 09:07:28
【问题描述】:

在 borland delphi 7 甚至在 delphi 2007 中一切正常,但在 delphi 2009 中它只是返回错误的哈希值!

我使用 wcrypt2 脚本 (http://pastebin.com/m2f015cfd)

看看吧:

字符串:“123456”

哈希:

Delphi 7 : "e10adc3949ba59abbe56e057f20f883e" - 真正的哈希。
Delphi 2007:“e10adc3949ba59abbe56e057f20f883e” - 也是真正的哈希。
和... 德尔福 2009:“5fa285e1bebe0a6623e33afc04a1fbd5”-WTF??

我尝试了很多 md5 脚本,但 delphi 2009 对所有这些脚本都做了同样的事情。有什么帮助吗?谢谢。

【问题讨论】:

    标签: delphi unicode delphi-2009 md5 hash


    【解决方案1】:

    您的库不支持 Unicode。仅仅传递一个 AnsiString 是不够的,因为它可能在内部使用字符串来存储数据。

    您可以尝试更新该库,等待作者更新它,或者只使用 Delphi 2009 附带的 MessageDigest_5.pas。它位于 source\Win32\ soap\wsdlimporter 文件夹,您需要将其添加到您的路径中,或者将其明确包含在您的项目中。

    这是在 Delphi 2009 中使用它的一些示例代码:

    uses Types, MessageDigest_5;
    
    procedure TForm16.Edit1Change(Sender: TObject);
    var
      MD5: IMD5;
    begin
      MD5 := GetMD5;
      MD5.Init;
      MD5.Update(TByteDynArray(RawByteString(Edit1.Text)), Length(Edit1.Text));
      Edit2.Text := LowerCase(MD5.AsString);
    end;
    

    你在做生意:

    MD5(123456) = e10adc3949ba59abbe56e057f20f883e

    如果你愿意,你可以将它包装在一个简单的函数调用中。在转换为 TByteDynArray 之前转换为 RawByteString 很重要,因为 RawByteString 转换会丢弃所有额外的 Unicode 字符。如果编辑包含 Unicode 字符,那么您最终可能会得到错误的数据。

    请记住,GetMD5 正在返回一个接口,因此它是引用计数的,等等。

    圣诞快乐!

    【讨论】:

    • 这里的演员表完全是假的。您不能合理地将 UnicodeString 转换为 RawByteString。而且您绝对不能将 RawByteString 转换为字节数组。这个答案大错特错,投票错误如此之大,以至于应该简单地删除它。正确的解决方案使用 TEncoding.GetBytes。
    【解决方案2】:

    在有人可以评论散列算法之前,如果他们至少对基本概念和原则有基本的了解,这会有所帮助。到目前为止,所有关注于无休止类型转换的响应都完全是矫枉过正,但更糟糕的是,如果对 unicode 字符串进行哈希处理,将导致不可靠的结果。

    您需要了解的第一件事是散列和加密算法在字节级别上运行。这意味着他们不在乎你在散列或加密什么。您可以散列整数、字符、纯 ASCII、完整的 unicode、字节、长字等。算法不在乎。

    在处理字符串时,您唯一需要确保的是散列库的内部函数在函数中返回一个 AnsiString,该函数会吐出生成的散列。就是这样。这才是最重要的。

    您的项目的实际代码可以(并且应该)基于正常的字符串输入,它映射到 Delphi 2009 中的 unicodestring。您不应该将任何内容强制转换为 ansistring 或 rawbytestring。通过这样做,当用户尝试散列 ANSI 字符集范围之外的任何内容时,您会立即创建一个损坏的散列。在散列的世界中,一个损坏的散列既不可靠又不安全。

    【讨论】:

    • 感谢理性的声音。 +1。
    【解决方案3】:

    您是否检查过您的库已针对 D2009 和统一编码进行了正确更新? 我有点怀疑相同的代码会为这类事情执行 D7/D2007 和 D2009。

    【讨论】:

      【解决方案4】:

      很明显,您的 lib 未启用 unicode。

      通过声明 temp AnsiString 并将您的 uniode 字符串分配给它,将您的字符串转换为 AnsiString 或 RawByteString 或 UTF8String。

      请注意,如果您使用无法转换为单个代码页的 unicode 特定字符,则应将字符串转换为 UTF8。

      然后调用 MD5(PAnsiChar(YourTempString))。

      检查您的库是否有 PWideChar 或 UNICODE 声明,以跳过此。

      【讨论】:

        【解决方案5】:

        如果您有wcrypt2.pas,请使用此功能。

        function md5ansi(const Input: AnsiString): AnsiString;
        var
          hCryptProvider: HCRYPTPROV;
          hHash: HCRYPTHASH;
          bHash: array[0..$7f] of Byte;
          dwHashBytes: Cardinal;
          pbContent: PByte;
          i: Integer;
        begin
          dwHashBytes := 16;
          pbContent := Pointer(PAnsiChar(Input));
          Result := '';
        
          if CryptAcquireContext(@hCryptProvider, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT or CRYPT_MACHINE_KEYSET) then
          begin
            if CryptCreateHash(hCryptProvider, CALG_MD5, 0, 0, @hHash) then
            begin
              if CryptHashData(hHash, pbContent, Length(Input) * sizeof(AnsiChar), 0) then
              begin
                if CryptGetHashParam(hHash, HP_HASHVAL, @bHash[0], @dwHashBytes, 0) then
                begin
                  for i := 0 to dwHashBytes - 1 do
                  begin
                    Result := Result + AnsiString(Format('%.2x', [bHash[i]]));
                  end;
                end;
              end;
              CryptDestroyHash(hHash);
            end;
            CryptReleaseContext(hCryptProvider, 0);
          end;
        
          Result := AnsiString(AnsiLowerCase(String(Result)));
        end;
        

        【讨论】:

        • @JW Kim,欢迎来到 StackOverflow。请花点时间阅读faq。如果您以前使用过论坛或新闻组,您会注意到该网站以不同的方式工作。您正在用一个公认的答案回答一个相当古老的问题,因此它是有效的,它没有被使用。要发布源代码,您必须将其缩进 4 个空格字符以使其看起来像源代码。 :)
        【解决方案6】:

        您是否可能将通用字符串(在 Delphi 2009 中为 UnicodeString)转换为 PAnsiChar 并将其传递给散列函数?这是行不通的。您首先必须将字符串转换为 AnsiString,然后再将该字符串转换为 PAnsiChar,例如:

        PAnsiChar(AnsiString('123456'))
        

        另外,尝试使用 RawByteString 而不是 AnsiString,就像 dmajkic 建议的那样。避免使用 UTF8String,因为它不是 AnsiString,任何超出 ASCII 范围 (0..127) 的字符都可能被重新解释为多字节字符。

        【讨论】:

          【解决方案7】:

          在吉姆的回答中:

          如果我们改变

          MD5.Update(TByteDynArray(RawByteString(Edit1.Text)), 长度(Edit1.Text));

          MD5.Update(TByteDynArray(RawByteString(Edit1.Text)), 长度(RawByteString(Edit1.Text)));

          在有汉字的情况下会更好地支持。

          【讨论】:

            猜你喜欢
            • 2016-02-29
            • 2010-11-03
            • 2012-08-17
            • 1970-01-01
            • 1970-01-01
            • 2020-12-08
            • 2019-04-24
            • 2011-06-18
            相关资源
            最近更新 更多