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);
}

