加密能防止攻擊者檢視網路上傳送的資訊,卻無法辨識「是誰送的」。持有加密金鑰不代表對方就是他所宣稱的身分;在非對稱加密下,任何人都能用你的公鑰加密資料寄給你。

簽章演算法(signature algorithm)為訊息產生一個獨特的簽章來解決這個問題。接收方能用同一套演算法證明訊息確實來自簽署者。附加簽章還有一個好處:

所有簽章演算法都建立在密碼雜湊演算法(cryptographic hashing algorithm)之上。

密碼雜湊演算法(Cryptographic Hashing Algorithms)#

密碼雜湊演算法對訊息套用後,產生一段固定長度的摘要,通常遠短於原始訊息,因此也稱為訊息摘要演算法(message digest algorithm)。在簽章中,雜湊的目的是產生一個相對獨特的值以驗證訊息完整性,並減少需要簽署與驗證的資料量。

適合密碼用途的雜湊演算法必須滿足三項要求:

要求說明
原像抵抗性(pre-image resistance)給定一個雜湊值,應難以還原出原訊息(例如需要海量運算力)。
碰撞抵抗性(collision resistance)應難以找到兩個不同訊息雜湊出相同的值。
非線性(nonlinearity)應難以刻意造出一個雜湊為任意指定值的訊息。

最常見的雜湊演算法屬於兩大家族:訊息摘要(MD)家族(含 Ron Rivest 開發的 MD4、MD5)與安全雜湊演算法(SHA)家族(含 NIST 發布的 SHA-1、SHA-2 等)。

校驗和(checksum)與循環冗餘檢查(CRC)等簡單演算法可偵測資料變動,但不適用於安全協定。它們的線性行為讓攻擊者能輕易推算校驗和如何隨資料改變,於是可同時竄改資料與校驗和而不被察覺。

非對稱簽章演算法(Asymmetric Signature Algorithms)#

非對稱簽章演算法利用非對稱密碼學的性質產生簽章。有些演算法(如 RSA)既能簽章也能加密;有些(如數位簽章演算法 DSA)則專為簽章設計。兩者都是先對訊息雜湊,再從雜湊產生簽章。

RSA 如何用來簽章?關鍵在於:可以用私鑰「加密」訊息、用公鑰「解密」。這種加密已不再保密(解密金鑰是公開的),卻能用來簽章:

  • 簽署者對訊息雜湊,並用私鑰對雜湊套用 RSA 解密流程,這個加密後的雜湊就是簽章。
  • 接收方用簽署者的公鑰還原出原始雜湊值,並與自己對訊息計算的雜湊比對。
  • 若兩者相符,代表發送方確實用了正確的私鑰;若接收方信任「只有簽署者持有該私鑰」,簽章便得到驗證。

圖表 7-13:RSA 的簽章處理流程

訊息鑑別碼(Message Authentication Codes)#

不同於非對稱的 RSA,訊息鑑別碼(message authentication code, MAC)是對稱式簽章演算法,仰賴發送方與接收方共享一把金鑰。基本流程是:把訊息與金鑰以某種方式結合,再雜湊該組合,得到一個沒有原訊息與共享金鑰就難以重現的值,當作簽章一併送出;接收方以相同演算法重算並比對即可驗證。

圖表 7-14:一個簡單的 MAC 實作

你可能想用最簡單的方式結合金鑰與訊息——直接把金鑰接在訊息前面再雜湊。但對許多常見雜湊演算法(含 MD5 與 SHA-1)而言,這是嚴重的安全錯誤,會開啟長度延伸攻擊(length-extension attack)

長度延伸攻擊與碰撞攻擊

許多常見雜湊演算法(含 MD5、SHA-1)採用區塊結構:先把訊息切成等大小區塊逐一處理(MD5 區塊為 64 位元組)。演算法在區塊之間唯一保留的狀態,就是前一區塊的雜湊值;第一個區塊的前置雜湊值是一組精心挑選的常數。

圖表 7-15:MD5 的區塊結構

關鍵在於:最終輸出只取決於前一區塊雜湊與當前區塊,且對最終雜湊值不做任何額外置換。因此可以「從最後的雜湊值出發」(而非預設常數),接著跑過你想追加的資料區塊,藉此延伸雜湊值。

  • 長度延伸攻擊:若 MAC 把金鑰前置於訊息開頭,等攻擊者取得控制權時金鑰早已被雜湊進演算法狀態。攻擊者因此能在不知道金鑰的情況下,於訊息尾端追加更多區塊並算出對應的 MAC(例如在已上傳的檔案末端附加額外資料)。
  • 碰撞攻擊:若改把金鑰放到訊息尾端,雖能防止長度延伸,卻仍有問題:攻擊者只需找到一個雜湊碰撞(與真實訊息雜湊值相同的另一則訊息)。由於許多雜湊演算法(含 MD5)不具碰撞抵抗性,MAC 仍可能受此攻擊。(SHA-3 不易受此攻擊。)

雜湊訊息鑑別碼(HMAC)#

雜湊訊息鑑別碼(Hashed Message Authentication Code, HMAC)可對抗上述攻擊。它不直接把金鑰接到訊息上,而是把流程拆成兩步:

  • 內層填充區塊(inner padding block):金鑰與一個等於雜湊區塊大小、填滿重複值(通常為 0x36)的填充區塊做 XOR,前置到訊息前再雜湊。
  • 外層填充區塊(outer padding block):取第一步的雜湊值,前置一把新金鑰(以常數 0x5C 產生),再次套用雜湊演算法,得到最終 HMAC 值。

圖表 7-16:HMAC 的構造

這種構造能同時抵抗長度延伸攻擊與碰撞攻擊,因為攻擊者沒有金鑰就無法輕易預測最終雜湊值。