1. 项目概述:深入AES硬件加速器的认证加密模式

在嵌入式安全系统的开发中,尤其是涉及物联网网关、车联网T-Box或工业控制设备时,数据在传输与存储过程中的机密性与完整性是必须保障的双重目标。单纯加密可以防止窃听,但无法阻止数据被篡改;单纯认证可以验证完整性,但数据本身是明文。因此,结合了加密与认证的“认证加密”(Authenticated Encryption)模式,如CCM和GCM,成为了构建安全通信链路的基石。然而,在资源受限的嵌入式环境中,完全依靠软件实现这些复杂的算法模式,其性能开销往往是不可接受的,这会直接导致系统响应延迟增加、功耗上升。

这时,AES硬件加速器(AESA)的价值就凸显出来了。它并非一个简单的AES加密/解密黑盒,而是一个高度可配置、支持多种工作模式与数据流管理的协处理器。以NXP QorIQ LS1046A等系列处理器集成的安全引擎(SEC)为例,其AESA模块对CCM、GCM以及为特定协议优化的CBC-XCBC、CTR-CMAC等模式提供了完整的硬件支持。这意味着,开发者可以通过配置一系列寄存器,将复杂的认证加密计算任务卸载给硬件,CPU得以解放出来处理业务逻辑,从而在系统层面实现高性能、低延迟的安全数据处理。

但是,将理论上的硬件加速转化为稳定可靠的实践,中间隔着一条名为“正确配置”的鸿沟。芯片手册中的寄存器描述往往分散且充满前提条件,一个配置位的疏忽就可能导致整个安全流程失效,或者更隐蔽地,产生看似正常实则不安全的结果。本文的目的,就是结合手册中的核心要点与工程实践,为你拆解AESA在CCM、GCM及优化模式下的工作原理、寄存器配置逻辑以及多会话处理中的关键陷阱。无论你是在为设备设计安全启动流程,还是实现一个高效的IPsec VPN通道,理解这些细节都将帮助你真正驾驭硬件加速能力,而非被其复杂性所困扰。

2. 核心模式解析:CCM与GCM的硬件实现逻辑

在开始配置寄存器之前,我们必须先理解AESA硬件是如何看待和处理CCM与GCM这两种模式的。这不仅仅是算法理论,更是硬件数据流和控制状态的体现。

2.1 CCM模式:计数器与CBC-MAC的硬件耦合

CCM模式本质上是CTR(计数器)模式加密与CBC-MAC认证模式的组合。软件实现时,我们通常先计算MAC,再加密数据。但AESA的硬件设计为了提升吞吐量和降低延迟,采用了一种交织处理的流水线方式。理解这一点对正确配置上下文(Context)至关重要。

核心流程与硬件职责划分:

  1. 初始化阶段 :当算法状态(AS)设置为 Initialize Initialize/Finalize 时,硬件要求Context寄存器必须清零。这不是一个建议,而是一个强制要求,因为硬件依赖干净的上下文来存储中间状态。此时,你需要向Context的DWord 0-3提供B0(关联数据与载荷的格式块)和初始计数器CTR0。硬件会并行执行两个操作:用CTR模式加密CTR0(结果暂存),以及用CBC-MAC模式处理B0(作为初始向量)。这两个结果会被写回Context的特定位置,为后续数据块处理做好准备。
  2. 数据处理阶段 :在 Update 状态下,数据通过输入FIFO源源不断地送入AESA。硬件内部实际上有两条并行的流水线:一条用于CTR模式加密/解密数据,另一条用于CBC-MAC计算认证标签。对于每一个16字节的数据块,CTR流水线使用递增的计数器生成密钥流,与数据异或;同时,该数据(加密前或解密后的明文,取决于ENC位)被送入CBC-MAC流水线进行迭代计算。
  3. 终结与验证阶段 :在 Finalize Initialize/Finalize 状态下,硬件完成最后一个数据块的处理,并生成最终的MAC值。对于加密操作,硬件会使用之前加密好的CTR0(存储在Context中)对最终MAC进行加密,得到ICV(完整性校验值),并输出。对于解密操作,硬件会从输入FIFO读取接收到的ICV(它始终是加密状态的),用密钥解密它,然后与本地计算出的MAC(明文)进行比较。如果 ICV_TEST 位被置位,这个比较由硬件自动完成,不匹配则产生错误中断。

关键陷阱:数据对齐与分割 手册中明确强调: “消息分割只能在16字节边界上进行” 。这意味着,如果你需要通过多个描述符(会话)来处理一段很长的数据,那么每个描述符所负责的数据长度,必须是16字节的整数倍(最后一个描述符除外,但最后一个描述符的 Data Size 写入后,总长度仍需是16字节的整数倍)。如果你试图在非16字节边界处拆分数据流,将会触发 data-size error 。这在设计DMA描述符链或软件分片逻辑时,是首要的约束条件。

2.2 GCM模式:GHASH与CTR的伽罗瓦域之舞

GCM模式同样结合了CTR加密和GMAC认证,但其认证部分基于伽罗瓦域乘法(GHASH),而非CBC-MAC。AESA对GCM的支持更为“自动化”,但代价是上下文管理和数据提交顺序有严格的规则。

硬件数据流与上下文管理: 与CCM需要显式提供B0不同,GCM的初始化完全由输入数据驱动。你需要按照 严格的顺序 向输入FIFO提交数据,并标记好数据类型:

  1. IV数据 :首先提交初始化向量。如果IV长度恰好是12字节,硬件会直接将其扩展为计数器Y0;否则,IV会先经过GHASH函数处理得到Y0。这个过程在 IV 数据类型的数据全部提交完成后完成。
  2. AAD数据 :接着提交附加认证数据。这部分数据只认证不加密。
  3. 明文/密文数据 :最后提交主要的载荷数据。

上下文的动态性 :在GCM模式下,一个全新的消息开始时,Context寄存器可以不需要任何初始数据(清零即可)。但是,在 多会话处理 中,这是最易出错的地方。硬件在处理每个数据块后,会动态更新Context中的多个状态:

  • DWord 0-1 :不断更新的中间MAC值。
  • DWord 2-3 :当前递增的计数器值 Yi
  • DWord 4-5 :计算出的初始计数器 Y0
  • DWord 6-7 :累计的IV、AAD、文本数据的 比特长度 (注意是比特,不是字节)。

这意味着,在进行下一个会话(描述符)的处理前,你必须将上一个会话结束时硬件写回的整个Context内容,原封不动地恢复(Restore)到Context寄存器组中。 如果忘记恢复,或者恢复的内容有误,GHASH的计算链就会断裂,导致最终的MAC值完全错误,且无法通过ICV校验。这个“保存-恢复”上下文的过程,是多会话GCM操作中的生命线。

2.3 模式寄存器(Mode Register)配置精要

模式寄存器是控制AESA行为的“大脑”。对于CCM和GCM,有几个位域需要特别关注:

  1. 算法(ALG)字段 :必须设置为 10h 来激活AESA。这是前提。
  2. 附加算法信息(AAI)字段
    • CCM模式:设置为 80h
    • GCM模式:设置为 90h
    • 这个字段是模式选择的直接开关,设错会导致硬件工作在完全不同的模式,结果自然错误。
  3. 算法状态(AS)字段 :这是多会话处理的核心。
    • Update (0h) :处理中间会话的数据。既不初始化也不终结。
    • Initialize (1h) 仅用于GCM 。表示当前会话将完成某个数据类型的最终GHASH步骤(例如,处理IV的最后一部分),但还不计算最终MAC。在CCM中, Initialize 有不同含义。
    • Finalize (2h) :单会话处理的终结,计算MAC。
    • Initialize/Finalize (3h) :多会话处理中最后一个会话,完成处理并计算MAC。
  4. ICV_TEST位与ENC位的互锁
    • 这是一个非常重要的安全约束: ICV_TEST=1 (启用ICV校验)时, ENC 位必须为0(即解密模式) 。这是因为ICV校验发生在解密侧,用于验证接收到的数据的完整性和真实性。在加密侧,你生成ICV;在解密侧,你验证ICV。硬件强制要求 ICV_TEST 仅在解密时启用,防止配置错误。
    • 例外情况是“仅ICV检查”任务(CICV-only job),此时 AS=Update Data Size=0 ICV_TEST=1 。这用于在数据已处理完毕后,单独提交并校验接收到的ICV。

