MD5 Hashing in Delphi 2009

时间:2008-12-25 09:07:29

标签: delphi unicode delphi-2009 md5 hash

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

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

看看:

字符串:“123456”

散列:

Delphi 7:“e10adc3949ba59abbe56e057f20f883e” - 真正的哈希。
Delphi 2007:“e10adc3949ba59abbe56e057f20f883e” - 真正的哈希值。
和... Delphi 2009:“5fa285e1bebe0a6623e33afc04a1fbd5” - WTF ??

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

7 个答案:

答案 0 :(得分:30)

您的库不支持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 会返回一个界面,因此会被引用计算等。

圣诞快乐!

答案 1 :(得分:5)

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

您需要了解的第一件事是散列和加密算法在字节级运行。这意味着他们不关心你正在散列或加密的内容。您可以散列整数,字符,纯ASCII,完整的unicode,字节,长字等等。算法无关紧要。

使用字符串时,您必须确保的唯一事情是哈希库的内部函数在函数中返回一个AnsiString,该函数会吐出您产生的哈希值。而已。这就是最重要的。

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

答案 2 :(得分:1)

您是否检查过您的图书馆已正确更新D2009和unicodification? 我有点怀疑D7 / D2007和D2009会为这类事做同样的代码。

答案 3 :(得分:1)

很明显,你的lib不支持unicode。

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

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

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

检查您的lib可能有PWideChar或UNICODE声明,以跳过此步骤。

答案 4 :(得分:1)

如果您有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;

答案 5 :(得分:0)

您是否正在将一个通用字符串(在Delphi 2009中是UnicodeString)转换为PAnsiChar并将其传递给哈希函数?那样不行。首先必须将字符串转换为AnsiString,然后将其转换为PAnsiChar,la:

PAnsiChar(AnsiString('123456'))

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

答案 6 :(得分:-3)

在吉姆的回答中:

如果我们改变

MD5.Update(TByteDynArray(RawByteString(Edit1.Text)),Length(Edit1.Text));

MD5.Update(TByteDynArray(RawByteString(Edit1.Text)),Length(RawByteString(Edit1.Text)));

在汉字存在时会更好地支持。