4.2 區塊模式 ECB CBC CTR GCM#
概念說明#
區塊加密每次只能加密一個區塊(AES 為 16 位元組)。要加密任意長度資料,必須使用工作模式(mode of operation)——決定多個區塊之間如何串接。演算法安全 ≠ 系統安全:真實世界對 AES 的絕大多數攻擊都是攻擊模式或 IV/nonce 的使用,而不是 AES 本身。
各模式原理#
ECB(Electronic Codebook)——禁止使用#
C_i = E_K(P_i),各區塊完全獨立。相同明文區塊 → 相同密文區塊,洩漏資料圖案(著名的「ECB 企鵝」:加密企鵝圖片,輪廓依稀可見)。3.3 節已示範。唯一可用場景:加密的資料本身就無圖案且短於一個區塊(如加密一把金鑰)。
CBC(Cipher Block Chaining)#
C_i = E_K(P_i ⊕ C_{i-1}),且 C_0 = IV
把每個明文區塊先與前一個密文區塊 XOR,打斷圖案。要求:IV 隨機且不可預測(若 IV 可預測,攻擊者可對第一個區塊做選定明文區分攻擊)。
已知陷阱:CBC 只提供機密性。若配合可變填充(padding oracle),解密端對「填充錯誤」與「MAC 錯誤」回報不同錯誤訊息,攻擊者可逐位元組解出明文(2010 年 ASP.NET、2014 年 POODLE 均屬此類)。教訓:錯誤訊息也是側頻道。
CTR(Counter)#
C_i = P_i ⊕ E_K(Nonce || counter_i)
把區塊加密當成偽隨機金鑰流產生器——本質是串流加密(3.1 節 OTP 的偽隨機版)。優點:可平行、可隨機存取、無需填充。鐵律:同一把金鑰下 nonce 絕不可重用,否則兩段密文 XOR 後金鑰流消去(C1⊕C2 = P1⊕P2),機密性全毀,甚至可利用已知明文還原金鑰流攻擊其他密文。
GCM(Galois/Counter Mode)——現代首選#
GCM = CTR 加密 + GHash(GF(2^128) 上的通用雜湊)認證,是 AEAD(認證加密附關聯資料):同時輸出密文與認證標籤 tag,解密時先驗證 tag、不通過即拒絕——竄改密文會被察覺,解決了 CBC 時代「加密但不完整」的問題(1.2 節四大目標之二)。關聯資料(AAD)可納入保護但不加密(如封包標頭)。
Python 實作與比較#
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import os
key = os.urandom(16)
pt = b"Transfer $100 to Alice" * 4
# --- CBC ---
iv = os.urandom(16) # 隨機、不可預測
cbc = AES.new(key, AES.MODE_CBC, iv)
ct = cbc.encrypt(pad(pt, 16))
pt2 = unpad(AES.new(key, AES.MODE_CBC, iv).decrypt(ct), 16)
print(pt2)
# --- CTR ---
from Crypto.Util import Counter
nonce = os.urandom(8)
ctr = Counter.new(64, prefix=nonce, initial_value=0)
ct = AES.new(key, AES.MODE_CTR, counter=ctr).encrypt(pt)
# --- GCM(AEAD,推薦) ---
c = AES.new(key, AES.MODE_GCM)
ct, tag = c.encrypt_and_digest(pt)
try:
d = AES.new(key, AES.MODE_GCM, nonce=c.nonce)
d.update(b"tamper") # AAD 不一致 → 驗證失敗
print(d.decrypt_and_verify(ct, tag))
except ValueError:
print("認證失敗:密文或 AAD 已被竄改!")
安全性分析與選擇指引#
| 模式 | 機密性 | 完整性 | 風險點 |
|---|---|---|---|
| ECB | 弱 | 無 | 洩漏圖案,禁止 |
| CBC | 可(IV 需隨機) | 無 | padding oracle、需另配 MAC(建議先 MAC 後加密,即 EtM) |
| CTR | 可(nonce 唯一) | 無 | nonce 重用即全毀 |
| GCM | 可 | 有 | nonce 重用會同時毀機密性與認證;高流量需 nonce 管理策略 |
實務建議:新系統一律選 AEAD——GCM 或 ChaCha20-Poly1305(4.3 節);nonce 用 96 位元隨機值,或依協定以計數器維護唯一性;密文一律視為「不可信輸入」,解密必須經驗證後才使用。TLS 1.3 更進一步:只保留 AEAD 模式,直接淘汰 CBC。
練習#
- 用 ECB 與 CBC 分別加密一張圖片(參考 3.3 節程式碼改用 AES),比較兩張輸出圖的視覺差異。
- 寫一個簡化的 padding oracle 模擬:一個函數對「填充正確/錯誤」回傳不同結果,另一個函數扮演攻擊者逐位元組還原明文。(在教學環境內進行!)
- 解釋為什麼 GCM 在同一金鑰下重用 nonce 比單純的 CTR 重用更嚴重?(提示:GHash 的認證金鑰可由 nonce 重用恢復出來,隨後可偽造任意密文。)