AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

DEC 5.2 String hashen?

Ein Thema von a.def · begonnen am 2. Mai 2017 · letzter Beitrag vom 7. Mai 2017
Thema geschlossen
Seite 1 von 2  1 2      
a.def
(Gast)

n/a Beiträge
 
#1

AW: DEC 5.2 String hashen?

  Alt 5. Mai 2017, 10:04
Ich habe das jetzt mal so gelöst. Ich bin von TStringStream weg, da es hier als Masochismus betitelt wurde.
Leider aber wieder hin zu AnsiString. Mit String bekomme ich nur Salat als Ergebnis.
Es funktioniert, aber es ist bestimmt nicht perfekt.

Delphi-Quellcode:
       SetLength(s, aFileStream.Size - (32 * SizeOf(Byte)));
       aFileStream.Read(s[1], Length(s));
       s:= THashFunctions_Selftest.CalcHash(s);

       Result := s;
Das Problem mit dem hohen Speicher bekomme ich leider nicht weg, da ich das SetLength nicht einfach weglassen kann
 
nahpets
(Gast)

n/a Beiträge
 
#2

AW: DEC 5.2 String hashen?

  Alt 5. Mai 2017, 10:11
Naja, wenn Du 'nen Hash über 50 MB machen willst, musst Du auch die 50 MB einmal lesen.

Du wirst also immer einmal die Menge Speicher benötigen, die der Größer der EXE entspricht plus dem, was vom Programm ansonsten noch zum Ermitteln des Hashes benötigt wird.

Egal welche Methode Du wählst: Um mindestens einmal alles Lesen wirst Du nicht herumkommen.
 
Michael II

Registriert seit: 1. Dez 2012
Ort: CH BE Eriswil
772 Beiträge
 
Delphi 11 Alexandria
 
#3

AW: DEC 5.2 String hashen?

  Alt 5. Mai 2017, 10:59
Wenn du den Hash selbst ermitteln musst, dann empfehle ich dir dies Stück für Stück zu tun.

Ich hatte mal Code gepostet, welcher gleich alles las. Das ist natürlich für extrem grosse Files dumm. [Aber für die meisten "normalen Fälle" ausreichend.]


Wenn du über das ganze File hashen willst, dann nimm doch eine vorgefertigte Methode, zum Beispiel

Delphi-Quellcode:
var b : TByte;
    rbs : rawbytestring;

...
...

b := System.hash.THashMD5.GetHashBytesFromFile( );
oder
rbs := System.hash.THashMD5.GetHashStringFromFile( );
Schau dir an, wie GetHashBytesFromFile programmiert ist.

...BytesFromFile liefert dir den 128Bit Hash in 16Bytes, und die ...StringFromFile liefert dir einen hex-String der Länge 32.

[Fritz hat mal eine Version gepostet, welche praktisch 1:1 gleich funktioniert. Die Version Fritz hasht aber bei der letzten Tranche über zu viele Bytes und liefert in fast nur in 1/1MB aller Fälle einen korrekten Wert.]



Wenn du nur über Teile eines Files hashen willst, dann könntest du es wie im Code unten tun (ich habe hier die Bytevariante ausgebaut, die hex Variante kannst du daraus ja leicht gewinnen):



Delphi-Quellcode:
procedure AddHashBytes( var lHasher: THashMD5; const AStream: TStream; von, bis : int64 );
const
   BufferSize = 64*1024;
var
  lStreamBytes: TBytes;
  Lies, SollLesen : int64;
  len : integer;
begin
  if bis >= AStream.size then bis := Astream.size-1;
  if von < 0 then von := 0;
  if bis >= von then
  begin
    setlength(lStreamBytes, BufferSize);
    AStream.Position := von;
    SollLesen := bis-von+1;
    while SollLesen > 0 do
    begin
      if SollLesen >= BufferSize then Lies := BufferSize else Lies := SollLesen;
      len := Astream.ReadData(lStreamBytes, Lies);
      if len = 0 then break;
      dec(SollLesen,len);
      lHasher.Update(lStreamBytes, len);
    end;
  end;
end;



function GetHashFromFile( aFileName : string; vonbis : array of int64 ) : TBytes;
var f : TFileStream;
   LMD5: THashMD5;
   i, len : integer;
   von, bis : int64;

begin
  f := TFileStream.Create( aFileName, fmOpenRead );
 try
  LMD5 := THashMD5.Create;
  LMD5.Reset;
  len := length(vonbis);
  if len < 2 then
  begin
      AddHashBytes( LMD5, f, 0, f.Size-1 );
  end
  else
  begin
      i := 0;
      while len-i >= 2 do
      begin
        von := vonbis[i];
        bis := vonbis[i+1];
        if von < 0 then von := f.Size+von;
        if bis < 0 then bis := f.Size+bis;

        AddHashBytes( LMD5, f, von, bis);
        inc(i,2);
      end;
  end;
  Result := LMD5.HashAsBytes;
 finally
  f.Free;
 end;
end;



Mögliche Aufrufe:
Beispiel 1:
Wenn du von Byte 0 bis 2000 und von Byte 2001 bis ans Ende hashen willst:

GetHashFromFile( filename, [0, 2000, 2001, maxint] );

Damit hashst du ja übers ganze File und erhältst natürlich exakt den gleichen Wert wie via
System.hash.THashMD5.GetHashBytesFromFile( filename );

Beispiel 2:
Wenn du Bytes 192435 - 192450 nicht "mithashen" willst:
GetHashFromFile( filename, [0, 192434, 192451, maxint] );

Beispiel 3:
Negative Werte:
Wenn du die letzten 16 Bytes des Files nicht hashen willst:
GetHashFromFile( filename, [0, -17] );




Ich hoffe, das hilft. Korrekturen bitte direkt an mich - Dankeschön.
Michael Gasser

Geändert von Michael II ( 5. Mai 2017 um 18:55 Uhr)
 
Benutzerbild von p80286
p80286

Registriert seit: 28. Apr 2008
Ort: Stolberg (Rhl)
6.659 Beiträge
 
FreePascal / Lazarus
 
#4

AW: DEC 5.2 String hashen?

  Alt 5. Mai 2017, 11:17
Ich habe das jetzt mal so gelöst. Ich bin von TStringStream weg, da es hier als Masochismus betitelt wurde.
Leider aber wieder hin zu AnsiString. Mit String bekomme ich nur Salat als Ergebnis.
Es funktioniert, aber es ist bestimmt nicht perfekt.

Delphi-Quellcode:
       SetLength(s, aFileStream.Size - (32 * SizeOf(Byte)));
       aFileStream.Read(s[1], Length(s));
       s:= THashFunctions_Selftest.CalcHash(s);

       Result := s;
Das Problem mit dem hohen Speicher bekomme ich leider nicht weg, da ich das SetLength nicht einfach weglassen kann
Es ist mehr als einmal erwähnt worden, daß der HASH nicht über Chars/Strings/Text gebildet wird, sondern über die in der Datei enthaltenen Bytes.
du kannst natürlich eine String-Struktur als Aufbewahrungsort Deiner Bytes verwenden aber das schein mir hier so sinnvoll wie sich ein Loch in die Kniescheibe zu bohren und Marmelade hinein zu schmieren, machen kann man viel wenn der Tag lang ist.

Zitat:
Das Problem mit dem hohen Speicher bekomme ich leider nicht weg, da ich das SetLength nicht einfach weglassen kann
Wenn Du viele Daten auf einmal verarbeiten willst, dann benötigst Du auch viel Speicher. Das "SetLength" ist nur ein Symptom Deiner Datenverarbeitung.

