阶段一对称密码基础 — 将前四课的组件整合:S-Box + 密钥扩展 + 轮函数 = 完整的 AES-128 加密引擎。这是第一个可独立运行的密码学 IP 核。
AES-128 加密包含初始轮密钥加 + 9 轮标准轮 + 1 轮最终轮:
| 架构 | 面积 | 吞吐量 | 适用场景 |
|---|---|---|---|
| 迭代 | 1× S-Box集合 | 1块/11周期 | 面积受限 |
| 流水线 | 11× S-Box集合 | 1块/周期 | 高吞吐 |
| 混合 | 2-4× S-Box集合 | 折中 | 通用 |
本课实现迭代架构:一轮硬件循环使用 11 次,面积最小。
// aes128_enc.v - AES-128 完整加密引擎(迭代架构)
module aes128_enc (
input wire clk,
input wire rst_n,
input wire start, // 启动加密
input wire [127:0] plaintext, // 明文输入
input wire [127:0] key, // 128位密钥
output reg [127:0] ciphertext, // 密文输出
output reg valid, // 输出有效信号
output reg busy // 引擎忙碌信号
);
// 状态机定义
localparam IDLE = 3'd0;
localparam INIT = 3'd1; // 初始 AddRoundKey
localparam ROUND = 3'd2; // 标准轮
localparam FINAL = 3'd3; // 最终轮
localparam DONE = 3'd4;
reg [2:0] state_fsm;
reg [3:0] round_cnt;
reg [127:0] state_reg;
reg [31:0] w [0:3]; // 当前轮密钥的4个字
reg [7:0] rcon [0:9];
initial begin
rcon[0]=8'h01; rcon[1]=8'h02; rcon[2]=8'h04; rcon[3]=8'h08;
rcon[4]=8'h10; rcon[5]=8'h20; rcon[6]=8'h40; rcon[7]=8'h80;
rcon[8]=8'h1b; rcon[9]=8'h36;
end
// S-Box 实例化(16个并行)
wire [7:0] sb_in [0:15];
wire [7:0] sb_out [0:15];
genvar gi;
generate
for (gi = 0; gi < 16; gi = gi + 1) begin : gen_sb
assign sb_in[gi] = state_reg[gi*8+7 -: 8];
aes_sbox_lut u_sb (.addr(sb_in[gi]), .data(sb_out[gi]));
end
endgenerate
wire [127:0] after_sub = {sb_out[15],sb_out[14],sb_out[13],sb_out[12],
sb_out[11],sb_out[10],sb_out[9],sb_out[8],
sb_out[7],sb_out[6],sb_out[5],sb_out[4],
sb_out[3],sb_out[2],sb_out[1],sb_out[0]};
// ShiftRows
wire [127:0] after_shift;
aes_shiftrows u_sr (.state_in(after_sub), .state_out(after_shift));
// MixColumns
wire [127:0] after_mix;
aes_mixcol mc0 (.s0(after_shift[127:120]), .s1(after_shift[119:112]),
.s2(after_shift[111:104]), .s3(after_shift[103:96]),
.d0(after_mix[127:120]), .d1(after_mix[119:112]),
.d2(after_mix[111:104]), .d3(after_mix[103:96]));
aes_mixcol mc1 (.s0(after_shift[95:88]), .s1(after_shift[87:80]),
.s2(after_shift[79:72]), .s3(after_shift[71:64]),
.d0(after_mix[95:88]), .d1(after_mix[87:80]),
.d2(after_mix[79:72]), .d3(after_mix[71:64]));
aes_mixcol mc2 (.s0(after_shift[63:56]), .s1(after_shift[55:48]),
.s2(after_shift[47:40]), .s3(after_shift[39:32]),
.d0(after_mix[63:56]), .d1(after_mix[55:48]),
.d2(after_mix[47:40]), .d3(after_mix[39:32]));
aes_mixcol mc3 (.s0(after_shift[31:24]), .s1(after_shift[23:16]),
.s2(after_shift[15:8]), .s3(after_shift[7:0]),
.d0(after_mix[31:24]), .d1(after_mix[23:16]),
.d2(after_mix[15:8]), .d3(after_mix[7:0]));
// 密钥扩展辅助:RotWord + SubWord + Rcon
wire [31:0] rot_w = {w[3][23:0], w[3][31:24]};
wire [7:0] sw0, sw1, sw2, sw3;
aes_sbox_lut u_rsb0 (.addr(rot_w[7:0]), .data(sw0));
aes_sbox_lut u_rsb1 (.addr(rot_w[15:8]), .data(sw1));
aes_sbox_lut u_rsb2 (.addr(rot_w[23:16]), .data(sw2));
aes_sbox_lut u_rsb3 (.addr(rot_w[31:24]), .data(sw3));
wire [31:0] t_func = {sw3, sw2, sw1, sw0} ^ {rcon[round_cnt-1], 24'h0};
// 轮密钥
wire [127:0] round_key = {w[0], w[1], w[2], w[3]};
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state_fsm <= IDLE;
round_cnt <= 4'd0;
state_reg <= 128'h0;
ciphertext <= 128'h0;
valid <= 1'b0;
busy <= 1'b0;
w[0] <= 32'h0; w[1] <= 32'h0;
w[2] <= 32'h0; w[3] <= 32'h0;
end else begin
valid <= 1'b0;
case (state_fsm)
IDLE: begin
if (start) begin
w[0] <= key[127:96]; w[1] <= key[95:64];
w[2] <= key[63:32]; w[3] <= key[31:0];
state_reg <= plaintext ^ {key[127:96],key[95:64],
key[63:32],key[31:0]};
round_cnt <= 4'd1;
busy <= 1'b1;
state_fsm <= ROUND;
end
end
ROUND: begin
// 更新轮密钥
w[0] <= w[0] ^ t_func;
w[1] <= w[1] ^ (w[0] ^ t_func);
w[2] <= w[2] ^ (w[1] ^ (w[0] ^ t_func));
w[3] <= w[3] ^ (w[2] ^ (w[1] ^ (w[0] ^ t_func)));
// 更新状态
state_reg <= after_mix ^ {w[0]^t_func,
w[1]^(w[0]^t_func),
w[2]^(w[1]^(w[0]^t_func)),
w[3]^(w[2]^(w[1]^(w[0]^t_func)))};
round_cnt <= round_cnt + 4'd1;
if (round_cnt == 4'd9)
state_fsm <= FINAL;
end
FINAL: begin
w[0] <= w[0] ^ t_func;
w[1] <= w[1] ^ (w[0] ^ t_func);
w[2] <= w[2] ^ (w[1] ^ (w[0] ^ t_func));
w[3] <= w[3] ^ (w[2] ^ (w[1] ^ (w[0] ^ t_func)));
state_reg <= after_shift ^ {w[0]^t_func,
w[1]^(w[0]^t_func),
w[2]^(w[1]^(w[0]^t_func)),
w[3]^(w[2]^(w[1]^(w[0]^t_func)))};
state_fsm <= DONE;
end
DONE: begin
ciphertext <= state_reg;
valid <= 1'b1;
busy <= 1'b0;
state_fsm <= IDLE;
end
endcase
end
end
endmodule
// aes128_enc_tb.v - AES-128 加密引擎测试台
module aes128_enc_tb;
reg clk, rst_n, start;
reg [127:0] plaintext, key;
wire [127:0] ciphertext;
wire valid, busy;
aes128_enc uut (
.clk(clk), .rst_n(rst_n), .start(start),
.plaintext(plaintext), .key(key),
.ciphertext(ciphertext), .valid(valid), .busy(busy)
);
always #5 clk = ~clk;
initial begin
clk = 0; rst_n = 0; start = 0;
#20 rst_n = 1;
// NIST FIPS-197 Appendix B 测试向量
key = 128'h2b7e151628aed2a6abf7158809cf4f3c;
plaintext = 128'h3243f6a8885a308d313198a2e0370734;
start = 1; #10; start = 0;
// 期望密文: 3925841d02dc09fbdc118597196a0b32
wait(valid);
$display("Ciphertext: %032h", ciphertext);
$display("Expected: 3925841d02dc09fbdc118597196a0b32");
if (ciphertext == 128'h3925841d02dc09fbdc118597196a0b32)
$display("✅ NIST test PASSED!");
else
$display("❌ NIST test FAILED!");
$finish;
end
endmodule
| 指标 | 值 |
|---|---|
| 延迟 | 11 个时钟周期(1 初始 + 9 标准轮 + 1 最终轮) |
| 吞吐量 | 128位 / 11 周期(约 11.6 位/周期) |
| S-Box 数量 | 20(16 SubBytes + 4 密钥扩展) |
| 关键路径 | S-Box → ShiftRows → MixColumns → AddRoundKey |
1. 使用 NIST 测试向量完整验证 AES-128 加密,确保每一位都正确。
2. 将迭代架构改为流水线架构:11 级流水线,每级处理一轮。计算面积开销和吞吐量提升。
3. 实现 AES 的 ECB 模式:连续加密多个 128 位块。然后实现 CBC 模式(需要反馈 XOR)。
4. 安全思考:迭代架构中,轮密钥的中间值是否可能通过功耗侧信道泄露?如何防护?
你已成功构建完整的 AES-128 加密引擎!从 S-Box 到轮函数到顶层集成,所有组件协同工作,通过了 NIST 标准测试向量验证。这是密码学硬件工程的第一个里程碑!
获得徽章:🔐 AES_ENGINE
推荐使用以下工具链进行课程实践:
# 安装 Verilator
sudo apt install verilator
# 安装 Icarus Verilog(可选)
sudo apt install iverilog
# 安装 GTKWave(波形查看器)
sudo apt install gtkwave
# 验证安装
verilator --lint-only --version
iverilog -V
密码学硬件实现的关键性能指标:
这些指标之间通常存在 trade-off,设计时需根据应用场景权衡。
11 级流水线,每级处理一轮。面积开销大(11× S-Box = 176 个 S-Box),但吞吐量极高。
// 流水线 AES:每周期输出一个密文块
Stage 0: AddRoundKey(K0)
Stage 1: SubBytes → ShiftRows → MixColumns → AddRoundKey(K1)
...
Stage 10: SubBytes → ShiftRows → AddRoundKey(K10)
复用同一套 S-Box 和 MixColumns 逻辑,通过 MUX 选择当前轮的输入。面积最小,但每块需 11 周期。
| 架构 | S-Box数 | 延迟 | 吞吐量 |
|---|---|---|---|
| 迭代 | 20 | 11周期 | 11.6 bit/cyc |
| 2级流水线 | 40 | 6周期 | 21.3 bit/cyc |
| 全流水线 | 176 | 1周期 | 128 bit/cyc |