3. 关键寄存器配置与数据流管理

理解了模式逻辑后,我们来看如何通过寄存器与硬件“对话”。配置错误是绝大多数驱动BUG的根源。

3.1 Context寄存器:会话状态的快照

Context寄存器组是AESA硬件在会话间保持连续性的唯一纽带。它不是用来存放输入参数的,而是硬件工作状态的“暂存区”。

CCM模式下的Context布局(以加密为例):

Context DWord 初始输入定义 中间/上下文切换定义 最终输出定义
0 B0[127:64] 中间MAC状态 MAC[127:64]
1 B0[63:0] 中间MAC状态 MAC[63:0]
2 CTR0[127:64] CTR[127:64] -
3 CTR0[63:0] CTR[63:0] -
4 - E(CTR0)[127:64] E(MAC)[127:64]
5 - E(CTR0)[63:0] E(MAC)[63:0]
6 - AAD大小, MAC大小 -

操作要点:

  • 初始化 :在第一个会话(AS=Initialize/Finalize)开始前,软件需填充DWord 0-3(B0和CTR0)。
  • 会话切换 :如果一个消息被分割到多个会话处理,在启动 第二个及以后的会话 前,软件必须将上一个会话完成后硬件写回的Context(DWord 0-6)全部恢复。特别是DWord 4-5中加密的CTR0和DWord 6中的大小信息,它们是后续计算的基础。
  • 结果获取 :最终会话完成后,加密的ICV从DWord 4-5读取,明文的MAC从DWord 0-1读取(用于调试或特定协议)。

GCM模式下的Context管理: GCM的Context在会话间完全由硬件维护和更新。软件的角色是:

  1. 第一个会话:提供清零的Context(可选,硬件不依赖初始值)。
  2. 后续会话: 必须 将前一会话输出的Context完整恢复。
  3. 特别关注DWord 6-7:它们累积的是 比特长度 。例如,你处理了32字节的AAD,那么DWord 6的高32位会增加 32 * 8 = 256 。硬件依赖这个精确的比特长度来完成GHASH。如果你在恢复上下文时弄错了这个值,认证必然失败。

3.2 Data Size寄存器:不仅仅是长度

Data Size寄存器的作用比看起来更主动。

  1. 启动信号 :对该寄存器的 第一次写入 ,会触发硬件开始处理当前描述符的数据。即使FIFO中已有数据,在Data Size写入前,硬件处于等待状态。
  2. 累积性 :在单个描述符处理过程中,可以多次写入Data Size寄存器。硬件会将新写入的值与当前值 累加 。这为动态生成数据流(例如,来自网络包)提供了灵活性。
  3. 递减计数器 :硬件每处理一个16字节块,就将该寄存器值减16。你可以通过读取此寄存器来粗略估计处理进度。
  4. 边界检查 :如前所述,对于CCM和优化模式,在 AS=Update Initialize 时,最后一次写入后的Data Size值必须是16的倍数,否则报错。GCM要求消息分割在16字节边界。