Gruß
K-H
Programme gehorchen nicht Deinen Absichten sondern Deinen Anweisungen
R.E.D retired error detector
 
a.def
(Gast)

n/a Beiträge
 
#5

AW: DEC 5.2 String hashen?

  Alt 5. Mai 2017, 12:02
Zitat:
Wenn du über das ganze File hashen willst, dann nimm doch eine vorgefertigte Methode, zum Beispiel
Die Delphi-eigenen Methoden sind elendig langsam. Wenn THashMD5 bei mir 200ms braucht, braucht DEC für dieselbe Arbeit ~60ms.

Zitat:
Ich hoffe, das hilft. Korrekturen bitte direkt an mich - Dankeschön.
+
Zitat:
Es ist mehr als einmal erwähnt worden, daß der HASH nicht über Chars/Strings/Text gebildet wird, sondern über die in der Datei enthaltenen Bytes.
= *klick*

Delphi-Quellcode:
aByteStream := TBytesStream.Create;
try
 aByteStream.LoadFromFile(aFileName);

 aByteStream2 := TBytesStream.Create;
 try
  aByteStream2.Write(aByteStream.Bytes[0], aByteStream.Size); // aktuellen Stream zwischenspeichern
  sHash := THashFunctions_Selftest.CalcHash(Trim(TEncoding.ANSI.GetString(aByteStream2.Bytes))); // einen Hash der im neu erzeugten Stream enthaltenen Bytes erzeugen

  aByteStream.Size := aByteStream.Size + iHashLengthInBytes; // die Größe des ALTEN streams um maximale Länge des Hashs vergrößern (?)
  Move(AnsiString(sHash)[1], aByteStream.Bytes[aByteStream.Size - iHashLengthInBytes], iHashLengthInBytes); // Hash im alten Stream ablegen
  aByteStream.SaveToFile(aFileName); // Alten, modifizierten Stream speichern
 finally
  aByteStream2.Free;
 end;
finally
 aByteStream.FreeM
end;

// Eine kürzere Variante, ohne aByteStream2 wäre
sHash := THashFunctions_Selftest.CalcHash(Trim(TEncoding.ANSI.GetString(aByteStream.Bytes))); // einen Hash der im Stream enthaltenen Bytes erzeugen
aByteStream.Size := aByteStream.Size + iHashLengthInBytes; // die Größe des ALTEN streams um maximale Länge des Hashs vergrößern (?)
Move(AnsiString(sHash)[1], aByteStream.Bytes[aByteStream.Size - iHashLengthInBytes], iHashLengthInBytes); // Hash im alten Stream ablegen
aByteStream.SaveToFile(aFileName); // Stream speichern
Den Dateiinhalt mit am Ende hängenden Hash, lese ich so aus
Delphi-Quellcode:
if aByteStream.Size > iHashLengthInBytes then
 begin
  aByteStream.Read(aByteStream.Bytes[0], aByteStream.Size - iHashLengthInBytes);
  Result := THashFunctions_Selftest.CalcHash(Trim(TEncoding.ANSI.GetString(aByteStream.Bytes, 0, aByteStream.Size - iHashLengthInBytes)));
 end;

// Dateiinhalt könnte sein: _TEST_TEST_2B3CC5E89E09A889CC10D0021284AB06EA6FF72BCFE78110C8D9B71A6030375F
// Ausgelesen wird dann "_TEST_TEST_" und davon er Hash gebildet.

Geändert von a.def ( 5. Mai 2017 um 12:09 Uhr)
 
Michael II

Registriert seit: 1. Dez 2012
Ort: CH BE Eriswil
772 Beiträge
 
Delphi 11 Alexandria
 
#6

AW: DEC 5.2 String hashen?

  Alt 5. Mai 2017, 12:45
Zitat:
Die Delphi-eigenen Methoden sind elendig langsam. Wenn THashMD5 bei mir 200ms braucht, braucht DEC für dieselbe Arbeit ~60ms.
Und was hat DEC mit MD5 zu tun?
Das liegt nicht an Delphi - du vergleichst hier zwei Hash Funktionen miteinander.


