CRC 校驗和是一個固定大小的檢查值,由位元組區塊在伽羅瓦域 GF(2) 中透過多項式除法衍生而來,而 gzip、ZIP、PNG 以及許多其他格式所使用的精確變體為 CRC-32/ISO-HDLC:寬度 32,反射多項式 0xEDB88320,初始暫存器 0xFFFFFFFF,反射位元組處理,以及最終 XOR 0xFFFFFFFF。當您將字串 123456789 的九個 ASCII 位元組代入該公式時,結果為八位數十六進位值 cbf43926,而該常數是用來確認工具所產生的是 ISO-HDLC 變體而非其他 32 位元 CRC 的標準交叉檢查值。輸出結果一律顯示為八個小寫十六進位數字,包括前置零,因為暫存器被視為無符號 32 位元值,且計算機絕不會截斷結果。
本指南將逐步說明如何在瀏覽器中計算 CRC 校驗和、如何選擇輸入模式、如何驗證八位數結果是否符合預期值,以及 CRC-32 在哪些情況下不再適用,因為它並非加密原語。

CRC-32/ISO-HDLC 實際上做了什麼
CRC-32 是一種循環冗餘校驗,而非雜湊。它將輸入位元組視為多項式的係數,將該多項式除以由 0xEDB88320 表示的生成多項式,並將餘數回報為 32 位元值。由於 GF(2) 中的除法是逐位元 XOR 而不進位,計算速度很快,且僅能透過對真實資料進行窮舉才能反推,但這離安全性保證還很遠。「ISO-HDLC」後綴指定了具體的參數集:32 位元寬度、標準多項式的反射(最低有效位元優先)版本、初始全為 1 的暫存器、反射輸入處理,以及最終全為 1 的 XOR。請使用 CRC32 計算機 來確認酬載是否符合該精確參數集所定義的檢查值,包括針對 123456789 的 ASCII 位元組的著名常數 cbf43926。
實際的結果是,如果您將位元組序列更改了僅僅一個位元,所產生的 CRC 將以統計上極不可能與原始值碰撞的方式改變。這足以捕捉來自雜訊儲存、不穩定的序列鏈結或截斷下載所造成的意外損毀,這也正是 gzip、ZIP、PNG、乙太網、SATA 以及許多嵌入式開機載入器在其資料旁附帶 CRC-32 欄位的原因。但它不足以捕捉蓄意的編輯,因為該函式是線性的,很容易在不更改選定偏移處值的情況下進行操控。
如何逐步計算 CRC 校驗和
CRC32 計算機遵循與大多數通訊協定規範中的 CRC 檢查相同的三步驟模式:識別變體與涵蓋的位元組範圍、輸入精確的酬載、以及逐一比對八個輸出數字與預期值。以下是具體的程序。
- 識別所需的 CRC 變體與精確的位元組範圍。 本頁僅實作 CRC-32/ISO-HDLC。針對 123456789 的 ASCII 位元組,標準檢查值為 cbf43926;如果您的規範對該輸入預期不同的常數,則另一端使用的是不同的變體或不同的涵蓋範圍,結果將無法相符。
- 選擇 UTF-8 文字或十六進位位元組並輸入精確的酬載。 僅在 UTF-8 明確無誤時才使用文字模式,因為每個重音字母、CJK 字元或表情符號會展開為多個位元組,任何重新編碼都會改變結果。當規範給您精確的位元組時(例如標頭內儲存的 CRC 欄位),請改用十六進位模式,而非重新輸入可見字元。
- 計算並讀取八位數結果。 輸出恰好為八個小寫十六進位數字,不會截斷。請將該值視為無符號 32 位元,因此前置零很重要:00a1b2c3 與 a1b2c3 是不同的結果。
- 逐一比對每個數字與預期值。 位元組逐位元組相符表示該酬載與目標變體及涵蓋範圍一致。該計算機亦提供針對空輸入、標準數字檢查以及 quick-brown-fox 句子的外部檢查字串,您可以用來在依賴它處理真實通訊協定酬載之前確認實作品。
- 當需要對抗性抵抗時,請使用加密摘要加上受信任的管道。 CRC-32 是設計用來偵測意外變更的循環冗餘校驗;它既非加密雜湊,也非訊息鑑別碼或數位簽章,您不應將其用於驗證未受信任的軟體、授權命令或驗證發布者。
文字模式與十六進位模式的比較
CRC 不相符的最常見原因是寄送者雜湊的位元組與您雜湊的位元組之間存在隱性差異。該計算機提供兩種輸入模式,讓您可以直接控制這點。在文字模式下,字串會在計算前編碼為 UTF-8;ASCII 字元各佔一個位元組,而重音拉丁字母通常佔兩個,CJK 表意文字佔三個,許多表情符號佔四個。即使可見文字看起來相同,以 UTF-16 程式碼單位、舊式字碼頁(例如 Windows-1252)、正規化 Unicode(NFC 或 NFD)或不同的換行慣例計算出來的結果都不會相符。若要更深入瞭解計算機如何針對相同任務進行結構設計,CRC-32 校驗和的資料完整性指南 詳細涵蓋了位元組範圍的決策。
只要格式指定的是精確位元組而非可讀文字,十六進位模式就是正確的選擇。該計算機會去除位元組對之間的空白字元,但除此之外要求偶數個十六進位數字;每對構成一個位元組。前綴如 0x、空白字元以外的分隔符、註解以及多出來的奇數 nibble 都會被拒絕,而非靜默忽略。前導的 00 位元組會予以保留,因為它們是酬載的一部分,因此若空酬載的第一個位元組恰好為零,仍會影響結果。如果您的目標規格包含標頭、長度欄位、分隔符或儲存的校驗和欄位,請確認這些位元組中哪些位於涵蓋範圍內,因為包含或排除即使一個位元組也會改變八位數的輸出。
讀取八位數輸出並進行比對
輸出是一個單一的無符號 32 位元值,以八個小寫十六進位數字呈現,永遠顯示前置零。該格式很重要:空酬載的 CRC 為 00000000 是有效且有意義的驗證結果,而要求先輸入資料再顯示結果的介面可以避免空點擊看起來像是有效的檢查。顯示絕不會靜默截斷,該值被視為無符號,且複製動作僅複製精確的 32 位元值,不含任何周圍文字。
若要驗證酬載,請使用相同的變體與涵蓋位元組在本機計算 CRC,然後逐位比對八個數字與公開的預期值。完全相符是位元組在儲存或傳輸過程中未發生意外損毀的證據。它並非證明檔案來自受信任的發布者、命令來自經授權的寄送者,或酬載未被蓄意修改的證據。針對那些保證,您需要透過已驗證管道發佈的加密摘要,並且針對訊息本身的竄改偵測,則需要諸如 HMAC 或已簽署封包之類的已驗證原語,因為 zlib 的校驗和手冊 在描述 adler32 與 crc32 在 gzip 容器中的角色時也做出了相同的區分。
CRC32 變體及如何區分
並非每個 CRC32 都是相同的函式。不同系統共用「CRC32」這個名稱,但使用不同的多項式、不同的初始與最終轉換,以及不同的位元組順序。如果您的工具所回報的值對 123456789 的 ASCII 位元組而言不等於 cbf43926,則另一個系統幾乎可以確定是執行下列其中一個變體,或是雜湊了不同的位元組範圍。
| 變體 | 多項式 | 「123456789」的檢查值 | 典型用途 |
|---|---|---|---|
| CRC-32/ISO-HDLC(本頁) | 0xEDB88320(反射) | cbf43926 | gzip、ZIP、PNG、乙太網、SATA |
| CRC-32C(Castagnoli) | 0x82F63B78(反射) | e3069283 | iSCSI、SCTP、ext4、BTRFS |
| CRC-32/MPEG-2 | 0x04C11DB7(非反射) | 0376e6e7 | MPEG-2 傳輸串流 |
| CRC-32/BZIP2 | 0x04C11DB7(非反射,無最終 XOR) | fc891918 | bzip2 檔案格式 |
| CRC-32/JAMCRC | 0xEDB88320(反射,無最終 XOR) | 340bc6d9 | JAM、demoscene、部分遊戲 |
在信任一個不符結果之前,請將本表作為快速健全性檢查。如果您的參考值對 123456789 預期為 e3069283,則另一端執行的是 CRC-32C,本頁的計算機依設計會產生不同的值,因此請更換工具,而非開始調整輸入。
計算 CRC 校驗和時的常見陷阱
大多數比對失敗源自少數幾種位元組範圍的錯誤。使用不同的字元集重新編碼酬載、在 CRLF 與 LF 換行之間切換、從會去除尾端空白的檢視器複製,或在涵蓋範圍內包含或排除儲存的校驗和欄位,都會改變八位數結果。十六進位模式會去除位元組間的空白,但會保留解析器用於維持準確位元組數的前置零,因此多出來的奇數 nibble 會被拒絕,而非靜默捨入。共有八個外部檢查字串,涵蓋空輸入、短訊息、常見訊息摘要與字母測試套件、標準數字檢查以及 quick-brown-fox 句子,可用於在信任計算機處理真實酬載之前確認所宣告的變體。
Python zlib 交叉檢查會在內部用於驗證多位元組 UTF-8 邊界,因此表情符號或 CJK 表意文字所產生的八位數值與參考 zlib 在等效位元組序列上執行的結果相同。該計算機使用 RFC 1952 中的查表法在瀏覽器中處理最多 5,000,000 位元組:由反射多項式產生 256 項的表格,將每個輸入位元組與低位元暫存器的低八位元進行 XOR,查表取得餘數,然後將暫存器向右位移八位元,最後對暫存器取補數並格式化為八個十六進位數字。這使得大型輸入保持回應迅速,並確保不會上傳任何酬載。如果您的輸入超過限制,請在實際擁有該位元組的裝置上切換至串流實作。
最後,請記住 CRC-32 是用於捕捉意外錯誤的工具,而非對抗惡意行為的工具。若未偵測到的修改所帶來的成本超過損毀的下載,請將 CRC 替換為透過已驗證管道發佈的加密摘要,並在酬載本身周圍加入訊息鑑別碼或已簽署的封包。
相關閱讀:如何從原始位元組計算二進位校驗和。