3.3 密钥、IV大小与ICV大小寄存器

  • 密钥寄存器与密钥大小 :密钥必须是加密密钥。密钥大小寄存器只能写入16、24或32(对应AES-128, AES-192, AES-256),其他值立即触发错误。在多会话中,如果使用 DK (解密密钥)位来避免重复的密钥扩展,则需要确保恢复的是扩展后的轮密钥。
  • IV大小寄存器(GCM) :仅用于GCM模式。你写入的是 最后一个IV块的字节数 (如果IV总长就是最后一个块,则写入总长,但只有低4位有效)。例如,IV长度为18字节,那么它被填充为32字节(2个块),最后一个块有2个有效字节。此时应写入 2 。硬件结合Data Size中填充后的IV总长和此寄存器中的最后块有效字节数,计算出准确的IV比特长度。
  • AAD大小寄存器(GCM与优化模式) :与IV大小寄存器类似,记录最后一个AAD块的有效字节数。在优化模式中,它用于指示认证头(如24字节头)或可选尾部(4字节ESN)的大小。
  • ICV大小寄存器 :指定MAC/ICV的字节长度(4-16)。如果期望的MAC不是16字节(例如,某些协议使用12字节的MAC),必须在此寄存器中设置。如果设置为0,则默认为16字节。 接收到的ICV长度必须与此处设置的长度一致

4. 优化模式实战:为特定协议而生

AESA的优化模式(CBC-XCBC, CTR-XCBC, CBC-CMAC, CTR-CMAC, CTR-CMAC-LTE)不是标准的AES模式,而是硬件为高效实现特定网络协议(如IPsec ESP)而设计的组合模式。它们的特点是在同一硬件流水线中,同时对数据执行加密(CBC或CTR)和认证(XCBC-MAC或CMAC)。

4.1 模式选择与AAI配置

优化模式通过Mode Register中的AAI字段低8位来选择:

AAI值 优化模式名称 加密模式 认证模式 典型应用
0A0h CBC-XCBC CBC XCBC-MAC IPsec ESP
0B0h CTR-XCBC CTR XCBC-MAC IPsec ESP
0C0h CBC-CMAC CBC CMAC IPsec ESP
0D0h CTR-CMAC CTR CMAC IPsec ESP
0E0h CTR-CMAC-LTE CTR CMAC LTE PDCP控制面

选择哪种模式,取决于你所实现的协议规范。例如,IPsec ESP协议早期使用CBC+XCBC,后来更常用CTR+CMAC(即AES-GCM流行之前的方式)。CTR-CMAC-LTE则是为LTE协议栈中的PDCP层控制面消息认证加密量身定做的。

4.2 多会话处理的数据分割与AS字段设置

优化模式的多会话处理逻辑比CCM/GCM更复杂,因为它涉及到固定大小的认证头、可选的认证尾(ESN),以及加密载荷的分割。手册中的表11-110是至关重要的“食谱”。

以一个典型的IPsec ESP数据包(使用CTR-CMAC模式)的多会话处理为例: 假设我们有一个数据包,包含16字节的认证头、不定长的加密载荷,以及可选的4字节ESN尾部。

  • 会话 1.2 (Header-only)

    • 场景 :我们首先只处理认证头。
    • AS字段 :设置为 1 (Initialize) 或 0 (Update)。如果这是该消息的第一个描述符,用 1 来初始化CMAC的派生密钥L;如果不是第一个,用 0
    • AAD Size :设置为 16 (认证头长度)。
    • Data Size :设置为 16 (认证头按16字节对齐处理)。
    • 操作 :硬件处理认证头,计算中间MAC,并计算/保存密钥派生值L到Context。
  • 会话 2.1 (Message-only)

    • 场景 :接着处理一个或多个完整的16字节加密数据块。
    • AS字段 :设置为 0 (Update)。
    • AAD Size :设置为 0
    • Data Size :设置为 16 * N (N为块数)。
    • 操作 :硬件同时用CTR模式加密数据,并用CMAC认证加密后的密文。Context中的L被用来实时计算所需的K1或K2密钥。
  • 会话 2.2 (Final message and ESN)

    • 场景 :处理最后一部分数据(可能不是16字节的倍数)和4字节的ESN。
    • AS字段 :设置为 2 (Finalize)。
    • ICV字段 :如果这是解密侧并需要验证ICV,则设置为 1 ;加密侧为 0
    • AAD Size :设置为 4 (ESN长度)。
    • Data Size :设置为最后一部分数据的字节长度(需按4字节对齐)。
    • 操作 :硬件完成最后数据的加密和认证,处理ESN,并计算最终MAC。如果ICV=1,则从FIFO读取接收到的ICV进行比较。

