В 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 делает то же самое со всеми из них. Любая помощь? Спасибо.





Возможно, вы преобразуете общую строку (которая в Delphi 2009 является UnicodeString) в PAnsiChar и передаете ее в хеш-функцию? Это не будет работать. Сначала вы должны преобразовать строку в AnsiString, а затем преобразовать ее в PAnsiChar, а-ля:
PAnsiChar(AnsiString('123456'))
Также попробуйте использовать RawByteString вместо AnsiString, как предлагает dmajkic. Избегайте использования UTF8String, поскольку это не AnsiString, и любые символы вне диапазона ASCII (0..127) могут быть переинтерпретированы в многобайтовые символы.
Вы проверили, правильно ли обновлена ваша библиотека для D2009 и юникодификации? Я как бы сомневаюсь, что один и тот же код подойдет для D7 / D2007 и D2009 для такого рода вещей.
Очевидно, что ваша библиотека не поддерживает Unicode.
Преобразуйте свою строку в AnsiString, RawByteString или UTF8String, объявив временную строку AnsiString и назначив ей свою строку униода.
Обратите внимание: если вы используете символы, специфичные для Unicode, которые нельзя преобразовать в одну кодовую страницу, вам следует преобразовать свою строку в UTF8.
Затем вызовите MD5 (PAnsiChar (YourTempString)).
Убедитесь, что в вашей библиотеке есть объявления PWideChar или UNICODE, чтобы пропустить это.
Ваша библиотека не поддерживает Unicode. Просто передать ему AnsiString будет недостаточно, потому что он, вероятно, использует строки для хранения данных внутри.
Вы можете попробовать обновить эту библиотеку, подождать, пока автор обновит ее, или просто использовать MessageDigest_5.pas, который поставляется с Delphi 2009. Он находится в папке источник \ Win32 \ мыло \ 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
Вы можете обернуть это простым вызовом функции, если хотите. Важно, чтобы вы выполняли преобразование в RawByteString перед преобразованием в TByteDynArray, поскольку преобразование RawByteString удаляет все лишние символы Unicode. Допустим, если редактирование содержит символы Unicode, вы можете получить неверные данные.
Имейте в виду, что GetMD5 возвращает интерфейс, поэтому он подсчитывается по ссылкам и т. д.
Счастливого Рождества!
В ответ Джима:
если мы изменим
MD5.Update (TByteDynArray (RawByteString (Edit1.Text)), Length (Edit1.Text));
к
MD5.Update (TByteDynArray (RawByteString (Edit1.Text)), Length (RawByteString (Edit1.Text)));
будет лучше поддерживать, пока существуют китайские иероглифы.
Прежде чем кто-то сможет прокомментировать алгоритмы хеширования, полезно иметь хотя бы фундаментальное понимание лежащих в основе концепций и принципов. Все ответы, которые до сих пор были сосредоточены на бесконечном приведении типов, полностью избыточны, но, что еще хуже, приведут к ненадежным результатам, если строка Юникода хешируется.
Первое, что вам нужно понять, это то, что алгоритмы хеширования и шифрования работают на байтовом уровне. Это означает, что им все равно, что вы хэшируете или шифруете. Вы можете хэшировать целые числа, символы, простой ASCII, полный юникод, байты, длинные слова и т. д. И т. Д. Алгоритм не заботится.
При работе со строками ЕДИНСТВЕННОЕ, что вы должны гарантировать, - это то, что внутренняя функция вашей библиотеки хеширования возвращает AnsiString в функции, которая выводит полученный вами хэш. Вот и все. Это все, что имеет значение.
Ваш фактический код для ВАШЕГО проекта может (и должен) быть основан на обычном вводе строки, который отображается в unicodestring в Delphi 2009. Вы не должны приводить какие-либо типы к ansistring или rawbytestring. Поступая таким образом, вы немедленно создаете неработающий хеш, если и когда пользователь пытается хешировать что-либо, выходящее за рамки набора символов ANSI. А в мире хеширования сломанный хеш одновременно и ненадежен, и небезопасен.
Спасибо за голос разума. +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;
@JW Ким, добро пожаловать в StackOverflow. Пожалуйста, уделите время чтению Часто задаваемые вопросы. Если у вас есть предыдущий опыт работы с форумами или новостными группами, вы заметите, что сайт работает по-другому. Вы отвечаете на довольно старый вопрос принятым ответом, поэтому он действителен, он не используется. Чтобы опубликовать исходный код, вы должны сделать отступ в 4 символа пробела, чтобы он выглядел как исходный код. :)
Броски здесь полностью фальшивые. Вы не можете разумно преобразовать UnicodeString в RawByteString. И вы абсолютно не можете преобразовать RawByteString в байтовый массив. Этот ответ настолько ошибочен и проголосован за него так ошибочно, что его следует просто удалить. Правильное решение использует TEncoding.GetBytes.