Seite 1 von 1
Hash-Werte aus Dateien ermitteln, und dann...?
Verfasst: Freitag 13. November 2015, 14:38
von Sophus
Hallo Leute,
im unten stehenden Quelltext lese ich eine *.Zip-Datei aus. Mittels der
namelist()-Methode lasse ich mir in der For-Schleife alle Dateien aus dem aktuellen Archiv ermitteln. Anschließend werden die einzelnen Dateien in der For-Schleife mit dem With-Statement geöffnet, und vom Inhalt der
jeweiligen Datei einen SHA521-Wert erzeugt, und anshcließend wird dieser Hash-Wert einer zuvor erstellte leere Liste hinzufügt. Sobald die For-Schleife ihre Arbeit getan hat, wird die Liste an die
hash_all-Funktion übergeben. Und nun stecke ich gedanklich fest. Ich habe ja nun eine ganze Reihe von Hash-Werten in der Liste. Und aus all diesen Hash-Werten möchte ich am Ende sozusagen einen Hash-Wert bekommen. Denn auf diesem Weg möchte ich dann ein Archiv "absichern". Zumindest war das meine Idee.
Code: Alles auswählen
# Import zipfile library
import zipfile
# Import hashlib library (md5 method is part of it)
import hashlib
def hash_all(prompt):
print "my prompt", prompt
def hash_file_content(file_name):
# Create a empty list for all hashes
list_hashes = []
file_path = zipfile.ZipFile(file_name, "r")
for name in file_path.namelist():
#print "All files are: ",name
try:
# Open,close, read file and calculate SHA512 on its contents
# Notice: Its should also open the file in binary mode (ex. rb),
# otherwise it might gets problems
with open(name,'rb') as file_to_check:
data = file_to_check.read()
# pipe contents of the file through
sha_512_returned = hashlib.sha512(data).hexdigest()
print "Hashed (", sha_512_returned ,") from content of file", name
list_hashes.append(sha_512_returned)
except Exception:
#print "Exception", Exception
pass
#print "list_hashes", list_hashes
hash_all(list_hashes)
if __name__ == "__main__":
zip_file_name = raw_input("Enter path completly: ")
hash_file_content(zip_file_name)
Re: Hash-Werte aus Dateien ermitteln, und dann...?
Verfasst: Freitag 13. November 2015, 14:41
von __deets__
Stattdessen kannst du auch einfach *ein* SHA512 Objekt erzeugen, alle Dateiinhalte mit "update" hinzufuegen, und gut ist. Oder du sparst dir gleich das gepfriemel in dem Archiv, und hashst das gesamte Archiv.
Re: Hash-Werte aus Dateien ermitteln, und dann...?
Verfasst: Freitag 13. November 2015, 15:07
von Sophus
Hallo __deeds__,
das mit der
update-Funktion ist mir gar nicht eingefallen. Aber deine Anmerkung, aus dem gesamtem Archiv einen Hash-Wert zu erstellen: Ist dies nicht etwas unsicher, weil dann aus den Dateinamen der jeweiligen Dateien im Archiv ein Hash-Wert erzeugt wird? Ich wollte nämlich die Inhalte der jeweiligen Dateien heranziehen und daraus Hash-Werte erstellen. Während du eine Antwortmöglichkeit geschrieben hast, habe ich das irgendwie versucht so zu lösen: In der
hash_all_hashes-Funktion wird die Liste noch einmal durch die For-Schleife geschickt, und die einzelnen Elemente der Liste werden dann wie in einem 'Array' in die zuvor erstelle
total_hash-Variable gepackt, und aus dem Inhalt dieser Variable wird dann ein einziger Hash-Wert erzeugt.
Neben der Tatsache, dass mein Vorgang ziemlich aufgebläht wirkt und dazu auch noch umständlich, frage ich mich, ob ich irgendwelche Speicher-Probleme bekommen könnte, wenn ich alle Elemente in eine Variable stopfe? Angenommen, ein Archiv ist knapp 100 MB groß, und hat weit über 500 einzelne Dateien. Käme ich mit meinem Vorhaben in ein Konflikt - bezüglich des Speichers?
Code: Alles auswählen
7# Import zipfile library
import zipfile
# Import hashlib library (md5 method is part of it)
import hashlib
def hash_all_hashes(prompt):
#print "my prompt", prompt
total_hash = ""
for hash_value in prompt:
total_hash = total_hash + hash_value
sha_512_returned = hashlib.sha512(total_hash).hexdigest()
return sha_512_returned
def hash_file_content(file_name):
# Create a empty list for all hashes
list_hashes = []
file_path = zipfile.ZipFile(file_name, "r")
for name in file_path.namelist():
#print "All files are: ",name
try:
# Open,close, read file and calculate SHA512 on its contents
# Notice: Its should also open the file in binary mode (ex. rb),
# otherwise it might gets problems
with open(name,'rb') as file_to_check:
data = file_to_check.read()
# pipe contents of the file through
sha_512_returned = hashlib.sha512(data).hexdigest()
#print "Hashed (", sha_512_returned ,") from content of file", name
list_hashes.append(sha_512_returned)
except Exception:
#print "Exception", Exception
pass
#print "list_hashes", list_hashes
result = hash_all_hashes(list_hashes)
return result
if __name__ == "__main__":
zip_file_name = raw_input("Enter path completly: ")
my_hashed = hash_file_content(zip_file_name)
print "my_hashed", my_hashed
Re: Hash-Werte aus Dateien ermitteln, und dann...?
Verfasst: Freitag 13. November 2015, 15:11
von kbr
@Sophus: nein, Du verwendest dabei nicht die Dateinamen, sondern den Inhalt des Archivs.
Sei "fn" der Pfad zum zip-Archiv:
Code: Alles auswählen
with open(fn, 'br') as f:
digest = hashlib.sha512(f.read()).hexdigest()
Re: Hash-Werte aus Dateien ermitteln, und dann...?
Verfasst: Freitag 13. November 2015, 15:21
von Sophus
Hallo kbr,
deine Variante ist ja um einiges kürzer als meine. Das gefällt mir. Aber eine Sache verstehe ich noch nicht ganz. Der Inhalt eines Archivs besteht ja aus Dateien, richtig? Und somit sind die Dateinamen sozusagen der Inhalt oder? Ich betrachte das so, wenn ich ein Archiv öffne, sehe ich ja noch nicht die Inhalte der jeweiligen Inhalte der Dateien, sondern nur die Dateinamen. Und deswegen ging ich davon aus, dass man dabei die Dateinamen nimmt, und daraus einen Hash-Wert erzeugt. Oder werden bei deiner Variante alle Inhalte der Dateien eingelesen und daraus dann ein Hash-Wert erzeugt?
Re: Hash-Werte aus Dateien ermitteln, und dann...?
Verfasst: Freitag 13. November 2015, 15:23
von BlackJack
@Sophus: Die Variante von kbr öffnet kein Archiv sondern irgendeine beliebige Datei und berechnet einen Hash über die Bytes in dieser Datei. Die beliebige Datei kann auch eine Archivdatei sein, aber das ist für das vorhaben ja völlig irrelevant.
Re: Hash-Werte aus Dateien ermitteln, und dann...?
Verfasst: Freitag 13. November 2015, 15:29
von Sophus
Hallo BlackJack,
dann ist die Variante von kbr nicht ganz sicher? Ich meine, in meiner Variante, auch wenn sie nicht perfekt ist, wird jede einzelne Datei eingelesen, dessen Inhalt raus gelesen, daraus einen Wert erstellen, und am Ende aus all den Werten einen Wert erzeugt. Nur war mein Anliegen, dass dieser Weg zu Probleme führen könnte, wenn ein Archiv über 100MB groß ist, und über 200 Dateien beinhaltet. Wäre das möglich?
Re: Hash-Werte aus Dateien ermitteln, und dann...?
Verfasst: Freitag 13. November 2015, 15:39
von Sirius3
@Sophus: was ist Dein Ziel, das Du erreichen willst? Dass eine Datei (sei es nun ein Archiv oder sonstirgendwas) nicht verändert wird, oder dass der Inhalt der Dateien, die irgendwie zu einem Archiv gepackt werden, nicht verändert werden?
Probleme mit dem Speicher bekommst Du nicht, wenn Du die update-Methode benutzt:
Code: Alles auswählen
with open(archivname, 'rb') as data:
sha = hashlib.sha512()
for chunk in iter(lambda: data.read(65536), bool):
sha.update(chunk)
digest = sha.hexdigest()
Re: Hash-Werte aus Dateien ermitteln, und dann...?
Verfasst: Freitag 13. November 2015, 15:48
von Sophus
Hallo Sirius3,
letzteres. Die Dateien, die zum Archiv gepackt wurden, dürfen nicht verändert werden. Ich dachte dabei sehr stark an eine Art "CheckSum". Mir geht es darum, dass ich am Ende sagen kann, dass ist ein "bekanntes" Archiv, und kein fremdes Archiv.
Dein Vorschlag gefällt mir sehr gut. Werde ich mir gleich mal einstudieren.
Re: Hash-Werte aus Dateien ermitteln, und dann...?
Verfasst: Freitag 13. November 2015, 15:55
von cofi
Wenn es dir schon um die Dateien und nicht erst um das ganze geht, darfst du nicht erst das Archiv pruefen. Es sei denn auch Dateinamen und die anderen Metadaten sind fuer deine Gleichheit relevant.
Re: Hash-Werte aus Dateien ermitteln, und dann...?
Verfasst: Freitag 13. November 2015, 15:56
von BlackJack
@Sophus: Also willst Du doch eigentlich ersteres: Wenn sich das Archiv verändert hat, dann ist da doch der Fall mit enthalten das sich eine Datei in dem Archiv geändert hat. Denn wenn man den Inhalt einer Datei im Archiv verändert, verändert das ja das Archiv selbst. Also warum so umständlich und nicht einfach einen Hash-Wert über die gesamte Archivdatei erstellen?
Re: Hash-Werte aus Dateien ermitteln, und dann...?
Verfasst: Freitag 13. November 2015, 16:04
von Sophus
@BlackJack: Das ist eine verdammt gute Frage. Ich ging davon aus, dass die Inhalte der Dateien und das Archiv als Ganzes nicht miteinander zutun haben. Ich betrachte das Archiv als eine Art Container, in der alle Dateien gepackt werden. Ich ging nicht davon aus, sobald der Inhalt einer Datei ändern, dass dies sich auf das Archiv auswirkt. Jedoch habe ich mich gerade mit Sirius3s Variante auseinander gesetzt, und diese scheint nicht zu funktionieren. Die Variante nimmt eine Datei aus dem Archiv vor, und "macht" dann nichts mehr? Es kommt keine Fehlermeldung. Hier der Quelltext:
Code: Alles auswählen
def new_one_digest(prompt):
file_path = zipfile.ZipFile(prompt, "r")
for name in file_path.namelist():
print "NAME", name
try:
with open(name, 'rb') as data:
sha = hashlib.sha512()
for chunk in iter(lambda: data.read(95536), bool):
sha.update(chunk)
digest = sha.hexdigest()
print "New DIGEST", digest
except Exception:
pass
if __name__ == "__main__":
zip_file_name = raw_input("Enter path completly: ")
my_hashed_code = new_one_digest(zip_file_name)
Re: Hash-Werte aus Dateien ermitteln, und dann...?
Verfasst: Freitag 13. November 2015, 16:14
von kbr
@Sophus: Ein Archiv ist eine Datei, wie jede andere auch. Zur Ermittlung des Hashwertes liest Du diese daher einfach als Binärdatei und nicht als Zip-Datei. Dann funktioniert auch das Beispiel von Sirius3.
Re: Hash-Werte aus Dateien ermitteln, und dann...?
Verfasst: Freitag 13. November 2015, 16:22
von Sophus
Hallo kbr,
dann mache ich wirklich was falsch. Hier, wie ich Sirius3s Variante anwende:
Code: Alles auswählen
def new_one_digest(prompt):
with open(prompt, 'rb') as data:
sha = hashlib.sha512()
for chunk in iter(lambda: data.read(65536), bool):
sha.update(chunk)
digest = sha.hexdigest()
return digest
if __name__ == "__main__":
zip_file_name = raw_input("Enter path completly: ") # Enter path completly with file name with file extension!
my_hashed_code = new_one_digest(zip_file_name)
print "my hashed code: ", my_hashed_code
Re: Hash-Werte aus Dateien ermitteln, und dann...?
Verfasst: Freitag 13. November 2015, 16:27
von BlackJack
Sophus: Wie kann ein Archiv nichts mit dem Inhalt der Dateien zu tun haben die in dem Archiv stecken‽ Das ist doch wohl offensichtlich das sich das Archiv ändert wenn man eine Datei darin ändert, das Archiv besteht doch aus den Daten der Dateien die darin gespeichert sind + Metadaten die sonst im Dateisystem gespeichert sind.
Das letzte Argument von `iter()` ist falsch, das muss anstelle von `bool` eine leere Zeichenkette sein.
Re: Hash-Werte aus Dateien ermitteln, und dann...?
Verfasst: Freitag 13. November 2015, 16:38
von Sophus
Nun, ich habe mir mal den Spaß erlaubt, und bei Sirius3s Variante überall eine Print-Anweisung anzusetzen, um mitverfolgen zu können, wie das Skript arbeitet. Mir fiel sehr stark auf, dass das Skript äußerst langsam arbeitet. Dabei ist meine Zip-Datei derzeit nur 34 MB groß. Ich vermute mal, dass Sirius3s Variante sehr stark ausgebremst wird?
Code: Alles auswählen
def new_one_digest(prompt):
print "Starting to hash"
print "Path", prompt
with open(prompt, 'rb') as data:
print "data", data
sha = hashlib.sha512()
for chunk in iter(lambda: data.read(65536), bool):
print "chunk", chunk
sha.update(chunk)
digest = sha.hexdigest()
return digest
Also bleibt mir nichts anderes übrig, als diese Variante zu nehmen?
Code: Alles auswählen
def hash_zip(prompt):
with open(prompt, 'rb') as f:
digest = hashlib.sha512(f.read()).hexdigest()
print "digest", digest
return digest
Denn so wie BlackJack und kbr es mir erklärt haben, verändert sich das Archiv ebenfalls, sobald sich eine Datei im Archiv ändert.
Re: Hash-Werte aus Dateien ermitteln, und dann...?
Verfasst: Freitag 13. November 2015, 16:46
von __deets__
Du hast *immer noch* einen Fehler in deiner Schleife, bei der du "bool" statt "''" uebergibst. Damit ist deine Abbruchbedingung falsch, und das fuehrt dann zu einer kleinen Endlosschleife - die dauert tatsaechlich etwas laenger.
Denn ansonsten sind die beiden Ansaetze gleich & es wuerde mich auch sehr wundern, wenn die Performance da gross unterschiedlich ist.
Was dass dann wiederum mit deiner Schlussfolgerung am Ende zu tun hat, weiss ich auch nicht...
Re: Hash-Werte aus Dateien ermitteln, und dann...?
Verfasst: Freitag 13. November 2015, 17:05
von Sophus
Um dieses letzte Argument in der
iter()-Methode zu verstehen, versuche ich das mal nachzuvollziehen.
Innerhalb des Iteratorobjektes wird eine anonyme Funktion (Lambda) erzeugt. Hier hat lambda keine Argumentationsliste, die vor dem Doppelpunkt stehen. Anschließend folgt ein Ausdruck, und zwar, dass das Objekt
data (hier: Zip-Datei) gelesen wird. In der
read()Methode wird dann die Anzahl der Bytes übergeben, die gelesen werden sollen. Und in
bool können nun zwei Werte, einmal True oder False enthalten sein. Eigentlich dient das letzte Argument der
iter()-Methode dazu, um diese For-Schleife bei einer bestimmten Bedingung abzubrechen.
Habe ich das alles so richtig verstanden?
Re: Hash-Werte aus Dateien ermitteln, und dann...?
Verfasst: Freitag 13. November 2015, 17:07
von BlackJack
@Sophus: Das letzte Argument ist in dem gezeigten Quelltext der Typ `bool`, der kann nicht zwei Werte enthalten der ist selber *ein* Wert. Und zwar, wie schon gesagt, der *falsche* Wert. Richtig wäre eine leere Zeichenkette beziehungsweise Bytekette.
Re: Hash-Werte aus Dateien ermitteln, und dann...?
Verfasst: Freitag 13. November 2015, 17:42
von __deets__
Sophus hat geschrieben:Um dieses letzte Argument in der iter()-Methode zu verstehen, versuche ich das mal nachzuvollziehen.
Ein alternativer Ansatz: Dokumentation lesen:
Code: Alles auswählen
$ pydoc iter
Help on built-in function iter in module __builtin__:
iter(...)
iter(collection) -> iterator
iter(callable, sentinel) -> iterator
Get an iterator from an object. In the first form, the argument must
supply its own iterator, or be a sequence.
In the second form, the callable is called until it returns the sentinel.
(END)