Entwicklertools · SHA-Hash-Rechner
Gleicher Text, unterschiedlich SHA-256: Zeilenumbrüche, Codierungen und versteckte Bytes
· Wie es funktioniert
sha-256 Kodierung Textverarbeitung Debugging
Die Befehlszeile sagt eine Sache und der Browser sagt eine andere für etwas, das wie derselbe Text aussieht. Nachgestellte Zeilenumbrüche, UTF-16 und CRLF erklären fast jeden Fall; Dieser Beitrag zeigt, wie man die versteckten Bytes findet.
echo sagt einen Hash, das Tool sagt einen anderen – die alltägliche Nichtübereinstimmung und warum keiner von beiden falsch ist
Ein Terminal meldet einen SHA-256-Digest und ein Browser meldet einen anderen für scheinbar identischen Text. Das Befehlszeilentool ist nicht kaputt und der Browser auch nicht. Die gehashten Bytes sind nicht identisch, auch wenn die sichtbaren Zeichen identisch aussehen. Dieser Beitrag untersucht die häufigsten Quellen dieser versteckten Bytes und zeigt, wie man sie mit einem Textfeld und einem Hex-Viewer findet.
Das Problem ist fast nie der SHA-256-Algorithmus selbst. SHA-256 ist deterministisch: Dieselben Bytes erzeugen immer denselben Digest, und der Digest ist korrekt. Wenn sich die Ausgaben unterscheiden, unterscheiden sich auch die Bytes. Die Verwirrung entsteht, weil „derselbe Text“ mehrdeutig ist: Eine Person sieht Zeichen, aber eine Hash-Funktion sieht Bytes, und in der Übersetzung zwischen ihnen verbergen sich die verborgenen Unterschiede.
Der abschließende Zeilenumbruch – wie echo ein Byte anhängt und printf nicht, und was das mit einem Digest macht
Der echo-Befehl in einer Shell hängt ein Newline-Zeichen (U+000A, Byte 0x0A) an seine Ausgabe an. Dies ist beabsichtigt: Die Konvention in Unix, dass Textdateien mit einem Zeilenumbruch enden, gibt echo eine einfache Aufgabe. Wenn Sie echo abc in ein Terminal eingeben und es an sha256sum weiterleiten, sind die verdauten Bytes 61 62 63 0A (die ASCII-Codes für a, b, c und das Byte für Newline), nicht 61 62 63. Das Tool, das ToolAcre zum Berechnen von Hashes verwendet, hasht die Bytes 61 62 63 und erzeugt ein anderes Ergebnis.
Der Befehl printf fügt keinen Zeilenumbruch hinzu, es sei denn, Sie schreiben einen in die Formatzeichenfolge. printf abc | sha256sum berechnet allein den Digest der Bytes 61 62 63, der dem Browser-Tool entspricht. Aus diesem Grund bedeutet das Vergleichen von Hashes häufig, dass Sie printf anstelle von echo ausführen, mit dem Flag -z an sha256sum weiterleiten oder Roheingaben in der von Ihrem Tool bereitgestellten Form angeben. Der versteckte Zeilenumbruch ist der häufigste Grund dafür, dass ein Browser-Tool und ein Befehlszeilen-Tool nicht übereinstimmen.
UTF-8 im Vergleich zu UTF-16 – warum dieselben Zeichen in einigen Shells und Editoren unterschiedliche Bytes sind
UTF-8 und UTF-16 kodieren dieselben Zeichen als unterschiedliche Bytesequenzen. Das Zeichen é (U+00E9, ein e mit akutem Akzent) wird als zwei UTF-8 Bytes kodiert: 0xC3 0xA9. In UTF-16, der Art und Weise, wie JavaScript Zeichenfolgen intern darstellt, belegt dasselbe Zeichen zwei Bytes in einer anderen Reihenfolge (je nach Endianness) oder in einer völlig anderen Form, wenn es aus einem Basiszeichen und einer Kombinationsmarke besteht. Wenn Sie café aus einer Windows-Anwendung kopieren und in ein Browser-Hash-Tool einfügen, stimmen die Bytes, die das Tool hasht, möglicherweise nicht mit denen eines Mac-Terminals überein, da die Systeme standardmäßig unterschiedliche Kodierungen oder Normalisierungsformen verwendet haben.
Das ToolAcre-Hash-Tool konvertiert Text explizit in UTF-8, bevor es über TextEncoder gehasht wird. Dies ist die gleiche Codierung, die die Unix-Befehlszeile standardmäßig verwendet. Der Quellcode in apps/dev/src/lib/base64.js zeigt die Funktion textToBytes, die new TextEncoder().encode() aufruft, was UTF-8 garantiert. Wenn ein anderes System UTF-16 oder Latin-1 oder eine andere Kodierung verwendet, unterscheiden sich die erzeugten Bytes. Das Tool zeigt die Bytezahl neben dem Digest an, weshalb das Einfügen von Café und der Vergleich mit einem Befehlszeilen-Hash unterschiedliche Bytezahlen anzeigt, wenn die Codierungen voneinander abweichen.
CRLF, BOM und Normalisierung – Zeilenenden, Byte-Reihenfolgemarkierungen und zusammengesetzte versus zerlegte Akzente als unsichtbare Eingabeunterschiede
CRLF (Wagenrücklauf + Zeilenvorschub, Bytes 0x0D 0x0A) ist die Zeilenendekonvention unter Windows; LF (Line Feed Alone, Byte 0x0A) ist die Unix-Konvention. Eine Textdatei, die beim Öffnen in einem Texteditor identisch aussieht, kann unterschiedliche Zeilenenden enthalten, und diese Bytes sind Teil der Eingabe für den Hash. Eine unter Windows bearbeitete und mit einem auf einem Unix-System berechneten SHA-256 verglichene Datei stimmt nicht überein, wenn ein System die Zeilenenden konvertiert hat und das andere nicht.
Die Byte-Reihenfolge-Marke (BOM, Bytes 0xEF 0xBB 0xBF für UTF-8) ist eine optionale Sequenz am Anfang einer Datei, die die Kodierung signalisiert. Einige Redakteure fügen es hinzu; einige Werkzeuge entfernen es; manche ignorieren es. Wenn eine Datei eine Stückliste enthält und Sie sie Byte für Byte hashen, sind die Stücklistenbytes Teil des Digests. Wenn Sie dann den sichtbaren Text (vor dem ein Betrachter die Stückliste verbirgt) in ein Tool kopieren, das keine Stückliste hinzufügt, stimmen die Digests nicht überein. Textnormalisierungsformen (NFD versus NFC für zusammengesetzte und zerlegte Akzente) fügen eine weitere Ebene hinzu: Der gleiche akzentuierte Buchstabe kann als einzelnes vorkomponiertes Zeichen oder als Basiszeichen gefolgt von einem kombinierenden Akzent dargestellt werden, und die Bytesequenzen sind unterschiedlich.
Funktioniertes Beispiel – eine Zeichenfolge, gehasht mit und ohne Zeilenumbruch, dann in zwei Codierungen, wobei der Unterschied jedes Bytes angezeigt wird
Diagnosemethode eins: Verwenden Sie ein Hex-Dump-Tool oder einen Online-Konverter, um genau zu sehen, mit welchen Bytes Ihre Tools arbeiten. Fügen Sie den Text in einen Base64-Encoder ein, kodieren Sie ihn, und Sie erhalten eine Textaufzeichnung der Bytes. Dann dekodieren Sie das Base64 in der Befehlszeile mit base64 -d und leiten Sie es an od -A x -t x1z weiter, um die Hex-Byte-Sequenz zu sehen. Wenn die Bytes übereinstimmen, ist der Algorithmus korrekt; Andernfalls ist der Unterschied sichtbar.
Diagnosemethode zwei: Verwenden Sie den ToolAcre SHA-Hash-Rechner, um zunehmend längere Eingaben zu hashen, beginnend mit einem einzelnen Zeichen. Fügen Sie eine neue Zeile hinzu (was bedeutet, dass Sie die Eingabetaste in das Textfeld eingeben), fügen Sie Leerzeichen hinzu und fügen Sie denselben Text mit UTF-16-Escape-Sequenzen hinzu, wenn die Eingabe von einer Nicht-ASCII-Quelle stammt. Beobachten Sie, wie sich die Zusammenfassung mit jeder Zugabe ändert. Die neben dem Digest angezeigte Byte-Anzahl gibt Aufschluss darüber, wie viele Bytes das Tool hasht, was die Suche erheblich einschränkt.
Hex-Schreibweise und Leerzeichen in der Ausgabe – die Unterschiede sind rein kosmetischer Natur
Bei der hexadezimalen Darstellung eines Digests wird die Groß-/Kleinschreibung nicht beachtet. Groß- und Kleinbuchstaben stellen beide die gleichen Bytes dar: A = 10, a = 10. Einige Tools geben Großbuchstaben aus, andere Kleinbuchstaben, andere erlauben beides. Wenn ein Digest in Kleinbuchstaben und ein anderer in Großbuchstaben geschrieben ist, handelt es sich um denselben Digest. Leerzeichen in der Digest-Anzeige sind rein kosmetischer Natur. Ein als ba78 16bf und ba7816bf angezeigter Digest ist derselbe; Das Leerzeichen ist nur eine Formatierungsauswahl. Durch Groß- und Kleinschreibung oder Leerzeichen verursachte Abweichungen sind keine echten Abweichungen.
Formatierungsunterschiede mit fester Breite sind auch auf Byte-Ebene unsichtbar. Ein mit Bindestrichen, Leerzeichen oder Doppelpunkten angezeigter Digest (wie ba-78-16-bf) ist eine Formatierungskonvention, die das Lesen für Menschen erleichtert, und keine Änderung der tatsächlichen Bytes. Das ToolAcre-Tool gibt immer Kleinbuchstaben ohne Trennzeichen aus. Dies ist das Format, das die meisten Befehlszeilentools ausgeben. Wenn Sie mit einem Werkzeug vergleichen, das anders emittiert, konvertieren Sie zuerst in die gleiche Darstellung.
Was dies nicht abdeckt – Hashing-Dateien, bei denen dieselben Prinzipien gelten, die Bytes jedoch von der Festplatte und nicht von einem Textfeld stammen
Der ToolAcre SHA-Hash-Rechner führt vor dem Hashing eine UTF-8-Konvertierung durch, zeigt die Anzahl der Eingabebytes an und bietet Base64- und Hexadezimal-Ausgabeformen. Die Quelldatei apps/dev/src/lib/hash.js zeigt die hashText-Funktion, die „digestBytes“ aufruft und bytes.slice().buffer an crypto.subtle.digest übergibt. Die Kommentare in dieser Datei dokumentieren ausdrücklich, dass der Schritt UTF-8 beabsichtigt ist und weisen auf den Unterschied zwischen verschiedenen Codierungen hin. Durch das Testen Ihrer Eingabe anhand des bekannten Vektors (abc-Hashes zu ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad in Hex) wird festgestellt, dass das Browser-Tool ordnungsgemäß funktioniert. Jede Abweichung deutet auf einen Byteunterschied in der Eingabe hin.
Datei-Hashing folgt dem gleichen Prinzip. Entscheidend sind die Bytes in der Datei: Ein Unterschied am Zeilenende beim Exportieren von einem System und beim Importieren in ein anderes kann jeden Digest verändern. Einige Tools bieten Optionen zum Umgang mit Zeilenenden beim Vergleich; andere hashen die Datei so wie sie ist. Für die Reproduzierbarkeit ist es wichtig zu wissen, ob Ihr Tool die Datei als Binärdatei hasht oder zuerst eine Textnormalisierung durchführt.
Fazit: Hash-Bytes, kein Text – der ToolAcre SHA-Hash-Rechner hasht die von Ihnen eingefügten Bytes. Überprüfen Sie also zuerst, was Sie eingefügt haben
Vergleich und Überprüfung funktionieren nur, wenn Sie dieselben Bytes hashen. Stellen Sie zunächst sicher, dass Sie genau dieselbe Eingabe hashen: Führen Sie echo -n (oder printf) anstelle von echo aus, um den Zeilenumbruch zu vermeiden. Geben Sie die Codierung UTF-8 explizit an, wenn Ihr Tool dies zulässt. Überprüfen Sie, ob CRLF nicht von einem Editor oder Systemdienstprogramm eingefügt wurde. Dann hashen Sie mit dem ToolAcre-Rechner und dem Befehlszeilentool nebeneinander. Wenn die Digests übereinstimmen, waren die Bytes identisch. Ist dies nicht der Fall, verwenden Sie die Byte-Count-Anzeige und die Hex-Dump-Methode, um den versteckten Unterschied zu finden.
Sobald Sie wissen, wo die Bytes voneinander abweichen, können Sie entscheiden, ob Sie sie zum Vergleich normalisieren möchten. Einige Prüfsummen sollen die Dateiintegrität genau so überprüfen, wie sie auf der Festplatte vorhanden ist. In diesem Fall ist Byte-für-Byte-Hashing das Ziel. Andere sollen überprüfen, ob der sichtbare Inhalt derselbe ist. In diesem Fall ist die Normalisierung von Zeilenenden und Codierung korrekt. Beides ist nicht falsch; Sie beantworten verschiedene Fragen. Der SHA-256-Algorithmus ist immer richtig; Die Frage ist nur, ob Sie in beiden Fällen verlangen, dass dieselbe Eingabe gehasht wird.