開發者工具 · SHA 雜湊計算器
相同的文字,不同的 SHA-256:換行符、編碼和隱藏位元組
· 工作原理
sha-256 編碼 文字處理 偵錯
對於看起來相同的文字,命令列說的是一件事,而瀏覽器說的是另一件事。尾隨換行符、UTF-16 和 CRLF 解釋了幾乎所有情況;這篇文章展示瞭如何找到隱藏的位元組。
echo 說一個哈希值,該工具說另一個哈希值 - 日常的不匹配以及為什麼兩者都沒有錯
終端報告一個 SHA-256 摘要,瀏覽器報告另一個看似相同的文字。命令列工具沒有損壞,瀏覽器也沒有。儘管可見字元看起來相同,但被散列的位元組並不相同。這篇文章追蹤了這些隱藏位元組的最常見來源,並展示瞭如何使用文字欄位和十六進位檢視器來找到它們。
問題幾乎從來都不是 SHA-256 演演算法本身。 SHA-256 是確定性的:相同的位元組總是產生相同的摘要,並摘要是正確的。當輸出不同時,位元組也不同。之所以會出現這種混亂,是因為「相同的文字」是不明確的:一個人看到的是字符,但雜湊函數看到的是字節,而它們之間的翻譯就是隱藏差異的地方。
尾隨換行符 — echo 如何附加字節而 printf 不附加字節,以及這對摘要有何作用
shell 中的 echo 指令在其輸出中附加一個換行符號(U+000A,位元組 0x0A)。這是設計使然:Unix 中文字檔案以換行符結尾的慣例使 echo 成為一項簡單的工作。當您在終端機中輸入 echo abc 並將其透過管道傳輸到 sha256sum 時,摘要的位元組為 61 62 63 0A(a、b、c 的 ASCII 代碼和換行符的位元組),而不是 61 62 63。 ToolAcre 用於計算雜湊值的工具對位元組 61 62 63 進行雜湊運算並產生不同的結果。
printf 指令不會新增換行符,除非您將換行符寫入格式字串。列印 abc | sha256sum 單獨計算位元組 61 62 63 的摘要,與瀏覽器工具相符。這就是為什麼比較雜湊值通常意味著執行 printf 而不是 echo,或者使用 -z 標誌透過管道傳輸到 sha256sum,或以工具提供的任何形式指定原始輸入。隱藏的換行符號是瀏覽器工具和命令列工具不一致的最常見原因。
UTF-8 與 UTF-16 — 為什麼相同的字元在某些 shell 和編輯器中是不同的位元組
UTF-8 和 UTF-16 將相同的字元編碼為不同的位元組序列。字元 é(U+00E9,帶有銳音符的 e)編碼為兩個 UTF-8 位元組:0xC3 0xA9。在 UTF-16(JavaScript 內部表示字串的方式)中,相同的字元以不同的順序(取決於位元組順序)佔據兩個位元組,或者如果由基本字元和組合標記組成,則完全不同的形式。當您從 Windows 應用程式複製咖啡館並將其貼上到瀏覽器雜湊工具中時,該工具雜湊的位元組可能與 Mac 終端雜湊的位元組不匹配,因為系統預設採用不同的編碼或規範化形式。
ToolAcre 雜湊工具在透過 TextEncoder 進行雜湊處理之前將文字明確轉換為 UTF-8。這與 Unix 命令列預設使用的編碼相同。 apps/dev/src/lib/base64.js 中的原始碼顯示函數 textToBytes 呼叫 new TextEncoder().encode(),這保證了 UTF-8。如果另一個系統使用 UTF-16 或 Latin-1 或任何其他編碼,則產生的位元組將有所不同。該工具在摘要旁邊顯示位元組計數,這就是為什麼如果編碼不同,請貼上咖啡館並與命令列雜湊進行比較將顯示不同的位元組計數。
CRLF、BOM 與標準化 — 行結尾、位元組順序標記以及組合重音與分解重音作為不可見的輸入差異
CRLF(回車+換行,位元組0x0D 0x0A)是Windows上的行結束約定; LF(單獨換行,位元組 0x0A)是 Unix 約定。在文字編輯器中開啟時看起來相同的文字檔案可以帶有不同的行結尾,並這些位元組是雜湊輸入的一部分。如果一個系統已轉換行結尾而另一個系統未轉換,則在 Windows 上編輯並對照在 Unix 系統上計算的 SHA-256 檢查的檔案將不符。
位元組順序標記(BOM,UTF-8 的位元組 0xEF 0xBB 0xBF)是位於檔案開頭的可選序列,用於表示編碼。一些編輯添加了它;有些工具會剝離它;有些人忽略它。如果檔案帶有 BOM,並您逐位元組對其進行雜湊處理,則 BOM 位元組就是摘要的一部分。如果您隨後將可見文字(檢視者隱藏了 BOM)複製到不新增 BOM 的工具中,則摘要將不符。文字規範化形式(用於組合和分解重音的 NFD 與 NFC)添加了另一層:相同的重音字母可以表示為單個預組合字符或表示為後跟組合重音的基本字符,並字節序列不同。
工作範例 - 一個字串使用或不使用換行符進行雜湊處理,然後採用兩種編碼,顯示每個位元組的差異
診斷方法一:使用十六進位轉儲工具或線上轉換器來準確查看工具正在操作的位元組。將文字貼到 Base64 編碼器中,對其進行編碼,然後您就擁有了位元組的文字記錄。然後在命令列上使用 base64 -d 解碼 Base64 並將其透過管道傳輸到 od -A x -t x1z 以查看十六進位位元組序列。如果位元組匹配,則演演算法正確;如果不這樣做,差異就會顯而易見。
診斷方法二:使用 ToolAcre SHA 雜湊計算器對逐漸變長的輸入進行雜湊處理,從單一字元開始。新增換行符(這表示在文字方塊中鍵入 Enter),新增空格,如果輸入來自非 ASCII 來源,則新增帶有 UTF-16 轉義序列的相同文字。觀察每次新增後摘要的變化。摘要旁邊顯示的位元組計數告訴您該工具正在散列多少字節,這大大縮小了搜尋範圍。
輸出中的十六進位大小寫和空格 - 純粹是裝飾性的差異
摘要的十六進位表示形式不區分大小寫。大寫和小寫字母都代表相同的位元組:A = 10,a = 10。有些工具發出大寫字母,有些工具發出小寫字母,有些則允許兩者。如果一個摘要是小寫,另一個摘要是大寫,則它們是相同的摘要。摘要顯示中的空白純粹是裝飾性的。顯示為 ba78 16bf 與 ba7816bf 的摘要是相同的;空格只是一種格式選擇。由大小寫或空格引起的不匹配並不是真正的不匹配。
固定寬度格式差異在位元組層級也是不可見的。以連字號、空格或冒號顯示的摘要(如 ba-78-16-bf)是一種格式約定,使人們更容易閱讀,而不是更改實際位元組。 ToolAcre 工具總是發出不含分隔符號的小寫字母,這是大多數命令列工具列印的格式。如果您要與發出不同訊號的工具進行比較,請先轉換為相同的表示形式。
這不包括什麼 - 散列檔案,應用相同的原理,但位元組來自磁碟而不是文字欄位
ToolAcre SHA 雜湊計算器在雜湊之前執行 UTF-8 轉換,顯示輸入位元組計數,並提供 base64 和十六進位輸出形式。原始檔apps/dev/src/lib/hash.js顯示了呼叫digestBytes的hashText函數,該函數將bytes.slice().buffer傳遞給crypto.subtle.digest。該檔案中的註釋明確記錄了 UTF-8 步驟是有意為之,並注意不同編碼之間的差異。根據已知向量(十六進位的 ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad)測試您的輸入,確定瀏覽器工具正常運作;任何偏差都表示輸入中存在位元組差異。
檔案雜湊遵循相同的原則。檔案中的位元組至關重要:從一個系統匯出並匯入到另一個系統時的行結束差異可能會更改每個摘要。有些工具提供了在比較期間處理行結尾的選項;其他人按原樣散列檔案。了解您的工具是將檔案散列為二進制還是首先執行文字規範化對於再現性至關重要。
重點:雜湊字節,而不是文字 — ToolAcre SHA 雜湊計算器會對您貼上的位元組進行雜湊處理,因此請先檢查您貼上的內容
僅當雜湊相同位元組時比較和驗證才有效。首先確認您正在散列完全相同的輸入:執行 echo -n (或 printf)而不是 echo 以避免換行符,如果您的工具允許,則明確指定 UTF-8 編碼,檢查 CRLF 是否未被編輯器或系統實用程式插入。然後並排使用 ToolAcre 計算器和命令列工具進行雜湊處理。如果摘要匹配,則位元組相同。如果不存在,請使用位元組計數顯示和十六進位轉儲方法來尋找隱藏的差異。
一旦了解了位元組分歧的位置,您就可以選擇是否對它們進行標準化以進行比較。某些校驗和旨在驗證檔案的完整性是否與磁碟上存在的檔案完全一致,在這種情況下,目標是逐字節散列。其他的目的是驗證可見內容是否相同,在這種情況下規範化行結尾和編碼是正確的。兩者都沒有錯;他們回答不同的問題。 SHA-256 演演算法總是正確的;問題只是你是否要求它在兩種情況下對相同的輸入進行雜湊處理。