MD5 хеширование в Delphi 2009 - PullRequest
6 голосов
/ 25 декабря 2008

В 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 ]

30 голосов
/ 25 декабря 2008

Ваша библиотека не поддерживает Unicode. Просто передать его AnsiString будет недостаточно, потому что он, вероятно, использует строки для хранения данных.

Вы можете попробовать обновить эту библиотеку, подождать, пока автор обновит ее, или просто использовать MessageDigest_5.pas , поставляемый с Delphi 2009. Она находится в 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

Вы можете обернуть это простым вызовом функции, если хотите. Важно, чтобы вы приводили к RawByteString перед приведением к TByteDynArray , поскольку при RawByteString отбрасываются все дополнительные символы Юникода. Конечно, если правка содержит символы Юникода, вы можете получить неверные данные.

Имейте в виду, что GetMD5 возвращает интерфейс, поэтому он подсчитывает ссылки и т. Д.

С Рождеством!

5 голосов
/ 10 апреля 2009

Прежде чем кто-то сможет прокомментировать алгоритмы хеширования, полезно иметь хотя бы фундаментальное понимание основополагающих концепций и принципов. Все ответы, которые до сих пор были направлены на бесконечное встраивание типов, полностью излишни, но, что еще хуже, приводят к ненадежным результатам, если хэшируется строка в юникоде.

Первое, что вам нужно понять, это то, что алгоритмы хеширования и шифрования работают на уровне байтов. Это означает, что им все равно, что вы хешируете или шифруете. Вы можете хешировать целые числа, символы, обычный ASCII, полный юникод, байты, длинные слова и т. Д. Алгоритм не имеет значения.

При работе со строками ЕДИНСТВЕННОЕ, что вы должны гарантировать, - это то, что внутренняя функция вашей библиотеки хэширования возвращает AnsiString в функции, которая выплевывает полученный хеш. Вот и все. Это все, что имеет значение.

Ваш фактический код для ВАШЕГО проекта может (и должен) быть основан на обычном вводе строки, который отображается на unicodestring в Delphi 2009. Вы не должны типизировать что-либо для ansistring или rawbytestring. Тем самым вы немедленно создаете сломанный хеш, если и когда пользователь пытается что-то хэшировать за пределами набора символов ANSI. А в мире хеширования сломанный хеш является ненадежным и ненадежным.

1 голос
/ 28 декабря 2010

Если у вас 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;
1 голос
/ 25 декабря 2008

Очевидно, что ваша библиотека не поддерживает Unicode.

Преобразуйте вашу строку в AnsiString или RawByteString или UTF8String, объявив temp AnsiString и назначьте ей строку uniode.

Обратите внимание, что если вы используете специфичные для юникода символы, которые не могут быть преобразованы в одну кодовую страницу, вы должны преобразовать вашу строку в UTF8.

Затем вызовите MD5 (PAnsiChar (YourTempString)).

Убедитесь, что ваша библиотека может иметь объявления PWideChar или UNICODE, чтобы пропустить это.

1 голос
/ 25 декабря 2008

Вы проверили, что ваша библиотека была корректно обновлена ​​для D2009 и unicodification? Я сомневаюсь, что один и тот же код мог бы выполнять D7 / D2007 и D2009 для такого рода вещей.

0 голосов
/ 18 марта 2009

В ответе Джима:

если мы изменим

MD5.Update (TByteDynArray (RawByteString (Edit1.Text)), длина (Edit1.Text));

до

MD5.Update (TByteDynArray (RawByteString (Edit1.Text)), длина (RawByteString (Edit1.Text)));

будет лучше поддерживать, пока существуют китайские иероглифы.

0 голосов
/ 25 декабря 2008

Вы случайно приводите обобщенную строку (которая в Delphi 2009 - UnicodeString) к PAnsiChar и передаете ее в хеш-функцию? Это не будет работать. Сначала вы должны привести строку в AnsiString, а затем привести ее к PAnsiChar, как:

PAnsiChar(AnsiString('123456'))

Кроме того, попробуйте использовать RawByteString вместо AnsiString, как предложил dmajkic. Избегайте UTF8String, так как это не AnsiString, и любые символы вне диапазона ASCII (0..127) могут быть переосмыслены в многобайтовые символы.

...