关键约束

  • 数据分割边界 :CTR-XCBC和CTR-CMAC要求数据分割在 16字节边界 。CBC-XCBC和CBC-CMAC要求第一个会话必须处理完整个认证头(24字节) 且至少16字节的CBC数据 ,之后才能在16字节边界分割。
  • AS=1的唯一性 :在整个消息的多会话处理中, 最多只能有一个会话的AS字段包含 Initialize (值为1) 。这个会话负责计算并保存密钥派生值(L或K2/K3)。
  • Context的保存与恢复 :与GCM类似,优化模式在会话间也需要保存和恢复完整的Context。特别是Context DWord 6-7,在CBC模式下用于保存上一个会话最后一个加密块的部分数据(因为认证边界与加密边界可能不对齐),在CTR-CMAC-LTE中用于保存9字节的头信息。

4.3 CTR-CMAC-LTE模式的特殊之处

此模式专为LTE PDCP控制面设计,其数据格式固定:先是 9字节的仅认证头 ,后面跟着任意长度的既认证又加密的数据。

  • 9字节头处理 :这个头必须作为一个整体进行CMAC认证。由于AESA以16字节块工作,9字节头需要特殊处理。在Data Size寄存器中,你需要为这9字节头写入 16 (因为硬件会按16字节块取数据),同时在AAD Size寄存器中写入 9 ,告诉硬件实际有效长度。
  • 上下文连续性 :如果当前会话只提供了9字节头,但后续加密数据在下一个会话,那么这个9字节头会被保存在Context DWord 6-7中,等待下一个会话的数据到来后才能完成其CMAC计算。Context DWord 7中的一个“数据延续标志位”由硬件自动管理,用于指示这种情况。
  • 不支持纯ICV检查 :手册明确指出, Data Size = 0 的“仅ICV检查”会话不支持CTR-CMAC-LTE模式。

5. 常见问题与调试技巧实录

在实际驱动开发中,你几乎一定会遇到以下问题。这里记录了我的排查思路和解决方法。

5.1 ICV校验失败

这是最常见的问题,现象是解密侧硬件报ICV错误。

  1. 第一步:检查密钥和IV 。确认加密端和解密端使用的密钥、IV(或CCM的B0/CTR0,GCM的IV)完全一致。一个字节的错误都会导致整个MAC计算链失效。
  2. 第二步:检查数据顺序和类型(针对GCM) 。确认输入FIFO的数据提交顺序严格为:IV -> AAD -> Text Data -> ICV(解密侧)。并且每个数据段写入FIFO时,其对应的“数据类型”标志位(IV, AAD, MSG, ICV)必须正确设置。顺序错或类型错是GCM失败的典型原因。
  3. 第三步:检查上下文(Context)保存与恢复(多会话) 。这是多会话处理中最容易出错的地方。确保在启动第二个及以后的会话描述符前,将上一个会话完成后硬件输出的Context寄存器组 全部、准确 地写回到AESA的Context寄存器中。使用调试器或打印日志,对比会话前后的Context值。
  4. 第四步:检查数据长度和填充
    • CCM :确认 Data Size 寄存器最终写入的总字节长度是正确的,且符合16字节对齐要求(最后一个会话除外,但总和要对齐)。
    • GCM :确认 IV Size AAD Size 寄存器设置的是最后一个块的 有效字节数 ,而不是总长度。确认Data Size中写入的是填充到16字节边界后的长度。
    • 通用 :检查是否有任何数据在传输或处理过程中被意外修改或截断。
  5. 第五步:检查模式寄存器配置
    • 确认 AAI 字段设置正确(CCM:80h, GCM:90h, 优化模式见上表)。
    • 确认 ICV_TEST ENC 位的组合符合规则(ICV_TEST=1时,ENC必须=0)。
    • 确认 AS 字段的设置符合多会话处理的状态机(参考表11-110)。

