EMS 知识库
首页 / knowledge/代码解析/common

aes.h

源文件路径:common/aes.h 所属模块:common(通用工具库) 代码行数:60

1. 文件职责

本文件是 common/aes.c 的对外接口头文件,定义 EMS 固件中唯一的 AES 对称加解密能力(密钥长度枚举、工作模式枚举、上下文结构体 AESInfo_t)以及 4 个函数原型。它是中间件层充电桩(EVC-II / EVC 升级)与 EMS 主控之间「加密协议帧」的算法契约:midware/evc/evc_ii.c 和 midware/evc/evc_upgrade.c 通过本头文件拿到 AESInfo_t、aesInfo[]、aes_key[] 和 AESInit/AESEncrypt/AESDecrypt,把 Modbus 数据域整体加密后再发出。本文件同时把一份硬编码的 32 字节 PUBLIC_KEY 暴露给调用方,作为与充电桩协商一机一密私钥前的「公钥」。文件本身不含任何可执行逻辑、不参与数据流计算,只提供类型/宏/原型。

2. 关键数据结构与宏

名称类型说明
__AES_H__宏include guard(第 6-7 行)
Nb宏4,加解密数据块大小(以 4 字节字为单位),即分组长度 16 字节。无括号包裹,属裸常量宏(第 11 行)
BPOLY宏0x1B,GF(2^8) 域约简多项式低字节,用于 GfMultBy02 的乘 2 溢出约简(第 12 行)
PUBLIC_KEY宏"R$66tK~Dh09&Mg#5#172DTA%&97^%^10",长度正好 32 字节的硬编码预共享密钥,在获取充电桩私钥前作为初始 AES-256 密钥(第 13 行)
AESType_t枚举密钥长度:AES128=128、AES192=192、AES256=256,单位为 bit(第 16-21 行)
AESMode_t枚举工作模式:AES_MODE_ECB=0(电子密码本)、AES_MODE_CBC=1(密码分组链接)(第 24-28 行)
AESInfo_t结构体单个 AES 通道的全部上下文:Nk(密钥字数)、Nr(轮数)、type、mode、key[32]、const void *pIV、expandKey[4*Nb*(14+1)](240 字节扩展密钥,按 AES-256 最大规格预留)(第 30-40 行)
AES_RUN_T结构体u8_public_key[32] / u8_pravite_key[32] / u16_valid_data_len / u16_invalid_data_len。注释写的是「充电桩单体设置」,但全工程无任何引用(第 42-49 行,死代码)
aes_key外部全局变量u8 aes_key[32],由 evc_ii.c 用作解密出的私钥暂存区
aesInfo外部全局变量AESInfo_t aesInfo[4],4 路 AES 上下文(对应 MAX_EVC_II_NUM = 4),索引 = 充电桩地址 - 1

本文件不含位域、联合体、函数指针或回调类型。基础类型 u8 / u16 来自第 9 行 #include "includes.h"(UCOSII/uCOS-CONFIG/includes.h),结构体里另混用了 uint8_t。

3. 函数清单

函数名作用域说明
AES_data_Init全局(原型声明)只把 aesInfo[id] 的 mode 置 ECB、type 置 AES256,不填密钥,定义于 aes.c:304
AESInit全局(原型声明)依据 type 推导 Nk/Nr 并完成 AES 密钥扩展,定义于 aes.c:316
AESDecrypt全局(原型声明)就地/异地对密文分块解密,返回数据长度,定义于 aes.c:409
AESEncrypt全局(原型声明)就地/异地对明文分块加密,返回数据长度,定义于 aes.c:374

共 4 个原型声明,全部对应 aes.c 的全局定义;本头文件没有 static 函数、没有内联函数、没有宏函数。

4. 核心逻辑解析

本文件是纯声明/类型文件,无可执行逻辑。要点集中在接口契约与内存布局上:

4.1 上下文结构的内存契约

AESInfo_t.expandKey 固定按 4*Nb*(14+1) = 240 字节预留(第 39 行注释明确写了「这里按最大的 AES256 进行初始化」),因此无论 type 是 AES128 还是 AES256,aes.c 中的 AESInit 都不会越界写扩展密钥,代价是每通道浪费最多 64 字节 RAM。全局 aesInfo[4] 因此约占 4 × 292 ≈ 1.2 KB 的静态 RAM。

4.2 模式与 IV 的配套约束

pIV 被声明为 const void *(第 37 行),注释指明「当 mode=AES_MODE_CBC 时需要设置,指向 unsigned char IV[4*Nb]」。但 aesInfo[] 在 aes.c:10 是零初始化(= {0}),AES_data_Init 也不写 pIV,所以若调用方把 mode 改成 CBC 而不赋 pIV,aes.c 中 XorBytes(cipher, pIV, 16) 会对 NULL 解引用。当前工程实际只使用 ECB(AES_data_Init 硬写 ECB),CBC 分支属未启用代码路径。

4.3 密钥类型枚举与注释不一致

第 32 行注释写「AES128:Nk=16、AES192:Nk=24、AES256:Nr=32」,这是把「密钥字节数」误写成「Nk(32 位字数)」。实际实现 aes.c:323-338 里 Nk 分别为 4/6/8,Nr 为 10/12/14,代码是对的,注释是错的。

4.4 固定长度填充约定(接口层面的隐含约定)

AESEncrypt/AESDecrypt 的 dataLen 必须是 4*Nb = 16 的整数倍(第 57-58 行注释即为此约束),且 aes.c 内 PKCS7 填充已被注释掉。填充责任被推给调用方,参见 midware/evc/evc_ii.c:2179-2186:不足 32 字节倍数时用 0xff 补齐,而非 PKCS7 的缺 n 补 n。这是一条跨设备(EMS 与充电桩固件)必须一致的隐式协议约定。

5. 对外接口

本文件导出(供谁调用)

本文件调用的外部函数/变量

6. 依赖关系

7. 备注与风险点

  1. 硬编码密钥:PUBLIC_KEY 明文写在头文件里(第 13 行),会被编入固件二进制,任何能读取固件的人都能解出「获取私钥」这一交换过程。属设计层面的安全弱点,非代码缺陷。
  2. AES_RUN_T 是死结构体:全工程仅有定义、零引用(grep -rn "AES_RUN_T" 只命中 aes.h:49),且注释「充电桩单体设置」与结构体字段(公私钥 + 有效/无效数据长度)语义含糊,疑为旧版遗留。
  3. 枚举 AES192 定义了但工程未使用:AES_data_Init 只写 AES256,实际只用 AES-256/ECB 一种组合;AES192 分支为死代码。
  4. aesInfo[4] 越界风险:数组长度 4 与 MAX_EVC_II_NUM 耦合,但头文件未做任何断言;调用方以 buf[0]-1 直接索引(evc_ii.c:154),仅有 buf[0] == 0 的检查,若地址 ≥ 5 则越界。
  5. pIV 为 const void * 而非 const u8 *:弱化了类型检查,配合零初始化和「CBC 未启用」形成潜在空指针隐患,建议若保留 CBC 支持则初始化为合法 IV 缓冲。
  6. 注释与实现不符:Nk 注释(第 32 行)把字数写成字节数;AES_RUN_T 注释与命名风格(pravite 系 private 拼写错误)都表明该头文件经过多轮拼改。