了解長度擴展攻擊
我一直試圖準確了解長度擴展攻擊如何在 SHA-1 上起作用。我將在下面詳細說明我到目前為止所理解的內容,以便我可以傳達我對相同的理解,並希望得到關於我哪裡出錯的建議。
假設對於一條消息 $ m $ , 一個秘密 $ s $ 附加在它前面併計算 SHA-1 雜湊。如果 $ \textrm{len}(m) + \textrm{len}(s) $ 不是塊大小的倍數,添加一定量的填充使其成為倍數,並使用本質上的內容生成雜湊 $ \textrm{H}(s \mathbin| m \mathbin| \textrm{padding}) $ .
現在 SHA-1 在內部使用 5 個寄存器——它接收一個塊,生成新的寄存器值,轉動曲柄,接收另一個塊,生成新的寄存器值,轉動曲柄……等等直到最後。當所有塊都用完時,寄存器值被連接並吐出。
假設攻擊者知道某個值 $ m $ ,他也知道散列鍵。在這種情況下,他知道 5 個寄存器的狀態 $ (s \mathbin\ m \mathbin\ \textrm{padding}) $ 被處理。我們還假設攻擊者知道 $ \textrm{len}(s) $ 這樣他就可以預測添加了多少填充。
這是我感到困惑的地方。從我目前所讀到的內容來看,攻擊涉及獲取已知的雜湊,添加一定數量的填充,然後是我們想要的值。但是,在創建雜湊時填充不是已經用完了嗎?為什麼我們在攻擊中使用填充?
SHA-1 按 512 位塊(64 字節)處理數據。對於給定的輸入消息m,它首先附加一些位(至少 65,最多 576),以便總長度是 512 的倍數。讓我們稱p添加的位(即填充)。填充位僅取決於m的**長度(這些位包括該長度的編碼,但它們不取決於實際位的值)。
然後將填充的消息m||p拆分為連續的 512 位塊,這些塊一個接一個地進行處理。SHA-1 使用內部壓縮函式(這是傳統術語);它還有一個由五個 32 位字組成的**執行狀態。**壓縮函式分別將 160 位和 512 位的兩個值作為輸入,並輸出 160 位。處理是這樣的:
- 執行狀態被初始化為一個固定的正常值(在SHA-1 規範中給出)。
- 對於每個輸入塊,評估壓縮函式,輸入目前執行狀態和輸入塊;函式的輸出是新的執行狀態。
- 處理完最後一個塊後的執行狀態就是雜湊輸出。
所以現在,長度擴展攻擊。假設您給我一個雜湊值h ,它是根據我不知道的消息m計算得出的。我知道m的長度,但不知道它的內容。因為我知道m的長度,所以我可以輕鬆計算您使用的填充p。然後我想像一條消息m’,它以m||p**開頭;也就是說,m’ = m||p||z其中z是我可以任意選擇的位序列。我現在將繼續計算m’的 SHA-1 雜湊,即使我不知道其中的一部分(它以m開頭,我不知道)。
當在m’上計算 SHA-1 時,後者首先用p’填充,這取決於m’的長度(我知道)。結果流是m||p||z||p’。然後,將 512 位塊一一處理。因為我不知道m ,所以我不能在第一個街區做這件事。但是,我可以想像自己這樣做。在某些時候,我會準確地到達p字元串的末尾(因為m||p的長度是 512 的倍數)。那時執行狀態的價值是多少?嗯,這正是雜湊值h那是你給我的!因此,我可以停止想像;我可以在z的開始處開始我的 SHA-1( m’ ) 的 SHA-1 計算,使用您的雜湊值h作為執行狀態的值。
這就是它的核心。我可以使用 SHA-1( m ) 來計算 SHA-1( m’ ),這是一條以**m的內容開頭的消息,我可以在不知道m的情況下做到這一點。SHA-1 的這一特性(適用於其他Merkle-Damgård散列函式,例如 MD5 或 SHA-256)與通常的散列函式安全特性(抗碰撞、原像和第二原像)並不矛盾,但它表明SHA-1 不是隨機預言機。
它對攻擊者有什麼好處?好吧,考慮一下消息驗證碼的以下(有缺陷的)構造:對於給定的密鑰k和要保護的數據d,計算 SHA-1( k||d ) 作為 MAC 值。該方案在存在長度擴展攻擊的情況下會中斷:如果我作為攻擊者看到消息d的 MAC ,那麼我可以計算擴展d的消息**d’ 的MAC——我可以在沒有知道k||d(特別是在不知道密鑰的情況下)。這使我可以使用有效的 MAC偽造消息。
長度擴展攻擊是為什麼在從散列函式建構 MAC 時,我們需要一些更複雜的東西,即HMAC(它是安全的)。