1. AES-128加密引擎的RTL设计
任务目标
设计一个可综合的AES-128加密引擎RTL模块,支持标准FIPS-197加密流程:完成密钥扩展(生成11轮轮密钥)与10轮轮函数(SubBytes、ShiftRows、MixColumns、AddRoundKey),并通过仿真验证加密结果与NIST标准测试向量一致。
实现方案与文件结构
采用单文件最小可综合实现,顶层模块 aes128_enc 内部例化密钥扩展与轮函数逻辑。文件结构如下:
aes128_enc.v // 顶层加密引擎(含密钥扩展与轮函数)
aes128_tb.v // 测试平台:加载标准向量并比对结果
关键完整代码
// aes128_enc.v
module aes128_enc (
input wire [127:0] plaintext,
input wire [127:0] key,
output wire [127:0] ciphertext
);
// 内部信号:11轮轮密钥(每轮128bit)
reg [127:0] round_key [0:10];
wire [127:0] state [0:10];
// 密钥扩展(FIPS-197 第5.2节)
integer i;
reg [7:0] rcon [0:10];
always @(*) begin
rcon[0] = 8'h01;
for (i = 1; i < 10; i = i + 1) rcon[i] = rcon[i-1] << 1;
round_key[0] = key;
for (i = 1; i <= 10; i = i + 1) begin
round_key[i] = {round_key[i-1][119:0], 8'h00} ^
{sub_word(rot_word(round_key[i-1][127:96])) ^ {24'h000000, rcon[i-1]},
round_key[i-1][95:64] ^ sub_word(rot_word(round_key[i-1][127:96])) ^ {24'h000000, rcon[i-1]},
round_key[i-1][63:32] ^ sub_word(rot_word(round_key[i-1][127:96])) ^ {24'h000000, rcon[i-1]},
round_key[i-1][31:0] ^ sub_word(rot_word(round_key[i-1][127:96])) ^ {24'h000000, rcon[i-1]}};
end
end
// 轮函数
assign state[0] = plaintext ^ round_key[0];
genvar g;
generate
for (g = 1; g <= 10; g = g + 1) begin : rounds
wire [127:0] sub_out, shift_out, mix_out;
// SubBytes + ShiftRows(合并实现)
assign sub_out = sub_bytes(state[g-1]);
assign shift_out = shift_rows(sub_out);
if (g < 10) begin
assign mix_out = mix_columns(shift_out);
assign state[g] = mix_out ^ round_key[g];
end else begin
assign state[g] = shift_out ^ round_key[g]; // 最后一轮无MixColumns
end
end
endgenerate
assign ciphertext = state[10];
// ---- 子函数定义 ----
function [7:0] sbox;
input [7:0] addr;
reg [7:0] sbox_mem [0:255];
integer idx;
begin
// S-box查找表(FIPS-197 附录A)
sbox_mem[0] = 8'h63; sbox_mem[1] = 8'h7c; sbox_mem[2] = 8'h77; sbox_mem[3] = 8'h7b;
sbox_mem[4] = 8'hf2; sbox_mem[5] = 8'h6b; sbox_mem[6] = 8'h6f; sbox_mem[7] = 8'hc5;
sbox_mem[8] = 8'h30; sbox_mem[9] = 8'h01; sbox_mem[10] = 8'h67; sbox_mem[11] = 8'h2b;
sbox_mem[12] = 8'hfe; sbox_mem[13] = 8'hd7; sbox_mem[14] = 8'hab; sbox_mem[15] = 8'h76;
sbox_mem[16] = 8'hca; sbox_mem[17] = 8'h82; sbox_mem[18] = 8'hc9; sbox_mem[19] = 8'h7d;
sbox_mem[20] = 8'hfa; sbox_mem[21] = 8'h59; sbox_mem[22] = 8'h47; sbox_mem[23] = 8'hf0;
sbox_mem[24] = 8'had; sbox_mem[25] = 8'hd4; sbox_mem[26] = 8'ha2; sbox_mem[27] = 8'haf;
sbox_mem[28] = 8'h9c; sbox_mem[29] = 8'ha4; sbox_mem[30] = 8'h72; sbox_mem[31] = 8'hc0;
sbox_mem[32] = 8'hb7; sbox_mem[33] = 8'hfd; sbox_mem[34] = 8'h93; sbox_mem[35] = 8'h26;
sbox_mem[36] = 8'h36; sbox_mem[37] = 8'h3f; sbox_mem[38] = 8'hf7; sbox_mem[39] = 8'hcc;
sbox_mem[40] = 8'h34; sbox_mem[41] = 8'ha5; sbox_mem[42] = 8'he5; sbox_mem[43] = 8'hf1;
sbox_mem[44] = 8'h71; sbox_mem[45] = 8'hd8; sbox_mem[46] = 8'h31; sbox_mem[47] = 8'h15;
sbox_mem[48] = 8'h04; sbox_mem[49] = 8'hc7; sbox_mem[50] = 8'h23; sbox_mem[51] = 8'hc3;
sbox_mem[52] = 8'h18; sbox_mem[53] = 8'h96; sbox_mem[54] = 8'h05; sbox_mem[55] = 8'h9a;
sbox_mem[56] = 8'h07; sbox_mem[57] = 8'h12; sbox_mem[58] = 8'h80; sbox_mem[59] = 8'he2;
sbox_mem[60] = 8'heb; sbox_mem[61] = 8'h27; sbox_mem[62] = 8'hb2; sbox_mem[63] = 8'h75;
sbox_mem[64] = 8'h09; sbox_mem[65] = 8'h83; sbox_mem[66] = 8'h2c; sbox_mem[67] = 8'h1a;
sbox_mem[68] = 8'h1b; sbox_mem[69] = 8'h6e; sbox_mem[70] = 8'h5a; sbox_mem[71] = 8'ha0;
sbox_mem[72] = 8'h52; sbox_mem[73] = 8'h3b; sbox_mem[74] = 8'hd6; sbox_mem[75] = 8'hb3;
sbox_mem[76] = 8'h29; sbox_mem[77] = 8'he3; sbox_mem[78] = 8'h2f; sbox_mem[79] = 8'h84;
sbox_mem[80] = 8'h53; sbox_mem[81] = 8'hd1; sbox_mem[82] = 8'h00; sbox_mem[83] = 8'hed;
sbox_mem[84] = 8'h20; sbox_mem[85] = 8'hfc; sbox_mem[86] = 8'hb1; sbox_mem[87] = 8'h5b;
sbox_mem[88] = 8'h6a; sbox_mem[89] = 8'hcb; sbox_mem[90] = 8'hbe; sbox_mem[91] = 8'h39;
sbox_mem[92] = 8'h4a; sbox_mem[93] = 8'h4c; sbox_mem[94] = 8'h58; sbox_mem[95] = 8'hcf;
sbox_mem[96] = 8'hd0; sbox_mem[97] = 8'hef; sbox_mem[98] = 8'haa; sbox_mem[99] = 8'hfb;
sbox_mem[100] = 8'h43; sbox_mem[101] = 8'h4d; sbox_mem[102] = 8'h33; sbox_mem[103] = 8'h85;
sbox_mem[104] = 8'h45; sbox_mem[105] = 8'hf9; sbox_mem[106] = 8'h02; sbox_mem[107] = 8'h7f;
sbox_mem[108] = 8'h50; sbox_mem[109] = 8'h3c; sbox_mem[110] = 8'h9f; sbox_mem[111] = 8'ha8;
sbox_mem[112] = 8'h51; sbox_mem[113] = 8'ha3; sbox_mem[114] = 8'h40; sbox_mem[115] = 8'h8f;
sbox_mem[116] = 8'h92; sbox_mem[117] = 8'h9d; sbox_mem[118] = 8'h38; sbox_mem[119] = 8'hf5;
sbox_mem[120] = 8'hbc; sbox_mem[121] = 8'hb6; sbox_mem[122] = 8'hda; sbox_mem[123] = 8'h21;
sbox_mem[124] = 8'h10; sbox_mem[125] = 8'hff; sbox_mem[126] = 8'hf3; sbox_mem[127] = 8'hd2;
sbox_mem[128] = 8'hcd; sbox_mem[129] = 8'h0c; sbox_mem[130] = 8'h13; sbox_mem[131] = 8'hec;
sbox_mem[132] = 8'h5f; sbox_mem[133] = 8'h97; sbox_mem[134] = 8'h44; sbox_mem[135] = 8'h17;
sbox_mem[136] = 8'hc4; sbox_mem[137] = 8'ha7; sbox_mem[138] = 8'h7e; sbox_mem[139] = 8'h3d;
sbox_mem[140] = 8'h64; sbox_mem[141] = 8'h5d; sbox_mem[142] = 8'h19; sbox_mem[143] = 8'h73;
sbox_mem[144] = 8'h60; sbox_mem[145] = 8'h81; sbox_mem[146] = 8'h4f; sbox_mem[147] = 8'hdc;
sbox_mem[148] = 8'h22; sbox_mem[149] = 8'h2a; sbox_mem[150] = 8'h90; sbox_mem[151] = 8'h88;
sbox_mem[152] = 8'h46; sbox_mem[153] = 8'hee; sbox_mem[154] = 8'hb8; sbox_mem[155] = 8'h14;
sbox_mem[156] = 8'hde; sbox_mem[157] = 8'h5e; sbox_mem[158] = 8'h0b; sbox_mem[159] = 8'hdb;
sbox_mem[160] = 8'he0; sbox_mem[161] = 8'h32; sbox_mem[162] = 8'h3a; sbox_mem[163] = 8'h0a;
sbox_mem[164] = 8'h49; sbox_mem[165] = 8'h06; sbox_mem[166] = 8'h24; sbox_mem[167] = 8'h5c;
sbox_mem[168] = 8'hc2; sbox_mem[169] = 8'hd3; sbox_mem[170] = 8'hac; sbox_mem[171] = 8'h62;
sbox_mem[172] = 8'h91; sbox_mem[173] = 8'h95; sbox_mem[174] = 8'he4; sbox_mem[175] = 8'h79;
sbox_mem[176] = 8'he7; sbox_mem[177] = 8'hc8; sbox_mem[178] = 8'h37; sbox_mem[179] = 8'h6d;
sbox_mem[180] = 8'h8d; sbox_mem[181] = 8'hd5; sbox_mem[182] = 8'h4e; sbox_mem[183] = 8'ha9;
sbox_mem[184] = 8'h6c; sbox_mem[185] = 8'h56; sbox_mem[186] = 8'hf4; sbox_mem[187] = 8'hea;
sbox_mem[188] = 8'h65; sbox_mem[189] = 8'h7a; sbox_mem[190] = 8'hae; sbox_mem[191] = 8'h08;
sbox_mem[192] = 8'hba; sbox_mem[193] = 8'h78; sbox_mem[194] = 8'h25; sbox_mem[195] = 8'h2e;
sbox_mem[196] = 8'h1c; sbox_mem[197] = 8'ha6; sbox_mem[198] = 8'hb4; sbox_mem[199] = 8'hc6;
sbox_mem[200] = 8'he8; sbox_mem[201] = 8'hdd; sbox_mem[202] = 8'h74; sbox_mem[203] = 8'h1f;
sbox_mem[204] = 8'h4b; sbox_mem[205] = 8'hbd; sbox_mem[206] = 8'h8b; sbox_mem[207] = 8'h8a;
sbox_mem[208] = 8'h70; sbox_mem[209] = 8'h3e; sbox_mem[210] = 8'hb5; sbox_mem[211] = 8'h66;
sbox_mem[212] = 8'h48; sbox_mem[213] = 8'h03; sbox_mem[214] = 8'hf6; sbox_mem[215] = 8'h0e;
sbox_mem[216] = 8'h61; sbox_mem[217] = 8'h35; sbox_mem[218] = 8'h57; sbox_mem[219] = 8'hb9;
sbox_mem[220] = 8'h86; sbox_mem[221] = 8'hc1; sbox_mem[222] = 8'h1d; sbox_mem[223] = 8'h9e;
sbox_mem[224] = 8'he1; sbox_mem[225] = 8'hf8; sbox_mem[226] = 8'h98; sbox_mem[227] = 8'h11;
sbox_mem[228] = 8'h69; sbox_mem[229] = 8'hd9; sbox_mem[230] = 8'h8e; sbox_mem[231] = 8'h94;
sbox_mem[232] = 8'h9b; sbox_mem[233] = 8'h1e; sbox_mem[234] = 8'h87; sbox_mem[235] = 8'he9;
sbox_mem[236] = 8'hce; sbox_mem[237] = 8'h55; sbox_mem[238] = 8'h28; sbox_mem[239] = 8'hdf;
sbox_mem[240] = 8'h8c; sbox_mem[241] = 8'ha1; sbox_mem[242] = 8'h89; sbox_mem[243] = 8'h0d;
sbox_mem[244] = 8'hbf; sbox_mem[245] = 8'he6; sbox_mem[246] = 8'h42; sbox_mem[247] = 8'h68;
sbox_mem[248] = 8'h41; sbox_mem[249] = 8'h99; sbox_mem[250] = 8'h2d; sbox_mem[251] = 8'h0f;
sbox_mem[252] = 8'hb0; sbox_mem[253] = 8'h54; sbox_mem[254] = 8'hbb; sbox_mem[255] = 8'h16;
sbox = sbox_mem[addr];
end
endfunction
function [127:0] sub_bytes;
input [127:0] data;
integer b;
begin
for (b = 0; b < 16; b = b + 1)
sub_bytes[b*8 +: 8] = sbox(data[b*8 +: 8]);
end
endfunction
function [127:0] shift_rows;
input [127:0] data;
reg [127:0] tmp;
integer r, c;
begin
// 状态矩阵按列存储:data[127:120]=S0, data[119:112]=S1, ... data[7:0]=S15
// 行移位:第r行循环左移r字节
for (r = 0; r < 4; r = r + 1)
for (c = 0; c < 4; c = c + 1)
tmp[(r*4+c)*8 +: 8] = data[((r*4 + ((c+r)%4)))*8 +: 8];
shift_rows = tmp;
end
endfunction
function [127:0] mix_columns;
input [127:0] data;
reg [7:0] col [0:3];
reg [7:0] out_col [0:3];
integer c, i;
begin
for (c = 0; c < 4; c = c + 1) begin
for (i = 0; i < 4; i = i + 1)
col[i] = data[(c*4+i)*8 +: 8];
// 列混合矩阵乘法(GF(2^8))
out_col[0] = xtime(col[0]) ^ (xtime(col[1]) ^ col[1]) ^ col[2] ^ col[3];
out_col[1] = col[0] ^ xtime(col[1]) ^ (xtime(col[2]) ^ col[2]) ^ col[3];
out_col[2] = col[0] ^ col[1] ^ xtime(col[2]) ^ (xtime(col[3]) ^ col[3]);
out_col[3] = (xtime(col[0]) ^ col[0]) ^ col[1] ^ col[2] ^ xtime(col[3]);
for (i = 0; i < 4; i = i + 1)
mix_columns[(c*4+i)*8 +: 8] = out_col[i];
end
end
endfunction
function [7:0] xtime;
input [7:0] x;
begin
xtime = {x[6:0], 1'b0} ^ (x[7] ? 8'h1b : 8'h00);
end
endfunction
function [31:0] rot_word;
input [31:0] w;
begin
rot_word = {w[23:0], w[31:24]};
end
endfunction
function [31:0] sub_word;
input [31:0] w;
integer b;
begin
for (b = 0; b < 4; b = b + 1)
sub_word[b*8 +: 8] = sbox(w[b*8 +: 8]);
end
endfunction
endmodule
仿真测试平台
// aes128_tb.v
`timescale 1ns/1ps
module aes128_tb;
reg [127:0] pt, key;
wire [127:0] ct;
aes128_enc dut(.plaintext(pt), .key(key), .ciphertext(ct));
initial begin
// FIPS-197 附录B 标准向量
pt = 128'h00112233445566778899aabbccddeeff;
key = 128'h000102030405060708090a0b0c0d0e0f;
#10;
if (ct === 128'h69c4e0d86a7b0430d8cdb78070b4c55a)
$display("PASS: AES-128 encryption matches FIPS-197 vector");
else
$display("FAIL: got %h, expected 69c4e0d86a7b0430d8cdb78070b4c55a", ct);
$finish;
end
endmodule
运行与验证
- 仿真运行:使用Icarus Verilog执行以下命令:
iverilog -o aes128_sim aes128_enc.v aes128_tb.v
vvp aes128_sim
- 通过条件:控制台输出
PASS: AES-128 encryption matches FIPS-197 vector,且无编译错误。 - 综合验证(可选):若使用Vivado/Quartus,将
aes128_enc.v设为顶层并运行综合,确认无latch推断且资源报告正常生成。
设计说明
本实现采用组合逻辑完成全部10轮加密,密钥扩展与轮函数均为纯组合电路,因此输出 ciphertext 在输入稳定后立即有效(无时钟边沿)。S-box查找表完整实现FIPS-197附录A数值,列混合使用xtime辅助函数完成GF(2^8)乘法。测试平台使用NIST标准向量(明文 00112233445566778899aabbccddeeff,密钥 000102030405060708090a0b0c0d0e0f),预期密文为 69c4e0d86a7b0430d8cdb78070b4c55a。若需时序版本,可在顶层添加寄存器级流水,但本案例聚焦组合逻辑正确性验证。