1. 项目概述与核心价值
在嵌入式物联网设备里做安全,尤其是处理无线通信数据,AES加解密是绕不开的核心操作。但如果你试过用纯软件库在MCU上跑AES,尤其是GCM或CCM这种带认证的组合模式,就会深刻体会到什么叫“性能瓶颈”——CPU占用率飙升,实时性难以保证,功耗也跟着上去了。这正是硬件AES加速器存在的意义:它把那些复杂的轮运算、伽罗瓦域乘法等操作固化到专用电路里,让CPU从繁重的计算中解脱出来,你只需要配置几个寄存器,数据就能“流”过硬件引擎,完成高速、低功耗的加解密和认证。
我手头这个项目基于TI的SimpleLink™ CC323x系列无线MCU,它的AES模块功能相当齐全,不仅支持基础的ECB、CBC、CTR模式,更关键的是完整支持GCM和CCM这两种业界广泛使用的认证加密模式。对于做Wi-Fi、蓝牙安全传输或者需要设备身份认证的开发者来说,直接操作硬件加速器是提升系统整体性能和安全性的关键一步。这篇文章,我就结合手册和实际调试经验,带你彻底搞懂如何给这个AES硬件加速器编程,重点拆解GCM/CCM模式的配置流程和那些关键的寄存器,让你能直接上手,把理论变成跑通的代码。
2. AES硬件加速器架构与工作模式解析
2.1 模块整体工作流程
CC323x的AES加速器是一个相对独立的协处理器,它通过一组内存映射寄存器与CPU(或DMA控制器)交互。你可以把它想象成一个功能强大的“加密黑盒”。基本的工作流是这样的:首先,CPU需要对这个黑盒进行“上下文”(Context)配置,这包括设置操作模式(如GCM)、密钥、初始化向量(IV)、数据长度等。配置完成后,CPU或DMA将待处理的明文或密文数据块写入输入数据寄存器。加速器内部硬件自动执行加密、解密或认证计算,完成后将结果放入输出数据寄存器,并通过状态寄存器或中断通知CPU读取结果。
整个过程中,数据通路和上下文通路是分离的。上下文(Context)指的是那些控制加密过程本身的参数,比如密钥、IV、模式设置。而数据(Data)就是你要加密或解密的具体信息。模块为上下文和数据的输入/输出分别提供了独立的DMA请求线和中断信号,这允许非常灵活的数据搬运策略。例如,你可以用DMA连续搬运大数据流,同时仅在模式切换时才由CPU更新一次上下文,极大提高了效率。
2.2 扩展与组合操作模式深度解读
手册里提到的“扩展和组合操作模式”,是这个加速器的精华所在。基础的ECB、CBC模式是分组加密的基石,但在实际的安全通信中,我们往往需要同时保证数据的机密性(别人看不懂)和完整性/真实性(数据没被篡改,且来源可信)。这就是GCM和CCM这类“认证加密”(Authenticated Encryption)模式出场的时候。
GCM模式的全称是Galois/Counter Mode。它的设计非常巧妙,将Counter模式(CTR)用于加密,同时利用一个在伽罗瓦域上的乘法器来进行消息认证码的计算。手册里提到一个关键点:“加密、解密和认证可以并行执行”。这是因为GCM的认证部分(GHASH)主要依赖伽罗瓦域乘法,而加密部分使用AES核心。在硬件实现上,这两个单元可以一定程度上并行工作,从而提升吞吐率。另一个重要概念是AAD。AAD指的是“仅认证数据”,比如网络数据包的头信息。这部分数据需要被纳入完整性校验,但本身不需要加密。手册强调AAD必须放在需要加密的数据之前输入,这是GCM算法本身定义的顺序要求,硬件会严格按照这个顺序处理。
CCM模式的全称是Counter with CBC-MAC。它与GCM的思路不同,认证和加密都复用同一个AES加密核心,因此是顺序执行的。先进行CBC-MAC计算生成认证标签,然后再用CTR模式加密数据。它的流程更复杂一些:首先需要构造一个特殊的起始块B0(包含标志、随机数和消息长度),然后处理AAD,最后交替进行数据块的加密和认证。CCM对数据长度有更严格的格式要求,需要在初始化时通过CCM_L和CCM_M字段明确指定。
选择GCM还是CCM?从硬件加速角度看,GCM通常能提供更高的吞吐率,因为其认证部分可以并行。而CCM在资源极其受限、无法集成伽罗瓦域乘法器硬件的平台上可能更有优势。CC323x的硬件同时支持两者,给了开发者选择的空间。
2.3 三种核心操作模式:轮询、中断与DMA
硬件配置好了,怎么把数据喂进去并把结果取出来?模块提供了三种编程模型,对应不同的应用场景和复杂度。
轮询模式是最简单直接的。CPU配置好上下文后,循环读取AES_CTRL寄存器中的INPUT_READY和OUTPUT_READY状态位。当INPUT_READY为1时,写入一个数据块(16字节);当OUTPUT_READY为1时,读取一个结果块。这种方式代码简单,但CPU被完全绑死在等待状态上,效率最低,只适合处理极少量数据或用于调试。
中断模式解放了CPU。你可以使能AES_IRQENABLE寄存器中相应的中断位,比如DATA_IN和DATA_OUT。当输入缓冲区空或输出数据就绪时,硬件会产生中断,CPU在中断服务程序中进行数据搬运。这种方式CPU利用率更高,但中断频繁时开销也不小。手册里特别提到一个重要限制:“如果应用使用中断模式,每个处理完的数据块都会产生一个中断。为了支持更大的数据流,应使用AES µDMA模式。” 这意味着对于连续的数据流传输,中断模式可能并不合适。
DMA模式是处理批量数据的推荐方式。在这种模式下,数据搬运完全由DMA控制器完成,CPU几乎不参与。你需要先配置好µDMA通道,将AES模块的DATA_IN、DATA_OUT等请求映射到具体的DMA通道,然后在AES_SYSCONFIG寄存器中使能对应的DMA请求。数据开始传输后,AES硬件会和DMA控制器直接“对话”,自动完成数据块的搬入和搬出。你甚至可以配置DMA传输完成中断,只在整段数据(可能是成百上千个块)处理完毕后才通知CPU。这是性能最优的方案,尤其适合音频流、图像传输、大文件加解密等场景。
3. 关键寄存器配置详解与实战步骤
理解了架构和模式,接下来就是动手配置。所有操作都通过读写一系列32位寄存器完成。下面我挑最核心的几个寄存器,结合代码片段告诉你具体怎么设。
3.1 全局初始化与时钟使能
任何操作之前,必须确保模块上电且时钟就绪。这涉及到系统级的配置。
使能加密模块时钟:这是第一步,也是最容易忽略的一步。你需要设置应用复位和时钟管理模块中
CRYPTOCLKEN寄存器的RUNCLKEN位(物理地址0x440250B8)。通常,将其设为0表示使能运行时钟。很多驱动库的初始化函数会封装这一步,但如果你在写底层驱动,务必检查。// 示例:使能AES模块时钟 HWREG(0x440250B8) &= ~(1 << 0); // 清除RUNCLKEN位,使能时钟配置µDMA通道映射:如果你计划使用DMA模式,必须在µDMA模块的
DMA_CHMAPn寄存器中,将AES的上下文输入、上下文输出、数据输入、数据输出请求,映射到具体的DMA通道号。具体映射关系需要参考芯片的《系统指南》或数据手册。这一步是建立硬件信号连接。
3.2 核心控制寄存器:AES_CTRL
AES_CTRL寄存器是整个AES加速器的大脑,所有模式选择、参数配置都集中在这里。它的位域比较多,我们分组来看。
模式选择位域:
GCM[1:0]:设置GCM模式。00=无操作;01=GHASH(H已加载,Y0强制为0);10=GHASH(H已加载,Y0内部计算);11=自主GHASH(H和Y0均内部计算)。对于标准的GCM加密/解密,通常设置为10。CCM:置1选择CCM模式。CTR:置1选择计数器模式。注意:当启用GCM或CCM模式时,此位也必须置1,因为它们的加密部分基于CTR模式。CBCMAC、F9、F8、XTS、CFB、ICM、MODE:分别用于选择其他各种加密模式。KEY_SIZE[1:0]:设置密钥长度。01=128位;10=192位;11=256位。务必与后续加载的密钥长度匹配。DIRECTION:操作方向。0=解密;1=加密。CCM_L[2:0]和CCM_M[2:0]:仅用于CCM模式。CCM_L定义长度字段的宽度(字节数),支持的值对应关系为:编程值1对应L=2字节,3对应L=4字节,7对应L=8字节。CCM_M定义认证字段的长度,认证字段有效字节数为2*(M+1)。例如,需要8字节的认证标签,则设置CCM_M = 3。CTR_WIDTH[1:0]:设置计数器宽度。00=32位;01=64位;10=128位;11=192位。对于GCM,标准使用32位计数器(CTR_WIDTH=00)。对于CCM,需要根据CCM_L的选择来设置。
状态位:
INPUT_READY和OUTPUT_READY:只读状态位,在轮询模式下非常有用,指示输入缓冲区是否为空、输出数据是否就绪。CONTEXT_READY和SAVE_CONTEXT_READY:用于上下文管理的状态位。
一个典型的GCM加密初始化代码框架如下:
void AES_GCM_Init(uint32_t *key, uint32_t key_len, uint32_t *iv) { // 1. 停止当前任何操作,确保模块空闲(可选,通过写入AES_C_LENGTH触发新上下文) // 2. 配置AES_CTRL寄存器 uint32_t ctrl_value = 0; ctrl_value |= (0x2 << 16); // 设置GCM[1:0] = 10 (GHASH with H loaded, Y0 calculated) ctrl_value |= (1 << 6); // 设置CTR = 1 ctrl_value |= (0x0 << 7); // 设置CTR_WIDTH = 00 (32-bit counter for GCM) ctrl_value |= (0x1 << 3); // 设置KEY_SIZE = 01 (128-bit key),根据实际调整 ctrl_value |= (1 << 2); // 设置DIRECTION = 1 (加密) // 其他位保持默认0 HWREG(AES_BASE + AES_CTRL) = ctrl_value; // 3. 加载密钥到AES_KEY1_n寄存器 // 注意寄存器顺序:AES_KEY1_0是LSW,AES_KEY1_3是MSW(对于128位密钥) HWREG(AES_BASE + AES_KEY1_0) = key[0]; HWREG(AES_BASE + AES_KEY1_1) = key[1]; HWREG(AES_BASE + AES_KEY1_2) = key[2]; HWREG(AES_BASE + AES_KEY1_3) = key[3]; // 4. 加载初始化向量到AES_IV_IN_n寄存器 HWREG(AES_BASE + AES_IV_IN_0) = iv[0]; HWREG(AES_BASE + AES_IV_IN_1) = iv[1]; HWREG(AES_BASE + AES_IV_IN_2) = iv[2]; HWREG(AES_BASE + AES_IV_IN_3) = iv[3]; }3.3 数据长度与认证长度寄存器
这两个寄存器用于告诉硬件要处理多少数据。
AES_C_LENGTH_0和AES_C_LENGTH_1:这两个寄存器组成一个64位值,指定需要加密或解密的数据长度(单位:字节)。对于GCM和CCM,这个长度不包括AAD。手册特别指出,写入AES_C_LENGTH_0寄存器会触发引擎开始使用当前配置的上下文(GCM和CCM模式除外,它们由AES_AUTH_LENGTH触发)。对于基本加密模式,可以写入0表示无限长度(流模式)。数据必须按字节对齐。AES_AUTH_LENGTH:用于组合模式(GCM/CCM),指定仅认证数据的长度(单位:字节)。对于GCM,AAD长度可以很大(最大2^32-1字节)。对于CCM,AAD长度有限制(0到2^16-28字节)。关键点:对于GCM和CCM模式,写入此寄存器才会触发上下文生效并开始处理。对于XTS模式,这个寄存器的高28位(bits[31:4])可用来加载参数j(数据单元内128位块的序列号)。
配置示例(GCM模式,有AAD):
// 假设有20字节的AAD和100字节的加密数据 uint32_t auth_len = 20; uint32_t crypto_len = 100; // 先设置认证数据长度(对于GCM/CCM,此写入触发上下文生效) HWREG(AES_BASE + AES_AUTH_LENGTH) = auth_len; // 再设置加密数据长度 HWREG(AES_BASE + AES_C_LENGTH_0) = crypto_len & 0xFFFFFFFF; HWREG(AES_BASE + AES_C_LENGTH_1) = (crypto_len >> 32) & 0x1FFFFFFF; // 高29位有效3.4 数据输入输出与标签寄存器
数据交互通过一组寄存器进行:
AES_DATA_IN_0到AES_DATA_IN_3:4个32位寄存器,组成一个128位的数据输入缓冲区。CPU或DMA将待处理的明文/密文按顺序写入这些寄存器。AES_TAG_OUT_0到AES_TAG_OUT_3:4个32位寄存器,用于输出认证标签(对于GCM/CCM模式)或哈希结果。处理完成后,从这里读取认证码进行验证。
在轮询模式下,你需要检查INPUT_READY位,为1时才写入下一个数据块。写入AES_DATA_IN_0通常意味着写入一个完整的128位块(16字节),硬件会自动按顺序使用这四个寄存器。
3.5 DMA与中断控制寄存器
这是实现高效数据流的关键。
AES_SYSCONFIG:配置DMA请求使能。DMA_REQ_DATA_IN_EN、DMA_REQ_DATA_OUT_EN、DMA_REQ_CONTEXT_IN_EN、DMA_REQ_CONTEXT_OUT_EN分别使能对应通道的DMA请求。MAP_CONTEXT_OUT_ON_DATA_OUT位如果置1,会将上下文输出请求也映射到数据输出请求线上,这在某些特定流程下可以简化DMA通道管理。AES_IRQENABLE和AES_IRQSTATUS:用于中断模式。AES_IRQENABLE使能特定的中断源(数据输入就绪、数据输出就绪、上下文输入就绪、上下文输出就绪)。当事件发生时,AES_IRQSTATUS中对应的位会被置1,并在中断服务程序中清除。DTHE_AES_IM、DTHE_AES_RIS、DTHE_AES_MIS、DTHE_AES_IC:这一组寄存器是与DMA传输完成相关的中断管理寄存器,位于DMA中断控制器域。DTHE_AES_IM是中断掩码设置寄存器,DTHE_AES_RIS是原始中断状态,DTHE_AES_MIS是屏蔽后的中断状态,DTHE_AES_IC用于清除中断标志。当使用DMA模式时,通常使能Dout(数据输出完成)或Cout(上下文输出完成)中断,以便在DMA搬运完所有数据或认证标签后通知CPU。
4. GCM与CCM模式编程实战与流程拆解
理论说再多,不如一行代码。下面我以GCM加密和CCM加密为例,拆解完整的编程流程和注意事项。
4.1 GCM模式加密完整流程
假设我们要用GCM模式加密一段数据,包含AAD和加密正文。
步骤1:全局初始化
- 使能CRYPTO模块时钟(
CRYPTOCLKEN)。 - (如果使用DMA)配置µDMA通道映射。
步骤2:GCM上下文初始化
- 配置
AES_CTRL寄存器:- 设置
GCM[1:0] = 2(自主GHASH或加载H,根据需求)。 - 设置
CTR = 1。 - 设置
CTR_WIDTH = 0(32位计数器)。 - 设置
KEY_SIZE匹配你的密钥长度。 - 设置
DIRECTION = 1(加密)。 - 其他模式位保持0。
- 设置
- 将128/192/256位密钥写入
AES_KEY1_0~AES_KEY1_7(根据长度选择)。 - 将96位IV(通常12字节)写入
AES_IV_IN_0~AES_IV_IN_2。AES_IV_IN_3在GCM标准下通常为0,但硬件要求写入4个寄存器。 - 将AAD长度(字节数)写入
AES_AUTH_LENGTH寄存器。此写入操作会锁存当前上下文并准备接收AAD数据。 - 将加密数据长度(字节数)写入
AES_C_LENGTH_0和AES_C_LENGTH_1。
步骤3:输入数据与触发计算
- 输入AAD数据:由于AAD仅用于认证,你需要将AAD数据按16字节分块,依次写入
AES_DATA_IN_0~3寄存器。如果AAD长度不是16字节的倍数,最后一个块需要填充(GCM规范要求填充到128位)。硬件会自动处理这部分。 - 输入加密数据:AAD输入完毕后,紧接着输入需要加密的明文数据块,同样按16字节分块写入。对于最后的不完整块,硬件也会根据规范处理。
- 数据输入可以通过轮询
INPUT_READY、响应DATA_IN中断,或者由DMA自动完成。
步骤4:获取结果
- 获取密文:加密后的密文可以从
AES_DATA_IN_0~3寄存器读取(在解密时)?注意:这里手册描述可能容易混淆。对于输出,通常有专门的数据输出寄存器或机制。在CC323x中,加密后的数据似乎也是通过读取AES_DATA_IN_n寄存器?实际上,根据标准流程,输入寄存器用于写入明文/密文,输出结果需要通过读取输出缓冲区或等待DMA输出。需要仔细查看数据手册的“操作模式”部分,确认输出数据的获取位置。在一些实现中,输入和输出可能复用同一组寄存器,通过状态机区分。更常见的做法是,输出数据由硬件放入一个内部FIFO或输出缓冲区,并通过DATA_OUT事件通知CPU/DMA读取。因此,在编程时,应等待OUTPUT_READY置位或DATA_OUT中断/DMA请求,然后从数据输出接口读取密文。 - 获取认证标签:所有数据处理完毕后,认证标签(Tag)会生成。你需要等待
CONTEXT_OUT_READY状态或中断。然后,从AES_TAG_OUT_0~AES_TAG_OUT_3寄存器读取128位的认证标签。在GCM中,通常只使用前指定长度(如96位或128位)作为Tag。
关键细节与避坑指南:
- 顺序至关重要:必须先配置所有上下文(密钥、IV、模式),然后写入
AES_AUTH_LENGTH(对于GCM/CCM)或AES_C_LENGTH_0(对于其他模式)来触发上下文生效。之后才能开始输入数据。顺序错乱会导致硬件行为未定义或计算错误。- 数据对齐:所有数据长度必须以字节为单位。硬件不支持比特流。
- GCM IV:通常使用12字节(96位)的IV,这样计数器部分可以从0开始。如果IV不是96位,需要经过GHASH计算生成初始计数器,硬件可能在不同
GCM模式下自动处理,需参考手册确认。- 标签验证:解密时,硬件会重新计算Tag,你需要将解密后得到的Tag与传输来的Tag进行逐位比较。切勿直接比较内存,应使用恒定时间比较函数以防止时序攻击。
4.2 CCM模式加密完整流程
CCM流程与GCM类似,但有几个关键区别。
步骤1:全局初始化(同GCM)
步骤2:CCM上下文初始化
- 配置
AES_CTRL寄存器:- 设置
CCM = 1。 - 设置
CTR = 1。 - 设置
CCM_L和CCM_M。例如,对于长度字段L=4字节,认证标签M=8字节,设置CCM_L=3,CCM_M=3。 - 设置
CTR_WIDTH。CCM的计数器宽度与CCM_L相关,通常CTR_WIDTH需要设置为与CCM_L匹配的模式(可能为32位或64位),需严格遵循CCM规范。 - 设置
KEY_SIZE和DIRECTION。
- 设置
- 加载密钥到
AES_KEY1_n寄存器。 - 加载Nonce(随机数)到
AES_IV_IN_n寄存器。CCM的IV构造包含Nonce和标志位,硬件可能会根据CCM_L自动构造B0块,所以这里写入的可能是纯Nonce部分,需查证手册。 - 将AAD长度写入
AES_AUTH_LENGTH。 - 将加密数据长度写入
AES_C_LENGTH_0/1。
步骤3:输入数据与触发计算
- 输入AAD数据。
- 输入明文数据。
注意:CCM标准规定,在加密时,认证和加密是顺序进行的。但硬件加速器可能通过内部流水线优化。对于开发者而言,输入数据的顺序和方式与GCM类似,按块写入即可。硬件内部会按照CCM算法顺序执行CBC-MAC和CTR加密。
步骤4:获取结果
- 获取密文。
- 获取认证标签(从
AES_TAG_OUT_n读取)。CCM的认证标签长度由CCM_M定义,你只需要读取相应数量的字节(从MSB开始)。
CCM模式特别注意事项:
- 长度字段限制:
CCM_L和CCM_M的选择直接影响可加密数据的最大长度和认证标签长度。必须在设计协议时确定,并与通信对方保持一致。- Nonce唯一性:和GCM一样,CCM的Nonce在同一个密钥下必须唯一,否则会严重破坏安全性。
- AAD处理:CCM对AAD的处理方式与GCM不同,如果AAD长度不为0,它会被格式化成特定的块。硬件应自动完成此格式化,但你需要确保传入的AAD数据是正确的原始数据。
4.3 DMA模式配置示例
对于大数据量,强烈建议使用DMA。以下是配置DMA处理AES数据流的大致步骤(以数据输入输出为例):
配置AES模块的DMA请求:
// 在AES_SYSCONFIG寄存器中使能数据输入和输出的DMA请求 uint32_t sysconfig = HWREG(AES_BASE + AES_SYSCONFIG); sysconfig |= (1 << 5); // 使能 DMA_REQ_DATA_IN_EN sysconfig |= (1 << 6); // 使能 DMA_REQ_DATA_OUT_EN HWREG(AES_BASE + AES_SYSCONFIG) = sysconfig;配置µDMA通道:
- 将AES的
DATA_IN请求映射到一个DMA通道(例如通道X),配置该通道为外设到内存(Peripheral-to-Memory)模式,源地址为你的明文数据缓冲区,目的地址为AES_DATA_IN_0寄存器地址,并设置传输数据量。 - 将AES的
DATA_OUT请求映射到另一个DMA通道(例如通道Y),配置为内存到外设(Memory-to-Peripheral)模式,源地址为AES_DATA_IN_0(或输出缓冲区地址,需确认),目的地址为你的密文数据缓冲区,并设置传输数据量。 - 详细配置需参考CC323x的µDMA控制器手册,设置控制字、数据大小、地址增量等。
- 将AES的
配置DMA完成中断(可选):
// 在DTHE_AES_IM寄存器中使能数据输出完成中断 HWREG(DTHE_AES_BASE + DTHE_AES_IM) |= (1 << 3); // 使能Dout中断启动流程:
- 完成AES上下文初始化(配置
AES_CTRL、加载密钥、IV、设置长度)。 - 启动DMA通道X(输入)和通道Y(输出)。
- AES硬件在输入缓冲区空时拉高
DATA_IN请求,DMA响应并搬运数据;在输出数据就绪时拉高DATA_OUT请求,DMA将结果搬走。 - 所有数据传输完毕后,如果使能了中断,会进入中断服务程序进行后续处理(如验证Tag)。
- 完成AES上下文初始化(配置
5. 常见问题排查与调试心得
在实际调试AES硬件加速器时,我踩过不少坑,这里总结几个典型问题和排查思路。
问题1:数据计算不正确,输出全是0或乱码。
- 检查时钟:首先确认
CRYPTOCLKEN寄存器是否已正确配置,加密模块时钟是否使能。这是最容易被忽略的一步。 - 检查上下文加载顺序:确保严格按照“配置控制寄存器 -> 加载密钥 -> 加载IV -> 写入长度寄存器(触发)”的顺序。特别是对于GCM/CCM,
AES_AUTH_LENGTH的写入是触发上下文生效的关键。可以尝试在写入长度寄存器后,读取AES_CTRL的CONTEXT_READY位,确认上下文是否已就绪。 - 检查密钥和IV格式:确认密钥和IV的数据是按小端序还是大端序写入寄存器。CC323x通常是小端序,即密钥的第一个字节放在
AES_KEY1_0的最低8位。但最好通过一个已知向量测试来验证。 - 检查数据对齐和填充:确保数据长度是字节的整数倍。对于非16字节整数倍的数据,硬件通常会自动处理填充(如GCM的GHASH填充、CCM的格式要求),但你需要清楚你的协议层是否已经处理了填充,或者硬件处理后的结果是否符合你的预期。
问题2:DMA传输不工作,数据没有流动。
- 检查DMA通道映射:确认在µDMA的
DMA_CHMAPn寄存器中,AES的DATA_IN、DATA_OUT等请求信号是否已正确映射到你所使用的DMA通道号。映射错误是DMA不工作的常见原因。 - 检查AES_SYSCONFIG寄存器:确认
DMA_REQ_DATA_IN_EN和DMA_REQ_DATA_OUT_EN等位是否已置1。 - 检查DMA通道配置:确认DMA通道的源地址、目的地址、传输数据量、数据宽度(应为32位)配置正确。特别是目的地址,写AES输入寄存器时,地址应是
AES_DATA_IN_0的固定地址,且不应递增。 - 检查AES数据长度寄存器:
AES_C_LENGTH_0/1设置的长度必须大于0,且与DMA要传输的数据量匹配。如果长度为0,某些模式下硬件可能不会产生DMA请求。
问题3:中断无法触发。
- 嵌套检查:首先确认CPU全局中断是否使能,然后确认AES模块的中断在中断控制器中是否已使能和正确配置优先级。
- 检查AES_IRQENABLE:确保你希望触发的中断(如
DATA_OUT)对应的位已置1。 - 检查中断状态与清除:在中断服务程序中,读取
AES_IRQSTATUS寄存器确定中断源,并在处理完成后写入1清除对应的状态位。如果使用DMA完成中断,则要操作DTHE_AES_IC寄存器。 - 注意中断模式限制:手册明确提醒,中断模式对每个数据块都会产生中断,不适合大数据流。如果你需要处理连续数据,应切换到DMA模式并禁用
AES_IRQENABLE中的位。
问题4:GCM/CCM认证失败。
- 确认AAD和加密数据的顺序:AAD必须在加密数据之前输入。如果顺序颠倒,计算出的Tag肯定对不上。
- 检查长度寄存器:确认
AES_AUTH_LENGTH和AES_C_LENGTH设置的值与实际传输的字节数完全一致,包括任何协议层添加的填充。 - 检查Tag比较:使用恒定时间比较函数(如
CRYPTO_memcmp)来比较计算出的Tag和接收到的Tag,防止时序攻击。 - 验证IV/Nonce唯一性:确保每次加密使用的IV/Nonce都是唯一的。重复的IV/Nonce会完全破坏GCM/CCM的安全性。
调试建议:
- 从最简单的ECB模式开始:先用一个已知的测试向量(例如NIST发布的AES-ECB测试用例)验证基本的加解密功能。这能排除密钥加载、数据通路等基础问题。
- 善用轮询模式调试:在初始阶段,使用轮询模式可以更直观地控制每一步,观察状态位的变化,便于定位问题。
- 分步验证:对于GCM/CCM,可以先尝试不包含AAD的加密解密,验证通过后再加入AAD。
- 查阅勘误表:TI的芯片通常有芯片勘误表,里面可能会列出AES模块的已知问题或特殊操作要求,在调试陷入僵局时值得一看。
最后,硬件加速器虽然高效,但对其编程需要更严谨的态度。每一个寄存器的位、每一个数据的顺序都可能影响最终结果。务必仔细阅读数据手册和编程指南,理解每个模式下的硬件行为,并结合实际的协议要求进行开发和测试。希望这篇详细的指南能帮你绕过我当年踩过的那些坑,顺利驱动起这颗强大的安全引擎。