區塊密碼有數百種,但建構它們的技巧只有寥寥幾種。兩個要點:
- 實務上使用的區塊密碼不是一個巨大的演算法,而是輪(rounds)的重複——輪是一段短短的運算序列,單獨看很弱,但數量一多就強。
- 建構「輪」主要有兩種技巧:替換—置換網路(AES 採用)與 Feistel 架構(DES 採用)。
區塊密碼的輪#
計算一個區塊密碼,歸根究柢就是計算一連串的輪。在區塊密碼中,一輪是一個易於規範、易於實作的基本變換,經過數次迭代就形成該區塊密碼的演算法。
這種「小元件重複多次」的建構方式,比起「單一巨大演算法」的建構方式,更容易實作、也更容易分析。
例如一個三輪的區塊密碼,把明文加密成 C = R₃(R₂(R₁(P)))。每一輪也必須有反函式,接收者才能算回明文:P = iR₁(iR₂(iR₃(C))),其中 iR₁ 是 R₁ 的反函式。
輪金鑰#
輪函式 R₁、R₂ 等通常是相同的演算法,但由一個稱為輪金鑰(round key)的值加以參數化。兩個使用相異輪金鑰的輪函式行為會不同,因此餵入相同輸入時會產生相異的輸出。
輪金鑰是用一個稱為金鑰排程(key schedule)的演算法從主金鑰 K 衍生而來:R₁ 用輪金鑰 K₁,R₂ 用 K₂,依此類推。
每一輪的輪金鑰都應該彼此相異,而且不是所有輪金鑰都該等於金鑰
K。否則所有的輪都會相同,區塊密碼就會變得比較不安全——原因見下。
滑動攻擊#
在區塊密碼中,任何一輪都不該與另一輪相同,以避免滑動攻擊(slide attack)。
滑動攻擊尋找兩組明文/密文對 (P₁, C₁) 與 (P₂, C₂),其中 P₂ = R(P₁)(R 是該密碼的輪)。
當各輪相同時,兩段明文之間的關係
P₂ = R(P₁)會蘊含其對應密文之間的關係C₂ = R(C₁)。而且無論有幾輪——3 輪、10 輪還是 100 輪——
C₂ = R(C₁)這個關係都成立。問題在於:知道單獨一輪的輸入與輸出,往往就足以還原金鑰。
使用不同的輪金鑰作為參數,確保了各輪行為相異,從而挫敗滑動攻擊。

圖 4-1:滑動攻擊的原理:針對各輪相同的區塊密碼
使用輪金鑰的一個潛在副產品與好處,是對旁道攻擊的防護。
若從主金鑰
K到輪金鑰Kᵢ的變換是不可逆的,那麼即使攻擊者找到了Kᵢ,也無法用它反推K。遺憾的是,很少區塊密碼具有單向的金鑰排程。例如 AES 的金鑰排程就允許攻擊者從任何一個輪金鑰
Kᵢ算出K。詳見 Biryukov 與 Wagner 1999 年的論文〈Advanced Slide Attacks〉。
替換—置換網路(SPN)#
如果你讀過密碼學教科書,一定看過混淆(confusion)與擴散(diffusion)這兩個詞:
- 混淆:輸入(明文與加密金鑰)經歷複雜的變換。
- 擴散:這些變換平均地依賴於輸入的所有位元。
概略地說:混淆關乎深度,擴散關乎廣度。
在區塊密碼的設計中,混淆與擴散以替換與置換操作的形式出現,兩者結合於替換—置換網路(SPN,substitution–permutation networks)之中。
替換:S-box#
替換常以 S-box(substitution box,替換盒)的形式出現,那是轉換 4 或 8 位元資料塊的小型查找表。
例如區塊密碼 Serpent 的八個 S-box 中的第一個,由 16 個元素組成:
3 8 f 1 a 6 5 b e d 4 2 7 0 9 c每個元素代表一個 4 位元的 nibble。這個 S-box 把 4 位元 nibble 0000 映射到 3(0011),把 0101(十進位 5)映射到 6(0110),依此類推。
S-box 必須被審慎挑選以確保密碼學強度:
- 應盡可能非線性(輸入與輸出之間以複雜的方程式關聯)。
- 應無統計偏差(例如翻轉一個輸入位元,應該有可能影響到任何一個輸出位元)。
置換#
替換—置換網路中的置換,可以簡單到只是改變位元的順序——容易實作,但把位元混合得不夠徹底。
有些密碼不用位元重排,而是用基本線性代數與矩陣乘法來混合位元:它們對固定值(矩陣的係數)執行一連串乘法運算,再把結果相加。這類線性代數運算能快速在密碼內的所有位元之間建立依賴關係,從而確保強擴散。
例如區塊密碼 FOX 把一個 4 位元組向量 (a, b, c, d) 變換成 (a′, b′, c′, d′):
a′ = a + b + c + (2 × d)
b′ = a + (253 × b) + (2 × c) + d
c′ = (253 × a) + (2 × b) + c + d
d′ = (2 × a) + b + (253 × c) + d上式中的 2 與 253 被解讀為二元多項式而非整數,因此加法與乘法的定義與我們習慣的略有不同——例如不是
2 + 2 = 4,而是2 + 2 = 0。無論如何,重點是:初始狀態的每個位元組都影響最終狀態的全部 4 個位元組。
Feistel 架構#
1970 年代,IBM 工程師 Horst Feistel 設計了一個名為 Lucifer 的區塊密碼,運作如下:
- 把 64 位元區塊拆成兩個 32 位元的半邊
L與R。 - 令
L = L ⊕ F(R),其中F是一個替換—置換輪。 - 交換
L與R的值。 - 回到步驟 2,重複 15 次。
- 把
L與R合併成 64 位元的輸出區塊。
這個建構後來被稱為 Feistel 架構(Feistel scheme)。

圖 4-2:Feistel 架構的兩種等價表示法
有一個功能上等價的表示法:不交換
L與R,而是讓各輪交替執行L = L ⊕ F(R)與R = R ⊕ F(L)。
各輪的 F 函式接收不同的輪金鑰:第一個 F 用 K₁,第二個用 K₂。在 DES 中,F 函式接收一把從 56 位元金鑰 K 衍生出的 48 位元輪金鑰。
PRP 或 PRF 都可以#
在 Feistel 架構中,F 函式可以是偽隨機置換(PRP)或偽隨機函式(PRF):
- PRP 對任意兩個相異輸入都產出相異輸出。
- PRF 則存在
X與Y使得F(X) = F(Y)。
但在 Feistel 架構中,只要
F在密碼學上夠強,這個差別無關緊要。
該有幾輪#
DES 執行 16 輪,GOST 28147-89 執行 32 輪。
若 F 函式強到極致,理論上四輪就足夠;但真實的密碼會用更多輪,以防禦 F 中潛在的弱點。