Ich habe dir anhand eines Beispiels [md5] zeigen wollen, wie du bei der Berechnung des MD5 Hashs einer beliebig grossen Datei immer nur einen Teil und nie das ganze File laden musst. [Du hattest wegen RAM schiesst in die Höhe geschrieben - und ich dachte ich mache dir eine Freude, wenn du siehst, dass dies nicht sein muss. und erst noch alles in Byte statt string]

Wenn du lieber SHA1 verwendest, dann verwendest du lieber SHA1 - dein Entscheid... sei mit deinem Code erst dann zufrieden, wenn eine Suche nach dem Wort "string" ins Leere läuft.

Wenn du alles in deinem Code Byte basiert machst, passieren auch nicht Fehler wie dieser hier:
Weg mit dem Trim [ich weiss, ich wiederhole mich] Grund: Solltest du mit diesem Code irgendwann den Hash Wert einer Datei mit Leerzeichen am Anfang oder Ende des Files berechnen wollen [OK, wie erwähnt bei .exe mind. am Anfang nicht der Fall], dann rechnest du diese nicht mit und die Berechnung geht in die Hose.


sHash := THashFunctions_Selftest.CalcHash([B]Trim([/B]TEncoding.ANSI.GetString(aByteStream.Bytes)));
Michael Gasser
 
a.def
(Gast)

n/a Beiträge
 
#7

AW: DEC 5.2 String hashen?

  Alt 5. Mai 2017, 13:40
Zitat:
Du hattest wegen RAM schiesst in die Höhe geschrieben - und ich dachte ich mache dir eine Freude, wenn du siehst, dass dies nicht sein muss.
Keine Sorge das hast du Mein Code ist jetzt so aufgebaut, dass nur noch 1x maximal die Datei geladen wird (statt mehrfach). Vorher habe ich die glaube ich 3x geladen.

Zitat:
Weg mit dem Trim. ich weiss, ich wiederhole mich
Ohne Trim funktioniert das leider nicht. Ich weiß nicht genau warum aber ich schätze Trim entfernt mehr als gut ist.
Wenn ich die Bytes der Datei ohne Trim hashe und später auch ohne Trim wieder auslese und dann hashe, sind die Ergebnisse unterschiedlich. Warum weiß ich nicht.

Edit
-- es funktioniert aber wunderbar bisher

Geändert von a.def ( 5. Mai 2017 um 13:48 Uhr)
 
Benutzerbild von p80286
p80286

Registriert seit: 28. Apr 2008
Ort: Stolberg (Rhl)
6.659 Beiträge
 
FreePascal / Lazarus
 
#8

AW: DEC 5.2 String hashen?

  Alt 5. Mai 2017, 15:16
Result := THashFunctions_Selftest.CalcHash([B]Trim(TEncoding.ANSI.GetString[/B](aByteStream.Bytes, 0, aByteStream.Size - iHashLengthInBytes))); Warum kannst Du Dich nicht von dem verf***** String trennen?

Siehst Du in dem Beispiel vom Michael II irgendwo einen String oder ein Char?

U.U wäre es ganz vernünftig, wenn Du noch einmal ganz von vorne anfangen würdest.....

Gruß
K-H
Programme gehorchen nicht Deinen Absichten sondern Deinen Anweisungen
R.E.D retired error detector
 
a.def
(Gast)

n/a Beiträge
 
#9

AW: DEC 5.2 String hashen?

  Alt 5. Mai 2017, 15:20
Zitat:
Warum kannst Du Dich nicht von dem verf***** String trennen?
Was soll denn an dem String so schlimm sein? Er wird vollkommen korrekt in meine Exe geschrieben und auch geladen. Was will ich denn mehr?
Ich habe schon alles auf TBytes umgestellt. Aber den Rückgabewert möchte ich dennoch gerne als String haben.