5.2 硬件报“非法模式错误”(Illegal Mode Error)

  1. 检查AS与ICV_TEST的组合 :当 ICV_TEST=1 时, AS 字段必须为 Finalize (2h) Initialize/Finalize (3h) 。唯一的例外是“仅ICV检查”任务( AS=Update , Data Size=0 )。如果配置不对,立即报错。
  2. 检查DK位 :在CCM、GCM和所有CTR基础的优化模式中,设置 DK (解密密钥)位会导致非法模式错误。 DK 位仅用于CBC基础优化模式的解密侧,以使用预扩展的密钥。
  3. 检查算法激活 :确认 ALG 字段已设置为 10h 来激活AESA。

5.3 硬件报“数据大小错误”(Data Size Error)

  1. 检查16字节边界 :对于CCM和所有优化模式,在 AS=Update Initialize 时,最后一次写入 Data Size 寄存器后,其值必须是16的倍数。确保你的数据分割逻辑遵守此规则。
  2. 检查CTR-XCBC/CTR-CMAC的最终对齐 :对于这两种模式,整个消息处理完成后, Data Size 寄存器的最终值(即所有数据的总长度)必须是 4字节的倍数
  3. 检查CMAC模式初始化/更新的数据大小 :对于所有基于CMAC的优化模式,当 AS=Initialize Update 时, Data Size 值必须能被16整除。
  4. 检查CBC模式初始化时的数据大小 :对于CBC-XCBC和CBC-CMAC,如果 AS 字段的 Initialize 位被置位, Data Size 值不能为0。这是为了强制要求第一个会话必须处理认证头和至少一些CBC数据。

5.4 多会话处理中认证结果不一致

  1. 上下文污染 :确保在开始一个新的、独立的消息处理之前, 显式地将所有Context寄存器清零 。上一个消息残留的上下文状态会污染新消息的计算。手册特别强调,在 AS=Initialize 时,Context必须为零。
  2. 会话状态机跳转错误 :严格按照手册表11-110的会话来组织你的描述符链。不要跳过必要的初始化会话,也不要在一个消息中重复使用 AS=1 的会话。
  3. AAD Size寄存器写入时机 :手册强调,AAD Size寄存器必须在最后一次写入Data Size寄存器 之前 写入。如果顺序颠倒,硬件可能使用了错误的AAD长度信息。

调试建议

  • 从单会话开始 :在调试任何模式时,首先让整个消息在一个会话( AS=Initialize/Finalize )中完成。成功后再拆分成多会话。
  • 使用已知答案测试向量 :NXP通常会提供测试套件或已知的输入/输出向量。用最简单的数据(如全零数据)和已知的密钥/IV,先验证单会话是否正确。
  • 逐步增加复杂度 :单会话成功后,尝试拆分成两个会话(如,一个头会话,一个数据会话)。仔细比对多会话结果与单会话结果是否一致。
  • 善用仿真器和调试器 :如果可能,在仿真环境中单步跟踪AESA寄存器的变化,观察Context、Data Size等寄存器的值如何随每个操作改变。这比在黑盒中猜测要高效得多。
  • 打印关键寄存器快照 :在驱动代码中,在每个会话开始和结束时,打印出Mode Register、Context关键DWord、Data Size等寄存器的值。对比预期值和实际值,能快速定位问题阶段。
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