ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

从Verilog到ASIC:手把手实现AES加解密硬件引擎

从Verilog到ASIC:手把手实现AES加解密硬件引擎 简介本资源是一套基于Verilog HDL实现AES加解密算法的完整FPGA工程面向数字电路设计工程师、密码学实践者及高校嵌入式/信息安全方向学习者解决AES算法硬件化落地的核心需求。压缩包含146个文件总计8.58MB主体为33个.cdb编译数据库、31个.hdb层次化数据库及6个.rpt综合与时序报告辅以.qsfQuartus设置、.sof配置文件、.vRTL源码、.mif密钥/数据ROM初始化文件等关键工程文件完整覆盖从S盒查表、轮密钥生成到加解密流水线的全部模块实现。已有280人下载学习资源结构清晰包含可综合的顶层模块、各轮运算子模块、测试激励及仿真波形支持直接导入Quartus平台进行编译、仿真与FPGA烧录验证特别适合深入理解AES算法硬件映射逻辑、掌握密码IP核开发流程与优化技巧。1. 项目概述从算法到芯片的硬核之旅最近在整理硬盘翻出来一个老项目文件名就叫“AES.zip”。点开一看里面是当年用Verilog手搓的一个AES加解密模块从算法实现到仿真验证再到思考如何做成一个专用芯片ASIC的全套资料。这让我想起了很多工程师尤其是刚接触数字IC设计或FPGA的朋友可能都想过自己实现一个AES加解密引擎。这确实是个绝佳的练手项目算法标准、应用广泛、既有理论深度又有工程实践。今天我就以这个老项目为引子和大家深入聊聊如何从零开始用Verilog实现一个完整的AES加解密模块并探讨将其固化为专用芯片AES加解密芯片的核心思路与挑战。无论你是FPGA开发者、数字IC设计初学者还是对硬件安全感兴趣的朋友这篇文章都将带你走完从算法理解到硬件实现的全过程分享那些只有真正动手做过才会知道的“坑”和技巧。2. AES算法核心原理与硬件实现思路拆解2.1 AES算法不止是“黑盒”提到AESAdvanced Encryption Standard很多人第一反应是调用某个库函数传入密钥和数据得到密文或明文。但在硬件世界里我们需要把它拆解得明明白白。AES是一种对称分组密码算法核心操作在一个称为“状态State”的4x4字节矩阵上进行。对于最常见的AES-128密钥长度是128位16字节数据块也是128位。它的加密过程可以概括为多轮10轮、12轮或14轮取决于密钥长度的迭代运算每轮包含四个基本步骤字节替换SubBytes用一个固定的S盒Substitution-box对状态中的每个字节进行非线性替换。这是算法安全性的关键提供了混淆特性。行移位ShiftRows将状态矩阵的每一行进行循环左移行号不同移位数不同。这提供了扩散特性。列混合MixColumns将状态矩阵的每一列视为GF(2^8)域上的多项式与一个固定多项式进行模乘运算。这进一步加强了扩散。轮密钥加AddRoundKey将当前轮的子密钥由初始密钥通过密钥扩展算法生成与状态进行简单的按位异或XOR操作。解密过程则是这些操作的逆过程顺序也相反。硬件实现的第一个关键决策就来了我们是实现一个加密解密分离的模块还是做一个加解密一体的模块分离设计逻辑相对简单但面积可能翻倍一体设计可以复用部分电路如S盒但控制逻辑和路径选择会复杂一些。对于追求面积效率的芯片设计一体设计通常是更优选择。2.2 硬件架构选型面积、速度与功耗的权衡在Verilog中实现AES本质上是在设计一个专用的数据通路Datapath和一个控制其运作的状态机Controller。这里有几个经典的架构模式迭代架构Iterative Architecture只实现一轮或几轮运算的硬件电路通过一个状态机控制数据循环通过这个电路10/12/14次来完成整个加解密。这种方案面积最小因为硬件被复用了但速度最慢完成一次操作需要多个时钟周期。适合对面积极度敏感、吞吐率要求不高的场景。流水线架构Pipelined Architecture为每一轮运算都实例化一套完整的硬件电路级联起来。数据像流水一样依次通过每一级。这种方案吞吐率最高每个时钟周期都能输出一个结果在流水线填满后但面积最大功耗也高。适合需要高速连续加密/解密的场景如高速网络接口。部分展开架构Partially Unrolled Architecture介于两者之间。例如实现两轮或四轮的硬件然后循环使用。可以在面积和速度之间取得一个较好的平衡。在我的“AES.zip”项目中最初版本为了验证算法正确性采用了迭代架构。后来为了评估性能又改出了一个三级流水线的版本。选择哪种完全取决于你的目标。如果是学习我强烈建议从迭代架构开始它帮你最清晰地理解数据流和控制流。注意密钥扩展Key Expansion模块的设计也需要仔细考虑。它可以预先计算好所有轮密钥并存储起来消耗存储资源但速度快也可以动态地每轮计算下一个轮密钥节省存储但增加关键路径延迟。在迭代架构中动态计算可能更省面积。3. Verilog实现核心模块详解与实操3.1 顶层模块设计与接口定义让我们先搭起框架。一个典型的AES加解密模块的顶层接口可能长这样module aes_core # ( parameter KEY_WIDTH 128, // 支持128, 192, 256 parameter DECRYPT_EN 1 // 1为包含解密功能0为仅加密 ) ( input wire clk, input wire rst_n, // 控制信号 input wire start_i, // 启动信号高有效 output reg ready_o, // 模块空闲准备就绪信号 // 数据接口 input wire [KEY_WIDTH-1:0] key_i, input wire [127:0] data_i, input wire decrypt_i, // 0-加密1-解密 output reg [127:0] data_o, output reg valid_o // 输出数据有效信号 );这里定义了时钟、复位、启动、就绪、密钥、输入数据、加解密模式选择、输出数据和输出有效信号。DECRYPT_EN参数允许我们在综合时选择是否包含解密逻辑以节省面积。ready_o和valid_o是典型的握手信号用于模块间的流控。3.2 字节替换SubBytes与逆字节替换InvSubBytes的实现这是算法中最复杂的非线性部分。S盒是一个256字节的查找表。在硬件中有两种主要实现方式查找表法LUT用Verilog的case语句或初始化一个ROMreg [7:0] sbox [0:255]来实现。这是最直接、速度最快的方法但会占用较多的芯片存储资源Block RAM或LUTRAM。// 示例使用组合逻辑case实现面积大但延迟小 always (*) begin case (byte_in) 8h00: byte_out 8h63; 8h01: byte_out 8h7c; // ... 完整的256个case 8hff: byte_out 8h16; default: byte_out 8h00; endcase end组合逻辑计算法基于GF(2^8)域的仿射变换和乘法逆元计算来实现。这种方法几乎不占用存储资源完全由基本逻辑门与、或、非、异或构成但逻辑层级深延迟大并且面积也不一定比优化后的ROM小。通常只在极端缺乏存储资源或出于安全考虑防止侧信道攻击的掩码方案时使用。实操心得对于FPGA项目直接使用$readmemh初始化一个ROM是最佳实践综合工具能很好地将其映射到Block RAM上面积和速度兼顾。对于ASIC目标需要评估标准单元库中的ROM编译器生成的宏和用逻辑搭出来的面积/时序报告。在我的项目里我使用了两个独立的ROM分别存储S盒和逆S盒。为了支持加解密一体我通过一个多路选择器来选择输出。3.3 行移位ShiftRows与列混合MixColumns的硬件优化这两个步骤是线性变换用Verilog描述非常简洁。行移位就是字节位置的重新排列用Verilog的位拼接操作{}即可实现几乎是零成本。// 加密行移位 wire [127:0] state_after_shiftrows; assign state_after_shiftrows[127:120] state_in[127:120]; // Row0, no shift assign state_after_shiftrows[119:112] state_in[ 87: 80]; // Row1, shift left 1 assign state_after_shiftrows[111:104] state_in[ 47: 40]; // Row2, shift left 2 assign state_after_shiftrows[103: 96] state_in[ 7: 0]; // Row3, shift left 3 // ... 同理赋值其他字节列混合这是GF(2^8)上的矩阵乘法。虽然公式看起来复杂但因为它是一个固定矩阵我们可以将其展开为高效的异或运算。例如对于输出列的每个字节它都是输入列四个字节的特定倍数的异或和。在GF(2^8)上“乘以2”xtime有非常高效的位运算实现。// GF(2^8)上的xtime函数乘以x (即02) function [7:0] xtime; input [7:0] b; begin xtime {b[6:0], 1b0} ^ (8h1b {8{b[7]}}); end endfunction // 计算列混合中的一个输出字节 s‘_0,j (02 * s_0,j) xor (03 * s_1,j) xor s_2,j xor s_3,j // 其中 03*s (02*s) xor s wire [7:0] s0, s1, s2, s3; // 输入列的四个字节 wire [7:0] s0_2 xtime(s0); wire [7:0] s1_2 xtime(s1); wire [7:0] s1_3 s1_2 ^ s1; assign out_byte s0_2 ^ s1_3 ^ s2 ^ s3;关键技巧列混合的逆运算InvMixColumns矩阵系数不同如0x0e, 0x0b, 0x0d, 0x09计算更复杂。在加解密一体设计中如果资源紧张可以考虑不在数据通路中直接实现逆列混合而是采用一种叫做等价解密电路的技术。其核心思想是调整解密流程中轮密钥的顺序并将解密最后一轮前的步骤用加密的列混合电路来实现从而复用硬件。这能显著节省面积但增加了密钥调度电路的复杂性。3.4 密钥扩展模块的巧妙设计密钥扩展算法根据初始密钥生成每一轮需要的轮密钥。对于AES-128需要生成10个轮密钥。硬件实现上预计算存储在收到start_i信号后用一个状态机在后台计算出所有轮密钥存入一个寄存器堆或RAM中。加解密过程直接读取。优点是加解密过程快缺点是增加延迟和存储。按需动态计算在迭代架构中每轮运算时同步计算下一轮的轮密钥。这需要额外的密钥扩展逻辑与数据通路并行工作控制逻辑稍复杂但节省存储空间。我采用的是动态计算方式因为它与我的迭代架构更匹配。密钥扩展中也用到了S盒和Rcon常数。这里要注意密钥扩展的S盒与数据处理的S盒是同一个可以复用节省资源。// 密钥扩展核心部分伪代码 always (posedge clk or negedge rst_n) begin if (!rst_n) begin // 初始化 end else if (key_expand_en) begin // 计算下一轮密钥 temp previous_round_key[31:0]; // 取上一轮密钥的最后4字节 if (round % 4 0) begin // 每4轮对于128位密钥就是每轮进行一次特殊变换 temp SubWord(RotWord(temp)) ^ Rcon[round/4]; end next_round_key[127:96] previous_round_key[127:96] ^ temp; next_round_key[ 95:64] next_round_key[127:96] ^ previous_round_key[95:64]; // ... 以此类推 end end3.5 主控制状态机协调一切的“大脑”控制状态机是模块的调度中心。一个典型的状态机可能包含以下状态IDLE空闲等待启动 -KEY_EXP_INIT初始化密钥扩展 -ROUND_LOOP循环执行轮运算 -FINAL_ROUND执行最后一轮无MixColumns -OUTPUT输出结果。状态机的跳转条件基于轮计数器round counter。在ROUND_LOOP状态每完成一轮运算轮计数器加一并判断是否进入最后一轮。localparam S_IDLE 0, S_KEY_EXP 1, S_ROUND 2, S_FINAL 3, S_OUTPUT 4; reg [2:0] state, next_state; reg [3:0] round_cnt; // 记录当前轮数 always (posedge clk or negedge rst_n) begin if (!rst_n) state S_IDLE; else state next_state; end always (*) begin next_state state; case (state) S_IDLE: if (start_i) next_state S_KEY_EXP; S_KEY_EXP: next_state S_ROUND; // 密钥扩展完成 S_ROUND: if (round_cnt 9) next_state S_FINAL; // AES-128第9轮后进入最终轮 else next_state S_ROUND; S_FINAL: next_state S_OUTPUT; S_OUTPUT: next_state S_IDLE; default: next_state S_IDLE; endcase end // 轮计数器控制 always (posedge clk or negedge rst_n) begin if (!rst_n) round_cnt 0; else if (state S_ROUND) round_cnt round_cnt 1; else if (state S_IDLE) round_cnt 0; end这个状态机确保了数据通路和密钥扩展模块在正确的时序下协同工作。4. 仿真验证与FPGA原型测试4.1 搭建完备的Testbench写Verilog代码一半是设计另一半是验证。一个健壮的Testbench至关重要。黄金模型Golden Model使用高级语言如Python、C、SystemVerilog编写一个行为级的AES加解密模型。这个模型将作为判断你的RTL设计是否正确的标准。// SystemVerilog Testbench 示例片段 import aes_ref_model_pkg::*; // 假设有一个包含参考函数的包 task automatic test_single_transaction(input bit decrypt, input [127:0] key, data); bit [127:0] ref_result, rtl_result; // 调用参考模型 if (decrypt) ref_result aes_decrypt(data, key); else ref_result aes_encrypt(data, key); // 驱动DUT (posedge clk); start_i 1; key_i key; data_i data; decrypt_i decrypt; (posedge clk); start_i 0; // 等待结果 wait(valid_o 1); rtl_result data_o; // 比较 if (ref_result ! rtl_result) $error(Mismatch!); else $display(Test passed.); endtask随机化测试不仅仅测试标准向量如NIST提供的测试向量还要进行大量的随机测试。使用SystemVerilog的约束随机化功能随机生成密钥和明文/密文进行成千上万次测试以覆盖更多角落情况。覆盖率收集使用仿真工具如VCS、ModelSim/QuestaSim的覆盖率功能收集代码覆盖率Code Coverage、条件覆盖率Condition Coverage和有限状态机覆盖率FSM Coverage。确保你的测试激励触发了所有代码分支和状态转移。4.2 FPGA原型验证与调试将设计综合到FPGA如Xilinx的Artix-7或Intel的Cyclone IV进行上板测试是检验设计是否真正可用的最后一步。时序约束必须为你的设计添加正确的时序约束.xdc或.sdc文件特别是时钟频率。AES运算的组合逻辑路径可能较长尤其是列混合和S盒如果时钟频率设得过高会导致建立时间Setup Time违例。# 示例 XDC 约束 create_clock -name clk -period 10.0 [get_ports clk] # 100MHz时钟 set_input_delay -clock clk 2.0 [get_ports {key_i[*] data_i[*] start_i decrypt_i}] set_output_delay -clock clk 2.0 [get_ports {data_o[*] valid_o ready_o}]片上逻辑分析仪利用FPGA厂商提供的调试工具如Xilinx的ILAIntegrated Logic Analyzer或Intel的SignalTap。将内部关键信号如状态机状态state、轮计数器round_cnt、中间状态state_reg抓取出来与仿真波形对比是定位硬件实际运行问题的最有效手段。与软核处理器联动一个更实际的测试场景是将AES模块作为外设挂载到一个软核CPU如MicroBlaze或Nios II的总线上。通过CPU编写测试程序从内存读取数据启动AES模块再读回结果。这验证了模块在实际系统中的集成能力。踩坑实录我曾遇到一个棘手的bug在仿真中完全正确但上板后结果偶尔错误。最后用ILA抓波形发现是ready_o信号在模块还在计算时就被意外置高了导致主控制器过早地发来了下一组数据造成数据覆盖。原因是状态机从OUTPUT跳回IDLE的逻辑条件在极端时序下产生了毛刺。解决办法是在状态跳转判断和ready_o赋值逻辑中插入寄存器打拍消除毛刺影响。5. 迈向AES加解密芯片ASIC实现考量如果目标不是FPGA而是一颗真正的专用集成电路ASIC那么考虑的问题要深入得多。5.1 从RTL到GDSII完整后端流程概览逻辑综合使用Design Compiler等工具将你的Verilog RTL代码在特定的工艺库如TSMC 28nm约束下映射成由基本逻辑门与门、或门、触发器组成的网表。你需要精心优化时序约束、面积约束和功耗约束。形式验证在综合后、布局布线后都要用Formality等工具进行等价性检查LEC确保网表功能与原始RTL一致。布局布线使用IC Compiler、Innovus等工具将网表中的单元在芯片平面上进行物理排列布局并用金属线连接起来布线。这里要解决时钟树综合CTS、电源规划、信号完整性等问题。静态时序分析在布局布线后进行更精确的时序分析考虑线延迟、时钟偏移等确保在所有工艺角CornerTT/FF/SS和温度电压条件下都能满足时序要求。物理验证检查设计规则DRC和电路图与版图一致性LVS确保芯片可以正确制造。5.2 针对AES设计的特殊优化与挑战安全性与侧信道攻击防护真正的加密芯片必须考虑安全性。简单的功耗分析SPA和差分功耗分析DPA可以通过监测芯片的功耗轨迹来推测密钥。防护手段包括掩码在算法执行过程中将中间数据与随机数进行异或扰乱功耗与真实数据的关联。隐藏通过随机插入空操作或调整操作顺序使功耗轨迹变得平坦。双轨预充电逻辑使用特殊的电路设计风格使无论处理0还是1功耗都恒定。 这些防护措施会显著增加设计的复杂性和面积开销。面积优化对于ASIC面积就是成本。需要极致优化复用策略加解密电路复用、S盒复用。使用工艺库中的专用元件有些工艺库提供面积小、速度快的ROM编译器比用逻辑门搭的S盒更优。数据通路位宽仔细评估是否可以用更小的位宽进行迭代如32位但这会增加控制复杂度。时钟门控在模块空闲时通过时钟门控单元关闭时钟大幅降低动态功耗。这是ASIC低功耗设计的基本功。可测性设计插入扫描链Scan Chain以便在芯片制造后进行自动化测试筛选出故障芯片。5.3 系统集成与接口一个独立的AES加解密芯片通常不会只有裸的算法引擎。它还需要标准总线接口如AHB、APB、AXI以便嵌入到SoC系统中被处理器控制。DMA控制器用于高效搬移大批量数据减轻CPU负担。密钥管理单元安全地存储和管理密钥可能包括密钥注入接口、密钥销毁机制等。真随机数发生器用于生成掩码和初始化向量。6. 常见问题、调试技巧与性能评估6.1 开发与调试中的典型问题问题现象可能原因排查思路与解决方法仿真结果与软件模型对不上1. S盒/逆S盒数据错误。2. 行移位方向弄反加密左移解密右移。3. 列混合系数或计算错误。4. 轮密钥加的顺序或值错误。1.逐轮比对在Testbench中打印出每一轮开始和结束时的状态值、轮密钥值与黄金模型逐轮对比定位首次出错的位置。2.检查边界特别注意第一轮和最后一轮的处理以及密钥扩展的第一轮。上板后功能不稳定偶尔出错1. 时序违例Setup/Hold violation。2. 跨时钟域问题如果接口异步。3. 复位信号毛刺或异步释放。4. 状态机被意外触发。1.静态时序分析检查综合和布局布线后的时序报告看是否有违例路径。2.降低时钟频率测试如果问题消失基本是时序问题。3.使用ILA/SignalTap抓取关键控制信号如start_i, ready_o, valid_o, state和数据信号观察出错时刻的波形。资源占用过高FPGA1. S盒使用了分布式RAMLUT而非Block RAM。2. 不必要的寄存器复制或逻辑冗余。3. 选择了面积大的实现方式如全流水线。1.检查综合推断确保S盒数组被正确推断为Block RAM查看综合报告。可尝试使用(* ram_style block *)等属性引导工具。2.资源共享检查加解密电路是否可进一步复用。3.更换架构如果吞吐率要求不高考虑改用迭代架构。吞吐率不达标1. 时钟频率过低。2. 架构瓶颈如迭代架构本身慢。3. 接口握手效率低模块空闲周期多。1.优化关键路径通过流水线打拍、重定时等方法提高系统可运行的最高时钟频率。2.架构升级评估改用部分展开或全流水线架构。3.优化接口实现背压机制确保上游能在ready_o有效时持续提供数据。6.2 性能评估指标当你完成一个设计后如何评价它的优劣需要从多个维度衡量吞吐率单位时间内处理的数据量通常用 Mbps 或 Gbps 表示。吞吐率 (数据块大小 * 时钟频率) / 处理所需时钟周期数。对于迭代架构N轮需N1个周期吞吐率较低对于K级流水线在流水线填满后可接近每个周期输出一块数据吞吐率很高。面积在FPGA上体现为LUT、FF、BRAM的使用数量在ASIC上体现为等效门数或平方微米。面积直接关系到成本。功耗分为静态功耗和动态功耗。动态功耗与时钟频率、数据翻转率、电压平方成正比。低功耗设计至关重要。最大时钟频率由最长的组合逻辑路径关键路径决定。这限制了吞吐率的上限。延迟从输入数据有效到输出数据有效所经历的时钟周期数。对于交互式应用低延迟很重要。以一个迭代架构的AES-128设计为例假设时钟频率为100MHz处理一个128位数据块需要11个周期1轮初始化10轮运算则 吞吐率 (128 bit * 100 MHz) / 11 cycles ≈ 1.16 Gbps。 面积可能只有几千个LUTs。 而一个10级全流水线的设计在100MHz下吞吐率可达 128 bit * 100 MHz 12.8 Gbps但面积可能是迭代架构的8-10倍。选择哪种设计没有绝对答案完全取决于你的应用场景是在物联网终端面积功耗优先还是在数据中心网卡吞吐率优先。最后这个“AES.zip”项目给我的最大体会是硬件设计永远是在各种约束下的艺术性折衷。从行为建模到RTL实现从仿真验证到上板调试再到思考ASIC实现的种种细节每一步都充满了挑战和乐趣。当你看到自己编写的代码在示波器或逻辑分析仪上稳定地跑出加密波形并与标准结果严丝合缝地对上时那种成就感是无与伦比的。希望这篇长文能为你点亮自己动手实现硬件AES的道路至少下次当你再看到一个“AES.zip”时能会心一笑知道里面藏着怎样一个精彩的世界。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进