AES-CCM 的 FPGA/Verilog 设计笔记
这份实现把 AES、CCM 认证、测试向量和仿真环境放在一套目录里,目标很明确:能跑、能测、能对结果。硬件部分以 Verilog 为主,软件侧补了嵌入式 C 参考代码,方便先把算法跑通,再去看硬件映射是否合理。
主要内容
- AES 加密、解密、密钥扩展的 Verilog 实现
- AES-CCM 128 位算法的 Verilog 实现
- AES-CCM 的嵌入式 C 语言参考代码
- AES-CCM 算法测试向量
- AES-CCM 算法自动化仿真环境(Modelsim 和 Makefile)
核心模块
1. AES 加密、解密与密钥扩展
AES 的难点不在单次轮变换本身,而在于轮密钥怎么稳定地产生出来。这里给出的密钥扩展示例是一个典型的 Verilog 写法:
module key_expansion ( input wire [127:0] key, output reg [127:0] w[0:10] );
always @(*) begin
w[0] = key;
for (int i = 1; i < 11; i = i + 1) begin
if (i % 4 == 0) begin
// 轮常量异或等操作
w[i] = w[i - 1] ^ {w[i - 4][111:0], w[i - 4][127:112]} ^ {8'h01 << (i / 4 - 1), 56'h0};
end else begin
w[i] = w[i - 1] ^ w[i - 4];
end
end
end
endmodule
这段逻辑的重点是把输入密钥拆成每轮要用的子密钥。实现上看起来不复杂,但一旦轮常量、移位和索引有偏差,后面加密结果就会整片跑偏,所以这部分通常是最先拿测试向量去对的。
2. AES-CCM 128 位算法
CCM 模式是在 AES 之上再加一层认证。加密能不能出密文是一回事,认证标签对不对又是另一回事,实际排错时往往后者更花时间。下面的示例展示了认证码计算的结构:
module ccm_auth ( input wire [127:0] block, input wire [127:0] key, output reg [127:0] auth_tag );
reg [127:0] state;
// 初始化状态
always @(*) begin
state = block;
for (int i = 0; i < 10; i = i + 1) begin
// 与子密钥异或
state = state ^ key;
// 执行 AES 轮变换操作(类似加密轮操作)
// 这里省略具体轮变换代码实现
end
auth_tag = state;
end
endmodule
这里的实现方式比较直白:先初始化状态,再按轮次与密钥混合并做轮变换。它适合先把数据通路搭起来,后续如果要做面积或时序优化,再考虑把组合逻辑拆开。
3. 嵌入式 C 语言参考代码
硬件实现之外,配一份 C 代码很有用。它不一定是最终产品代码,但对理解参数组织、调用顺序和 CCM 的附加处理很直接:
void aes_ccm_encrypt(unsigned char *plaintext, unsigned char *key, unsigned char *iv, unsigned char *ciphertext) {
// 初始化相关参数
// 调用 AES 加密函数对明文进行加密
aes_encrypt(plaintext, key, ciphertext);
// 进行 CCM 模式相关的额外操作,如计算认证码等
// 这里省略具体代码
}
这类参考实现的价值不在'完整',而在于它能帮你确认接口顺序和数据流。很多 FPGA 设计最后不是卡在密码学本身,而是卡在输入输出约定没统一。
4. 测试向量
测试向量是这类工程里最省事、也最不能省的部分。NIST 的已知输入输出能快速告诉你实现是不是已经偏了。文件格式示例如下:
text
plaintext: 00112233445566778899aabbccddeeff
key: 000102030405060708090a0b0c0d0e0f
ciphertext: 69c4e0d86a7b0430d8cdb78070b4c55a
只要把实现结果和这些样本逐项比对,就能把大多数轮函数错误、字节序问题和密钥扩展问题揪出来。对 AES 这种算法来说,越早比对越省时间。
5. 自动化仿真环境
仿真环境放在 sim 目录下,核心是 Modelsim 和 Makefile 的配合:
SIMULATION := modelsim -c -do "run -all; quit"
all: $(SIMULATION)
clean: rm -rf transcript vsim.wlf *.log
这种写法不花哨,但够用。make 直接拉起仿真,make clean 清掉中间文件,适合在调试阶段反复跑向量。对硬件工程来说,自动化仿真比手工点界面靠谱得多。
目录结构
- src:设计文件和测试激励(
*.v,*.sv) - doc:设计相关文档
- sim:Modelsim 仿真环境
- software:嵌入式软件 C 代码
- testvector:NIST 提供的测试向量
小结
这套实现的思路比较务实:先把 AES-CCM 的关键路径拆出来,Verilog、C 代码和测试向量一起配齐,再用自动化仿真去收口。它不追求把每个模块写得最漂亮,但对验证算法、定位错误、后续继续做 FPGA 化调整都够用了。


