為什麼拿這一頁對賬
手上兩份站內資源頁下載的 TXT,一份 2840 字節、一份 4995 字節。打開雜湊工具頁才注意到,它自己的腳本裡就寫了三套雜湊實現,瀏覽器原生介面不可用時才回落。
這一頁自己寫了三套實現
被測頁是文件MD5計算,模板 456 行、18467 字節,頁內自寫 md5Bytes、sha1Hex、sha256Hex 三支。把三支逐字摘進純 Node,與 node:crypto 的 md5、sha1、sha256 在 18 個輸入上交叉核對,54 條比對全部相等、0 條不符。輸入含兩份 TXT 全文、各自首 64 與末 64 字節、中間 1000 字節切片、0 字節、1 字節與 8 條 RFC 向量。
- 輸出碼位長恆為 32 / 40 / 64 字元,即 128 / 160 / 256 位。
- 兩素材 MD5 前 8 位 ee965b6b 與 cd254166;SHA-1 前 8 位 f544f5af 與 a7b9c271;SHA-256 前 8 位 9d6a51bc 與 3c2f351d。
- 把 hasSubtleCrypto() 打樁成假,頁內 SHA 支與 crypto.subtle 支在同一 buffer 上逐字元相同;MD5 從不進 calcSHA。
- DOM 層另一口徑:headless Chrome 154 實測 hasSubtleCrypto() 為真。
頁內 MD5 的分塊賬
2840 字節按頁內補位口徑量出 44 個完整塊加 24 字節尾塊,含填充共 45 塊、2880 字節;4995 字節那份是 78 個完整塊加 3 字節尾塊,含填充 79 塊、5056 字節。0x80 分別寫下下標 2840 與 4995,長度域按小端寫兩個 32 位元字,低字是 22720 與 39960,高字都是 0。頁內 padLen 寫成 ((len+8)>>6)+1,標準寫法是 ceil((len+9)/64),在長度 0..2000 上逐個比對,分歧 0 處;觸發額外塊要 len%64 達到 56,兩份素材的尾塊 24 與 3 都不觸發。
圖 1:一部 TXT 被切成 64 字節一塊的賬。
改一個字節會怎樣
- 翻下標 0、下標 1000、末字節各 1 位:字節數不變,MD5 的 32 個十六進位字元有 28 到 32 個改變;SHA-1 最多 40 個;SHA-256 改變 57 到 62 個。
- 刪首字節 2840 變 2839;末尾加一個換行變 2841;加 BOM 變 2843,三個摘要都換。
- LF 轉 CRLF 把兩檔案拉到 2926 與 5127 字節,增量 86 與 132 恰等於兩檔案的 LF 個數;反向轉回得到原摘要。
- GBK 或 GB18030 重編碼未實測——Node 內建 TextEncoder 只會 UTF-8,沒有 GBK 編碼器。只實測了把 UTF-8 字節按 GBK 誤讀:一份得 1618 碼元含 18 個替換字元、編回 4375 字節;另一份 2693 碼元含 20 個替換字元、編回 7715 字節。
塊級中間態給出機理:複製一份同構實現、每塊末印出鏈接變數,2840 素材共 45 塊、46 個態——只改末塊內 1 字節,前面 45 個態逐字節相同;改首字節,只有初向量相同;改下標 1420 那個字節,前 23 個態相同。4995 素材是 79 塊、80 個態,對應三檔 79、1、40。
大小那一列的數怎麼捨入
formatSize 三檔閾值 1024、1048576、1073741824,前一檔直接帶 B,後兩檔分別用 toFixed(1) 與 toFixed(2):
| 輸入字節 | 列印 |
|---|---|
| 1023 | 1023 B |
| 1024 | 1.0 KB |
| 1048575 | 1024.0 KB |
| 1048576 | 1.00 MB |
| 1073741823 | 1024.00 MB |
| 1073741824 | 1.00 GB |
KB 檔內部,4095 印出 4.0 KB、5119 印出 5.0 KB;3583 與 3584 都印出 3.5 KB。表格每行大小列與統計區總大小調的是同一個函數,差在輸入是逐檔案還是求和:6 個 1075 字節的檔案逐行 1.0 KB、合計 6450 字節印出 6.3 KB;2 個 1126 字節逐行 1.1 KB、合計 2252 印出 2.2 KB。兩部素材同時在表內,列顯示 2.8 KB 與 4.9 KB,總大小 7835 字節顯示 7.7 KB。
一行一個檔案,重複的兩個都算
行標識由 Date.now() 加底線再加隨機段拼成,實測完整 id 長 20。把 Date.now 打樁成同一毫秒、隨機段用真值,同毫秒連加 10、100、1000 個,重複條數都是 0,隨機段長度分佈全是 6 位;隨機段也打樁成同一個值時,5 次入隊只得 1 個 id。真實時鐘代入 2000 次,隨機段全是 6 位;短尾只能用樁值代入:0.5 得 1 位、0 得空字串使整個 id 只剩 14 字元、極小值得 000000。
DOM 層實測:同一檔案添加兩次得到兩行同摘要;3 個檔案進表,ids distinct 為 3、重複標紅行 2,統計區四行是「檔案總數:3、總大小:9 B、重複檔案:2、重複群組:1」。頁面只標紅計數,不刪行也不匯出。
進度條那 50% 是哪裡來的
computing 幀的 MD5 格被換成 width:50% 的進度條,另兩格顯示「計算中...」。50% 與實際計算量無關,代碼裡這一幀就是這樣。整場探針 57 幀,done 行與 pending 行同幀並存。這組來自 headless Chrome 154 探針頁,餵的是合成字節,與上面純 Node 層兩套口徑不混。
兩份 TXT 的字節賬
語料都是從資源頁下載來的:百家姓那份 2840 字節、UTF-16 碼元 1104、碼點 1104,按 LF 切段 87,非空 84、空 3,無 CRLF、無 BOM,末字節是換行,非 ASCII 字節 2604;弟子規那份 4995 字節、碼元與碼點都是 1783,切段 133、非空 109、空 24,同樣無 CRLF 無 BOM,非 ASCII 字節 4818。兩份碼元數與碼點數相等,非 ASCII 字節都是 3 的整數倍:三位元組字元 868 與 1606 個,U+4E00 到 U+9FFF 區間的漢字 716 與 1240 個,其餘 152 與 366 個。摘要只認這條字節流,不認行——87 段還是 133 段,落到分塊賬上只是 2840 與 4995 這兩個分母。
常見問題
Q:只是換了編碼形式,為什麼摘要整個變了?
摘要函數讀的是字節序列:加 BOM 讓字節數從 2840 到 2843、LF 轉 CRLF 到 2926,輸入已不是同一串,三個摘要跟著全換。
Q:同一檔案的兩行,摘要為什麼一樣?
頁面不按內容去重:每次入隊各佔一行、各算各的摘要,兩行自然相同;統計只把它記成重複檔案 2、重複群組 1,標紅按 MD5 歸組。
Q:這麼小的檔案,怎麼也有一格 50%?
50% 是 computing 幀的佔位寫法,與檔案大小無關;探針裡每個檔案都走三幀,那一幀的 MD5 格在 DOM 裡就是這樣。