AES-128 RTL 初學者圖解
本文件用圖解說明 AES-128 加密器的資料流、各個 sub-block 的功能、模組連接方式,以及 RTL 控制流程。
1. 先認識 AES-128
AES-128 每次處理:
- 一組 128-bit 明文(Plaintext)
- 一把 128-bit 金鑰(Cipher Key)
- 產生一組 128-bit 密文(Ciphertext)
- 總共執行 10 個 rounds
AES-128 不是把 128 bits 當成一個大數字計算,而是先切成 16 個 bytes。
128 bits = 16 bytes
Plaintext = 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF
| | | | | | | | | | | | | | | |
B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 B10...........B15
2. 初學者版 Top-Level 架構
Top-Level IO
| 訊號 | 方向 | 寬度 | 功能 |
|---|---|---|---|
clk | Input | 1 | 系統時脈 |
rst_n | Input | 1 | Active-low synchronous reset |
key_valid | Input | 1 | 表示 key_data 有效 |
key_ready | Output | 1 | 核心可以接收新金鑰 |
key_data | Input | 128 | AES-128 cipher key |
in_valid | Input | 1 | 表示 in_data 有效 |
in_ready | Output | 1 | 核心可以接收明文 |
in_data | Input | 128 | 128-bit plaintext |
out_valid | Output | 1 | 表示 out_data 有效 |
out_ready | Input | 1 | 下游可以接收密文 |
out_data | Output | 128 | 128-bit ciphertext |
busy | Output | 1 | AES 正在運算 |
資料只有在 valid=1 且 ready=1 的 clock edge 才真正被接收。
3. 完整 AES-128 加密流程
初學者只要先記住:
Round 0 = AddRoundKey
Round 1~9 = SubBytes + ShiftRows + MixColumns + AddRoundKey
Round 10 = SubBytes + ShiftRows + AddRoundKey
Final Round 不做 MixColumns。
4. AES State 的 4 x 4 Byte 排列
AES 把 16 bytes 排成 4 rows x 4 columns,而且採用 column-major 排列。
128-bit input bytes:
B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 B12 B13 B14 B15
放入 AES State 後:
Column 0 Column 1 Column 2 Column 3
Row 0 B0 B4 B8 B12
Row 1 B1 B5 B9 B13
Row 2 B2 B6 B10 B14
Row 3 B3 B7 B11 B15
對應 RTL bit mapping:
B0 = state[127:120] B8 = state[63:56]
B1 = state[119:112] B9 = state[55:48]
B2 = state[111:104] B10 = state[47:40]
B3 = state[103:96] B11 = state[39:32]
B4 = state[95:88] B12 = state[31:24]
B5 = state[87:80] B13 = state[23:16]
B6 = state[79:72] B14 = state[15:8]
B7 = state[71:64] B15 = state[7:0]
這個排列方式必須先固定,否則 ShiftRows 和 MixColumns 很容易接錯 byte。
5. 一個 Normal Round 的模組連接
aes_encrypt_round IO
module aes_encrypt_round (
input logic [127:0] state_i,
input logic [127:0] round_key_i,
output logic [127:0] state_o
);
此模組是 combinational logic。輸入一個 state 和 round key,輸出完成一個 normal round 的新 state。
6. SubBytes:每個 Byte 查 S-box
功能
- 將 128-bit state 分成 16 個 8-bit bytes。
- 每個 byte 獨立通過同一張 AES S-box 查表。
- 16 個 bytes 的位置不改變。
- 16 個 S-box 可以平行運算。
IO
module aes_sub_bytes (
input logic [127:0] state_i,
output logic [127:0] state_o
);
module aes_sbox (
input logic [7:0] data_i,
output logic [7:0] data_o
);
小例子
S-box(8'h53) = 8'hED
輸入 byte 53
|
AES S-box
|
輸出 byte ED
7. ShiftRows:移動位置,不改變 Byte 數值
ShiftRows 前 ShiftRows 後
B0 B4 B8 B12 B0 B4 B8 B12
B1 B5 B9 B13 ---> B5 B9 B13 B1
B2 B6 B10 B14 B10 B14 B2 B6
B3 B7 B11 B15 B15 B3 B7 B11
Row 0:左移 0 格
Row 1:循環左移 1 格
Row 2:循環左移 2 格
Row 3:循環左移 3 格
RTL 接線觀念
IO
module aes_shift_rows (
input logic [127:0] state_i,
output logic [127:0] state_o
);
ShiftRows 只需要重新接線,不需要 S-box、加法器、乘法器或 register。
8. MixColumns:每次混合一個 Column
MixColumns 將每個 column 內的 4 個 bytes 混合。四個 columns 彼此獨立,可以平行運算。
單一 Column 內部連接
輸入 Column 輸出 Column
a0 ---- x2 --+ y0 = 2*a0 ^ 3*a1 ^ a2 ^ a3
a1 ---- x3 --+--> XOR --> y0 y1 = a0 ^ 2*a1 ^ 3*a2 ^ a3
a2 --------- + y2 = a0 ^ a1 ^ 2*a2 ^ 3*a3
a3 --------- + y3 = 3*a0 ^ a1 ^ a2 ^ 2*a3
這裡的乘 2、乘 3是在有限體 GF(2^8) 中運算,不是一般整數乘法。
mul2(x) = xtime(x)
mul3(x) = xtime(x) XOR x
IO
module aes_mix_columns (
input logic [127:0] state_i,
output logic [127:0] state_o
);
module aes_mix_one_column (
input logic [31:0] column_i,
output logic [31:0] column_o
);
初學者記憶方式
ShiftRows:bytes 在不同 columns 之間移動。MixColumns:把同一 column 內的 4 個 bytes 混合。- AES 標準沒有
MixRows這個步驟。
9. AddRoundKey:State 與 Round Key 做 XOR
功能
state_o[127:0] = state_i[127:0] XOR round_key_i[127:0]
Byte 例子
State byte = 8'h53 = 0101_0011
Key byte = 8'hCA = 1100_1010
---------
Result = 8'h99 = 1001_1001
IO
module aes_add_round_key (
input logic [127:0] state_i,
input logic [127:0] round_key_i,
output logic [127:0] state_o
);
10. Final Round 的連接
Final Round 與 Normal Round 的唯一主要差別:
Normal Round:有 MixColumns
Final Round :沒有 MixColumns
11. AES-128 Key Expansion
原始 128-bit key 會被展開成 11 把 128-bit round keys。
一次 Key Expansion Step
將一把 128-bit key 分成四個 32-bit words:
key_i[127:0] = { w0, w1, w2, w3 }
計算式:
temp = SubWord(RotWord(w3)) XOR Rcon(round)
w4 = w0 XOR temp
w5 = w1 XOR w4
w6 = w2 XOR w5
w7 = w3 XOR w6
next_round_key = {w4, w5, w6, w7}
Key Expansion IO
module aes128_key_expand_step (
input logic [127:0] key_i,
input logic [3:0] round_i,
output logic [127:0] key_o
);
round_i 的有效範圍是 1 到 10。
12. Iterative RTL Datapath
為了讓初版面積較小,可以只放一套 AES Round 硬體,每個 clock 重複使用一次。
每個 Clock 做什麼
| Clock 階段 | State Register 更新內容 | 使用的 Key |
|---|---|---|
| 接收輸入 | plaintext | 無 |
| Round 0 | plaintext XOR original_key | Round Key 0 |
| Round 1 | Normal Round 結果 | Round Key 1 |
| Round 2 | Normal Round 結果 | Round Key 2 |
| … | … | … |
| Round 9 | Normal Round 結果 | Round Key 9 |
| Round 10 | Final Round 結果 | Round Key 10 |
| Output | 保持結果直到被接收 | 無 |
13. Controller FSM
狀態功能
| FSM State | 功能 |
|---|---|
NO_KEY | 等待載入 128-bit key |
READY | 已有 key,等待 plaintext |
ROUND_0 | 執行 initial AddRoundKey |
NORMAL_ROUND | 依序執行 rounds 1 到 9 |
FINAL_ROUND | 執行 round 10,不做 MixColumns |
OUTPUT_HOLD | out_valid=1,保持密文直到 out_ready=1 |
14. Valid/Ready 握手圖
Clock 1 2 3 4 5
| | | | |
in_valid 0_______/‾‾‾‾‾‾‾\_______________
in_ready 0_______/‾‾‾‾‾‾‾\_______________
^
在此 clock edge 接收 plaintext
Clock N N+1 N+2 N+3
| | | |
out_valid 0_______/‾‾‾‾‾‾‾‾‾‾‾‾‾\____
out_ready 0_______________/‾‾‾‾‾\____
^
在此 clock edge 傳送 ciphertext
當 out_valid=1 但 out_ready=0:
out_valid必須保持為 1。out_data必須保持不變。- 核心停在
OUTPUT_HOLD。
15. 建議的 RTL Module Hierarchy
在 RTL 中 aes_sub_bytes 可以由 normal round 和 final round 共用同一套 combinational logic;上圖主要用來表達功能階層。
16. 建議教學順序
- 先用一張圖說明 plaintext + key 產生 ciphertext。
- 解釋 128 bits 如何拆成 16 bytes 和 4 x 4 state。
- 只介紹四個基本積木:SubBytes、ShiftRows、MixColumns、AddRoundKey。
- 組合出 normal round。
- 說明 final round 少了 MixColumns。
- 再加入 key expansion。
- 最後才解釋 register、round counter、FSM 和 valid/ready。
17. 最小實作檢查表
- State byte mapping 已明確定義。
- SubBytes 有 16 個 byte substitutions。
- ShiftRows 只做 byte permutation。
- MixColumns 對 4 個 columns 分別運算。
- AddRoundKey 是 128-bit XOR。
- Key Expansion 能產生 Round Keys 1 到 10。
- Rounds 1 到 9 有 MixColumns。
- Round 10 沒有 MixColumns。
-
out_valid && !out_ready時輸出保持不變。 - 通過 FIPS-197 標準測試向量。
標準測試向量:
Key = 000102030405060708090A0B0C0D0E0F
Plaintext = 00112233445566778899AABBCCDDEEFF
Ciphertext = 69C4E0D86A7B0430D8CDB78070B4C55A