P.S.: kein Grund ausfallend zu werden
 
Michael II

Registriert seit: 1. Dez 2012
Ort: CH BE Eriswil
772 Beiträge
 
Delphi 11 Alexandria
 
#10

AW: DEC 5.2 String hashen?

  Alt 5. Mai 2017, 15:46
Hallo a.def,

ich habe dir hier noch rasch die ähnliche Funktion für SHA1 geschrieben:

Delphi-Quellcode:
procedure AddSHA1HashBytes( var lHasher: THashSHA1; const AStream: TStream; von, bis : int64 );
const
   BufferSize = 64*1024;
var
  lStreamBytes: TBytes;
  Lies, SollLesen : int64;
  len : integer;
begin
  if bis >= AStream.size then bis := Astream.size-1;
  if von < 0 then von := 0;
  if bis >= von then
  begin
    setlength(lStreamBytes, BufferSize);
    AStream.Position := von;
    SollLesen := bis-von+1;
    while SollLesen > 0 do
    begin
      if SollLesen >= BufferSize then Lies := BufferSize else Lies := SollLesen;
      len := Astream.ReadData(lStreamBytes, Lies);
      if len = 0 then break;
      dec(SollLesen,len);
      lHasher.Update(lStreamBytes, len);
    end;
  end;
end;



function GetSHA1HashFromFile( aFileName : string; vonbis : array of int64 ) : TBytes;
var f : TFileStream;
   lSHA1: THashSHA1;
   i, len : integer;
   von, bis : int64;

begin
  f := TFileStream.Create( aFileName, fmOpenRead );
 try
  lSHA1 := THashSHA1.Create;
  lSHA1.Reset;
  len := length(vonbis);
  if len < 2 then
  begin
      AddSHA1HashBytes( lSHA1, f, 0, f.Size-1 );
  end
  else
  begin
      i := 0;
      while len-i >= 2 do
      begin
        von := vonbis[i];
        bis := vonbis[i+1];
        if von < 0 then von := f.Size+von;
        if bis < 0 then bis := f.Size+bis;

        AddSHA1HashBytes( lSHA1, f, von, bis);
        inc(i,2);
      end;
  end;
  Result := lSHA1.HashAsBytes;
 finally
  f.Free;
 end;
end;


Wenn du von Byte 0 bis 2000 und von Byte 2001 bis ans Ende hashen willst:

GetSHA1HashFromFile( filename, [0, 2000, 2001, maxint] );

Damit hashst du übers ganze File und erhältst natürlich exakt den gleichen Wert wie via
System.hash.THashSHA1.GetHashBytesFromFile( filename );

Beispiel 2:
Wenn du die 20 Bytes 192435 - 192454 nicht "mithashen" willst:
GetSHA1HashFromFile( filename, [0, 192434, 192455, maxint] );
Wenn du deinen SHA1 Hash Wert h ins Programm schreibst und h ab Position 192435 abgelegt ist, dann ist dies der Aufruf der Wahl .

Beispiel 3:
Ein positiver Wert n wird interpretiert als Fileposition n.
Ein negativer Wert n wird interpretiert als Fileposition fsize+n.

GetSHA1HashFromFile( filename, [0, -21] );

Wenn du zum Beispiel an dein File einen SHA1 Hash (20 Bytes) angehängt hast, dann hashst du in diesem Beispiel über dein File, nicht aber über den angehängten Hash Wert.

Beispiel 4:
Du kannst natürlich über beliebig viele Intervalle hashen, zum Beispiel über drei:
GetSHA1HashFromFile( filename, [0,255, 256+pesig, 256+pesig+peofs-1, -20,maxint] );
Michael Gasser

Geändert von Michael II ( 5. Mai 2017 um 18:57 Uhr)
 
Thema geschlossen
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:12 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz