DCPcrypt Hashing German Umlauts

Я использую DCPcrypt и SHA512 для хэш-строк.

Я использую версию Warren Postma https://bitbucket.org/wpostma/dcpcrypt2010

Он работает нормально. Однако это не удается с немецкими умляутами, такими как ä, ö, ü и, возможно, другими юникодами.

Я использую библиотеку следующим образом:

function TForm1.genhash(str: string): string;
var
  Hash  : TDCP_sha512;
  Digest: array[0..63] of byte;
  i: integer;
  s: string;
begin
  s:= '';
  hash  := TDCP_sha512.Create(nil);
  if hash<>nil then
  begin
    try
      Hash.Init;
      Hash.UpdateStr(str);
      Hash.Final(Digest);

      for i:= 0 to length(Digest)-1 do
        s:= s + IntToHex(Digest[i],2);

    finally
      hash.free;
    end;

  end;
  Result := s;
end;

Когда я вводим букву ä, я ожидаю, что результатом будет:

64868C5784A6004E675BCF405F549369BF607CD3269C0CAC1711E21BA9F40A5ABBF0C7535856E7CF77EA55A072DD04AA89EEA361E95F497AA965309B50587157

Я проверил его с этими сайтами: http://hashgenerator.de/ http://passwordsgenerator.net/sha512-hash-generator/

Однако я получаю:

1A7F725BD18E062020A646D4639F264891368863160A74DF2BFC069C4DADE04E6FA854A2474166EED0914B922A9D8BE0C89858D437DDD7FBCA5C9C89FC07323A

Итак, мой вопрос: Как я могу использовать библиотеку DCPcrypt для генерации хэшей для немецких умляутов? БЛАГОДАРЯ

Ответ 1

Это должна быть самая распространенная ошибка, которую люди делают с хэшированием и шифрованием. Эти algos работают на двоичных данных, но вы передаете текст. Что-то где-то есть, чтобы закодировать этот текст как двоичный. И какую кодировку следует использовать. Откуда вы знаете, что ваша библиотека использует то же самое, что и онлайн-инструмент? Вы этого не сделаете.

Итак, вот правило для вас следовать. Никогда не хэш-текст. Только не делай этого. Кодирование текста в виде двоичного кода с использованием четко определенной, явно выбранной кодировки. И хэш это. Я предлагаю вам кодировать как UTF-8 и хэш. Итак, TEncoding.UTF8.GetBytes(...) - ваш друг здесь.

Теперь, глядя на настоящую деталь, вы вызываете этот метод:

procedure UpdateStr(const Str: RawByteString);

Параметр RawByteString означает, что ваш текст Юникода преобразуется в строку ANSI со страницей системного кода по умолчанию. Я уверен, что не то, что вы намереваетесь произойти. В самом деле, компилятор говорит следующее:

[dcc32 Warning] W1058 Неявная строка с потенциальной потерей данных от 'string' до 'RawByteString'

Итак, компилятор говорит вам, что вы делаете что-то неправильно. Вы действительно должны внимательно относиться к сообщениям компилятора.

Теперь вы можете вызвать UpdateUnicodeStr вместо UpdateStr. Но опять же, откуда вы знаете, какая кодировка используется? Это обычная внутренняя кодировка, UTF-16LE.

Но пусть последует мое правило никогда не кодировать текст.

{$APPTYPE CONSOLE}

uses
  SysUtils, Classes, DCPsha512;

function genhash(str: string): string;
var
  Bytes: TBytes;
  Hash: TDCP_sha512;
  Digest: array[0..63] of byte;
begin
  Bytes := TEncoding.UTF8.GetBytes(str); // encode text as UTF-8 bytes

  hash := TDCP_sha512.Create(nil);
  try
    Hash.Init;
    Hash.Update(Pointer(Bytes)^, Length(Bytes));
    Hash.Final(Digest);
  finally
    hash.Free;
  end;

  // convert the digest to a hex hash string
  SetLength(Result, Length(Digest)*2);
  BinToHex(Digest, PChar(Result), Length(Digest));
end;

begin
  Writeln(genhash('ä'));
  Readln;
end.

Выход

64868C5784A6004E675BCF405F549369BF607CD3269C0CAC1711E21BA9F40A5ABBF0C7535856E7CF77EA55A072DD04AA89EEA361E95F497AA965309B50587157

Обратите внимание, что я упростил код другими способами. Я удалил локальную строковую переменную и работал непосредственно с Result. Я использовал BinToHex из блока Classes, чтобы преобразовать дайджест в шестнадцатеричное преобразование. Я также изменил этот код:

hash := TDCP_sha512.Create(nil);
if hash<>nil then
  ....

чтобы удалить инструкцию if, которая не нужна. Если конструктор не работает, возникает исключение.

Пожалуйста, следуйте моему правилу, никогда не добавляя хэш-текст. Это будет вам хорошо!