Warum unterscheidet sich das von Python berechnete „hashlib.sha1“ von „git hash-object“ für eine Datei?

Lesezeit: 3 Minuten

Benutzer-Avatar
Ikke

Ich versuche, den SHA-1-Wert einer Datei zu berechnen.

Ich habe dieses Skript erstellt:

def hashfile(filepath):
    sha1 = hashlib.sha1()
    f = open(filepath, 'rb')
    try:
        sha1.update(f.read())
    finally:
        f.close()
    return sha1.hexdigest()

Für eine bestimmte Datei bekomme ich diesen Hashwert:
8c3e109ff260f7b11087974ef7bcdbdc69a0a3b9

Aber wenn ich den Wert mit git hash_object berechne, dann bekomme ich diesen Wert: d339346ca154f6ed9e92205c3c5c38112e761eb7

Wie kommt es, dass sie sich unterscheiden? Mache ich etwas falsch oder kann ich den Unterschied einfach ignorieren?

  • Sie können den Unterschied nicht wirklich ignorieren, wenn Sie vorhaben, die Hashes zusammen zu verwenden.

    – Matthew Scharley

    8. Dezember 2009 um 21:16 Uhr

  • Ich habe vergessen zu erwähnen, dass ich nur Git als Referenz verwendet habe und sie nicht zusammen verwenden werde.

    – Ikke

    8. Dezember 2009 um 21:24 Uhr

  • Wenn die Datei ziemlich groß sein könnte, können Sie sie blockweise verarbeiten, sodass Sie nicht das Ganze auf einmal im RAM benötigen: stackoverflow.com/questions/7829499/…

    – rakslice

    1. August 2013 um 18:24 Uhr

  • Mögliches Duplikat von Wie berechnet Git Datei-Hashes? Minimalbeispiele 😉

    – Ciro Santilli Путлер Капут 六四事

    17. Mai 2016 um 10:14 Uhr


Benutzer-Avatar
Brian R. Bondy

git berechnet Hashes wie folgt:

sha1("blob " + filesize + "\0" + data)

Bezug

  • Kein Problem, der referenzierte Link ist ganz anders, habe ihn nur zufällig gefunden.

    – Brian R. Bondy

    8. Dezember 2009 um 21:21 Uhr

  • Es sollte erwähnt werden, dass git dies tut, um Längenerweiterungsangriffe zu vermeiden.

    – Allmächtig

    8. Dezember 2009 um 21:56 Uhr

  • Eine vollständige Implementierung dieses Vorschlags finden Sie in der Frage Git SHA1 ohne Git zuweisen.

    – Mark Booth

    10. Juni 2013 um 0:07 Uhr


Benutzer-Avatar
Ben

Als Referenz, hier ist eine kürzere Version:

def sha1OfFile(filepath):
    import hashlib
    with open(filepath, 'rb') as f:
        return hashlib.sha1(f.read()).hexdigest()

Auf den zweiten Blick: Obwohl ich es noch nie gesehen habe, denke ich, dass es Potenzial dafür gibt f.read() um weniger als die vollständige Datei zurückzugeben, oder bei einer Datei mit vielen Gigabyte, damit f.read() nicht mehr genügend Arbeitsspeicher zur Verfügung steht. Lassen Sie uns zur Erbauung aller darüber nachdenken, wie das behoben werden kann: Eine erste Lösung dafür ist:

def sha1OfFile(filepath):
    import hashlib
    sha = hashlib.sha1()
    with open(filepath, 'rb') as f:
        for line in f:
            sha.update(line)
        return sha.hexdigest()

Allerdings gibt es dafür keine Garantie '\n' überhaupt in der Datei auftaucht, also die Tatsache, dass die for Schleife gibt uns Blöcke der Datei, die auf enden '\n' könnte uns das gleiche Problem geben, das wir ursprünglich hatten. Leider sehe ich keinen ähnlich pythonischen Weg, um möglichst große Blöcke der Datei zu durchlaufen, was meiner Meinung nach bedeutet, dass wir bei a festsitzen while True: ... break Schleife und mit einer magischen Zahl für die Blockgröße:

def sha1OfFile(filepath):
    import hashlib
    sha = hashlib.sha1()
    with open(filepath, 'rb') as f:
        while True:
            block = f.read(2**10) # Magic number: one-megabyte blocks.
            if not block: break
            sha.update(block)
        return sha.hexdigest()

Wer sagt natürlich, dass wir Ein-Megabyte-Strings speichern können? Wahrscheinlich können wir das, aber was ist, wenn wir uns auf einem winzigen eingebetteten Computer befinden?

Ich wünschte, ich könnte mir einen saubereren Weg vorstellen, der bei riesigen Dateien garantiert nicht zu wenig Speicher hat und der keine magischen Zahlen hat und der so gut funktioniert wie die ursprüngliche einfache Pythonic-Lösung.

  • Bei näherer Überlegung kann dies zu Problemen führen, wenn f.read() nicht die gesamte Datei zurückgeben kann (z. B. im Fall von Multi-Gigabyte-Dateien) und daher wahrscheinlich über Chunks iterieren sollte.

    – Ben

    17. April 2014 um 12:44 Uhr

1282580cookie-checkWarum unterscheidet sich das von Python berechnete „hashlib.sha1“ von „git hash-object“ für eine Datei?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy