在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对所有这些脚本都做了同样的事情。有帮助吗?感谢。
答案 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)));
在汉字存在时会更好地支持。