AES(Advanced Encryption Standard,進階加密標準)是全宇宙使用最廣的密碼。
在 AES 被採用之前,標準密碼是 DES 與其升級版 Triple DES(3DES):
- DES 的安全性只有荒謬的 56 位元。
- 3DES 雖然提供更高的安全等級(112 位元),卻沒有效率——金鑰得長達 168 位元才能得到 112 位元安全性,而且在軟體中很慢(DES 是為了在積體電路上快,而非在主流 CPU 上快而設計的)。
AES 兩個問題都解決了。
NIST 於 2000 年將 AES 標準化以取代 DES,此後它成為全世界事實上的加密標準。今日多數商用加密產品都支援 AES,NSA 也核准它用於保護最高機密資訊。
(有些國家確實偏好使用自己的密碼,多半是因為他們不想用美國標準——但 AES 其實比較像比利時的東西,而非美國的。)
延伸:AES 競賽與 Rijndael 這個名字
AES 在成為 AES 競賽 15 個候選者之一時,原本叫做 Rijndael——這是它兩位發明者 Rijmen 與 Daemen 名字的合併,唸起來像 “rain-dull”。
AES 競賽是 NIST 於 1997 至 2000 年間舉辦的流程,目的依 1997 年《聯邦公報》的競賽公告所述,是要規範出「一個非機密的、公開揭露的加密演算法,能夠妥善保護敏感的政府資訊直到下個世紀」。
這場競賽有點像密碼學家版的「達人秀」:任何人都能參加,方式是提交一個密碼,或是破解其他參賽者的密碼。
AES 內部結構#
AES 以 128、192 或 256 位元的秘密金鑰處理 128 位元的區塊。128 位元金鑰最常見,因為它讓加密略快一些,而且對多數應用而言,128 位元與 256 位元安全性之間的差別沒有意義。
內部狀態#
有些密碼處理單一位元或 64 位元字,AES 則操作位元組。它把 16 位元組的明文視為一個二維位元組陣列 s = s₀, s₁, ..., s₁₅,排成 4×4:
s0 s4 s8 s12
s1 s5 s9 s13
s2 s6 s10 s14
s3 s7 s11 s15(用字母 s 是因為這個陣列稱為內部狀態,internal state,或簡稱 state。)AES 變換這個陣列的位元組、欄與列,產生最終值也就是密文。

圖 4-3:AES 的內部狀態:16 位元組的 4 × 4 陣列
輪數#
AES 使用 SPN 結構,輪數依金鑰長度而定:
| 金鑰長度 | 輪數 |
|---|---|
| 128 位元 | 10 |
| 192 位元 | 12 |
| 256 位元 | 14 |

圖 4-4:AES 的內部運作
一輪的四個構件#
除了最後一輪之外,每一輪都是 SubBytes、ShiftRows、MixColumns、AddRoundKey 的序列:
AddRoundKey:把一把輪金鑰 XOR 進內部狀態。
SubBytes:依 S-box 把每個位元組
s₀, s₁, ..., s₁₅替換成另一個位元組。此處的 S-box 是一張 256 個元素的查找表。ShiftRows:把第
i列位移i個位置(i從 0 到 3):s0 s4 s8 s12 s0 s4 s8 s12 s1 s5 s9 s13 → s5 s9 s13 s1 s2 s6 s10 s14 s10 s14 s2 s6 s3 s7 s11 s15 s15 s3 s7 s11

圖 4-5:ShiftRows 在內部狀態的每一列中旋轉位元組
- MixColumns:對狀態的四個欄各套用相同的線性變換。
記得 SPN 中 S 代表替換、P 代表置換。這裡的替換層是 SubBytes,置換層是 ShiftRows 與 MixColumns 的組合。
金鑰排程:KeyExpansion#
KeyExpansion 是 AES 的金鑰排程演算法。它從 16 位元組的金鑰產生 11 把各 16 位元組的輪金鑰(K₀, K₁, ..., K₁₀),使用與 SubBytes 相同的 S-box 以及一系列 XOR。
這種「從任一輪金鑰就能取得主金鑰」的能力,通常被視為對旁道攻擊的防禦不夠完善——因為攻擊者可能輕易還原出某一把輪金鑰。
每個操作為何不可或缺#
少了這些操作,AES 會完全不安全。每個操作都以特定方式貢獻了 AES 的安全性:
- 沒有 KeyExpansion:所有輪都會使用同一把金鑰
K,AES 就會受滑動攻擊。 - 沒有 AddRoundKey:加密就不依賴金鑰,任何人都能在沒有金鑰的情況下解密任何密文。
- 沒有 SubBytes:SubBytes 帶來非線性運算,也就是密碼學強度。少了它,AES 只會是一個大型線性方程組,用高中代數就能解開。
- 沒有 ShiftRows:某一欄的變化永遠不會影響其他欄,意味著你可以為每一欄建立四張 2^32 個元素的碼本來破解 AES。(記得在安全的區塊密碼中,翻轉輸入的一個位元應該影響所有輸出位元。)
- 沒有 MixColumns:某個位元組的變化不會影響狀態中的其他位元組。選擇明文攻擊者只要存下 16 張各 256 位元組的查找表(存放每個位元組每個可能值的加密結果),就能解密任何密文。
AES 的最後一輪不含 MixColumns。省略它是為了免去無用的計算:因為 MixColumns 是線性的(也就是可預測的),你可以用一種不依賴位元值也不依賴金鑰的方式組合位元,來抵銷它在最末輪的效果。
但 SubBytes 不同——在 AddRoundKey 之前的狀態值未知時,它無法被反轉。
解密#
要解密一段密文,AES 對每個操作取其反函式逐一回捲:
- SubBytes 的反查找表還原 SubBytes 變換。
- ShiftRows 往反方向位移。
- 套用 MixColumns 的反矩陣(即編碼其操作之矩陣的反矩陣)。
- AddRoundKey 的 XOR 維持不變,因為 XOR 的反運算還是 XOR。
動手試試#
用 Python 的 cryptography 函式庫試試 AES 的加解密:
#!/usr/bin/env python
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
from binascii import hexlify as hexa
from os import urandom
# pick a random 16-byte key using Python's crypto PRNG
k = urandom(16)
print "k = %s" % hexa(k)
# create an instance of AES-128 to encrypt a single block
cipher = Cipher(algorithms.AES(k), modes.ECB(), backend = default_backend())
aes_encrypt = cipher.encryptor()
# set plaintext block p to the all-zero string
p = '\x00'*16
# encrypt plaintext p to ciphertext c
c = aes_encrypt.update(p) + aes_encrypt.finalize()
print "enc(%s) = %s" % (hexa(p), hexa(c))
# decrypt ciphertext c to plaintext p
aes_decrypt = cipher.decryptor()
p = aes_decrypt.update(c) + aes_decrypt.finalize()
print "dec(%s) = %s" % (hexa(c), hexa(p))執行後會得到類似這樣的輸出(因為每次執行金鑰都隨機,你的結果會不同):
$ ./aes_block.py
k = 2c6202f9a582668aa96d511862d8a279
enc(00000000000000000000000000000000) = 12b620bb5eddcde9a07523e59292a6d7
dec(12b620bb5eddcde9a07523e59292a6d7) = 00000000000000000000000000000000AES 安全嗎#
AES 已經安全到一個區塊密碼所能達到的程度,而且它永遠不會被破解。
根本原因在於:所有輸出位元都以某種複雜的、偽隨機的方式依賴於所有輸入位元。
為了達成這點,AES 的設計者為每個元件都有特定理由地審慎挑選——MixColumns 是為了它最大化的擴散性質,SubBytes 是為了它最佳的非線性——並且證明了這樣的組合能保護 AES 免於整類整類的密碼分析攻擊。
但沒有證明#
並沒有證明說 AES 對所有可能的攻擊免疫。
一來我們不知道所有可能的攻擊有哪些,二來我們也不總是知道如何證明一個密碼對某個給定攻擊是安全的。
真正對 AES 安全性建立信心的唯一方式,就是群眾外包攻擊:讓許多有能力的人嘗試破解 AES,並且(但願如此)失敗。
經過超過 15 年、數百篇研究論文,AES 的理論安全性只被搔到一點皮毛。
2011 年密碼分析者找到一個方法,執行約 2^126 次(而非 2^128 次)運算就能還原 AES-128 金鑰,加速了四倍。
但這個「攻擊」需要瘋狂數量的明文—密文對——約 2^88 位元之多。換句話說,這是個不錯的發現,但不是你需要擔心的東西。
結論:實作與部署密碼學時你該在意的事有一百萬件,但 AES 的安全性不在其中。
區塊密碼最大的威脅不在其核心演算法,而在其運作模式。當模式選錯了、或正確的模式被誤用,即使強如 AES 也救不了你。