Delphi-PRAXiS
Seite 1 von 3  1 23      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   MD5 - Unterschiede zw. Indy und DEC6 (https://www.delphipraxis.net/214847-md5-unterschiede-zw-indy-und-dec6.html)

dschiffler 19. Mär 2024 10:37

MD5 - Unterschiede zw. Indy und DEC6
 
Hallo,

ich verwende Indy zur Kommunikation mit einem Webserver.
Der Webserver verlangt Digest-Authentication und Indy hat dafür ja die Klasse TIdDigestAuthentication.
In dieser Klasse wird zur Berechnung des Hashes MD5 verwendet, was in der Klasse TIdHashMessageDigest5 implementiert ist.

Jetzt mal unabhängig davon, dass MD5 nicht mehr als sicher gilt, ist der Algorithmus als solcher ja standardisiert und
es sollte bei verschiedenen Komponenten, die Hash-Klassen anbieten, doch dann immer der gleiche Hash rauskommen, oder?

Jedenfalls benutze ich auch DEC6 und wenn ich mir da den MD5-Hash des gleichen Ausgangswertes mit der Klasse THash_MD5 geben lasse,
bekomme ich einen anderen Hash-Wert als bei Indy.
Delphi-Quellcode:
  lMD5_Indy := TIdHashMessageDigest5.Create;
  try
    sValue := lMD5_Indy.HashStringAsHex('Testwert');
  finally
    lMD5_Indy.Free;
  end;

  lMD5_DEC := THash_MD5.Create;
  try
    sValue := lMD5_DEC.CalcString('Testwert', TFormat_HEX);
  finally
    lMD5_DEC.Free;
  end;
Hashwert bei Indy: B089896DDE61B804B603F7866A9D664B
Hashwert bei DEC: 7C94514A886400F144C1B2FF80854F33


Welche Erklärung kann es dafür geben?

Gausi 19. Mär 2024 11:04

AW: MD5 - Unterschiede zw. Indy und DEC6
 
Ich tippe auf automatische interne Umwandlung des übergebenen Strings. Ansi, UTF8, UnicodeString, sowas in der Richtung.

himitsu 19. Mär 2024 11:05

AW: MD5 - Unterschiede zw. Indy und DEC6
 
Die Berechnung selbst sollte bei Beiden korrekt sein.
Ich geht da mal nicht von einem Fehler aus,

aber es kommt auch darauf an, wie der String "binär" interpretiert wird.

* Unicode (UTF-16), also 2 Byte pro Char
* ANSI, also mit der aktuellen Codepage und 1 Byte pro Char (besonder unpraktisch, wenn z.B. in deutschem, englischen, russischen oder japanischem Windows andere Codepages/Charsets verwendet werden)
* UTF-8 ... wird meistens gern benutzt

Und das kannst du dir ja im Code ansehn, was HashStringAsHex und CalcString wie intern nutzen.
* falls Parameter als "String" sind
* ansonsten wird natürlich schon bei Übergabe des Parameters konvertiert

Rolf Frei 19. Mär 2024 12:55

AW: MD5 - Unterschiede zw. Indy und DEC6
 
B089896DDE61B804B603F7866A9D664B ist auf jeden Fall der richtige MD5 Hash für 'Testwert'. Ich vermute auch, dass die DEC Variante den Unicodestringparameter nicht korrekt verarbeitet. Dazu müsstest du mal den Quelltext der lMD5_DEC.CalcString Methode hier posten.

Mit neueren Delphi's kannst du auch die mitgeliferten Hash Routinen nutzen:
Delphi-Quellcode:
hash := System.Hash.THashMD5.GetHashString('Testwert');

dschiffler 19. Mär 2024 13:07

AW: MD5 - Unterschiede zw. Indy und DEC6
 
Beide Methoden haben als Parameter einen ganz normalen String.

Indy
function HashStringAsHex(const AStr: String; ADestEncoding: IIdTextEncoding = nil): String;

In der Methode wird HashString aufgerufen (als Parameter auch ein ganz normaler String).
Delphi-Quellcode:
function HashString(const ASrc: string; ADestEncoding: IIdTextEncoding = nil): TIdBytes;
var
  LStream: TStream;
begin
  LStream := TMemoryStream.Create;
  try
    WriteStringToStream(LStream, ASrc, ADestEncoding);
    LStream.Position := 0;
    Result := HashStream(LStream);
  finally
    FreeAndNil(LStream);
  end;
end;
In WriteStringToStream steht u.a. folgendes:
Delphi-Quellcode:
LBytes := ToBytes(AStr, LLength, AIndex, ADestEncoding);
Ohne Encoding-Angabe ist der Standard bei Indy dann ASCII.

DEC6
function CalcString(const Value: string; Format: TDECFormatClass = nil): string; overload;
Delphi-Quellcode:
function TDECHash.CalcString(const Value: string; Format: TDECFormatClass): string;
var
  Size : Integer;
  Data : TBytes;
begin
  Result := '';
  if Length(Value) > 0 then
  begin
    {$IFDEF HAVE_STR_LIKE_ARRAY}
    Size  := Length(Value) * SizeOf(Value[low(Value)]);
    Data  := CalcBuffer(Value[low(Value)], Size);
    {$ELSE}
    Size  := Length(Value) * SizeOf(Value[1]);
    Data  := CalcBuffer(Value[1], Size);
    {$ENDIF}
    Result := StringOf(ValidFormat(Format).Encode(Data));
  end
  else
  begin
    SetLength(Data, 0);
    result := StringOf(ValidFormat(Format).Encode(CalcBuffer(Data, 0)));
  end;
end;
In der Methode wird CalcBuffer aufgerufen,
Delphi-Quellcode:
function TDECHash.CalcBuffer(const Buffer; BufferSize: Integer): TBytes;
in der mit dem übergebenen Wert dann als untypisierter Buffer weitergearbeitet wird.

dschiffler 19. Mär 2024 13:22

AW: MD5 - Unterschiede zw. Indy und DEC6
 
Danke Rolf.

Habe auch noch einmal verschiedene Werte getestet.

Mit System.Hash.THashMD5 von Delphi und TIdHashMessageDigest5 von Indy bekomme ich immer die gleichen Hash-Werte, so wie man es auch erwartet.

THash_MD5 von DEC6 gibt immer einen anderen Hash-Wert, was die Vermutung nahe legt, dass im DEC6 intern etwas anderes passiert.
Vielleicht kann TurboMagic etwas dazu sagen, wenn er den Thread vielleicht liest.

Gausi 19. Mär 2024 13:57

AW: MD5 - Unterschiede zw. Indy und DEC6
 
Zitat:

Zitat von dschiffler (Beitrag 1534832)
Habe auch noch einmal verschiedene Werte getestet.

Auch mit Umlauten? Das wäre ggf. noch eine Stolperstelle bgzl. Ansi/Ascii und UTF8.

Ansonsten sollte die Ursache ja jetzt klar sein. Wenn bei Indy per Default der String als ANSI-String (also 1 Byte pro Zeichen) angenommen wird, und bei TDECHash.CalcBuffer der übergebene String als untypisierter Buffer ankommt, dann werden da höchstwahrscheinlich 2 Byte pro Zeichen verarbeitet.

Rolf Frei 19. Mär 2024 14:55

AW: MD5 - Unterschiede zw. Indy und DEC6
 
Du müsstest auch mal abklären, was für ein Format zur Berechnung des MD5 der Webdienst benötigt. Vermutlich erwartet der nähmlich einen MD5 von einem UTF-8 string. In dem Fall musst du deinen String zuerst in UTF-8 umwandeln und dann von diesem den MD5 berechnen.

Delphi-Quellcode:
var
 b:TBytes;
 hash: string;
begin
  b := TEncoding.UTF8.GetBytes('Testwörter'); // StringOf(b) ergibt "Testwörter"
  hash := System.Hash.THashMD5.GetHashString(StringOf(b));
...
end;

Michael II 19. Mär 2024 15:55

AW: MD5 - Unterschiede zw. Indy und DEC6
 
Ich habe momentan DEC nicht installiert.
Aber wenn's immer noch so ist wie früher: Mit DEC wird doch ein Testprogramm für alle eingebauten Hash Funktionen mitgeliefert.
Hast du dort überprüft wie DEC die MD5 Testwerte berechnet? Ich nehme mal an, TurboMagic hat die Werte aus dem RFC1321 gewählt.

Stevie 19. Mär 2024 16:26

AW: MD5 - Unterschiede zw. Indy und DEC6
 
Bei Indy würde ich immer enUTF8 angeben, ansonsten wird wie bereits gesagt intern immer das ASCII encoding genutzt, was einfach alle Zeichen größer $7F als '?' interpretiert - siehe TIdASCIIEncoding.GetBytes in IdGlobal.pas

Ebenso musst du bei DEC dafür sorgen, dass er einen UTF8 String hasht und nicht einen UnicodeString (UTF16) - das kann man einfach mit einem Cast auf UTF8String bewerkstelligen, hier baut der Compiler immer die notwendige Konvertierungsfunktion ein. Durch die Überladung von CalcString mit RawByteString wird dann diese aufgerufen.

Delphi-Quellcode:
  var lMD5_Indy := TIdHashMessageDigest5.Create;
  try
    var sValue := lMD5_Indy.HashStringAsHex('Tästwert', enUTF8);
    Writeln(sValue);
  finally
    lMD5_Indy.Free;
  end;

  var lMD5_DEC := THash_MD5.Create;
  try
    var sValue := lMD5_DEC.CalcString(UTF8String('Tästwert'), TFormat_HEX);
    Writeln(sValue);
  finally
    lMD5_DEC.Free;
  end;
Ausgabe (Obacht, ich hab da nen ä in den String geschmuggelt, um das mit dem UTF8 zu testen):

9C6F9390DE3580AA8717DAA21D1E3622
9C6F9390DE3580AA8717DAA21D1E3622

Laut diverser online md5 Generatoren ist das wohl richtig.


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:40 Uhr.
Seite 1 von 3  1 23      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz