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. 对外接口
本文件导出(供谁调用)
- 类型:
AESType_t、AESMode_t、AESInfo_t、AES_RUN_T - 宏:
Nb、BPOLY、PUBLIC_KEY - 全局变量:
extern u8 aes_key[32]、extern AESInfo_t aesInfo[4] - 函数:
AES_data_Init、AESInit、AESEncrypt、AESDecrypt - 主要调用方:
midware/evc/evc_ii.c(第 22 行 include;:154解密接收帧、:2187加密发送帧、:481-484/:493-496密钥初始化)、midware/evc/evc_upgrade.c(第 24 行 include;:140解密升级帧)
本文件调用的外部函数/变量
- 无函数调用。仅通过
#include "includes.h"间接依赖 uCOS-II 配置头所提供的u8/u16等基础类型定义。
6. 依赖关系
- 依赖:
UCOSII/uCOS-CONFIG/includes.h(提供u8等类型)。不依赖chip.h、crc.h等其它 common 头文件。 - 被依赖:
common/aes.c(自身实现)、midware/evc/evc_ii.c、midware/evc/evc_upgrade.c。这三处是全工程仅有的#include "aes.h"点(grep -rn "aes.h"结果)。
7. 备注与风险点
- 硬编码密钥:
PUBLIC_KEY明文写在头文件里(第 13 行),会被编入固件二进制,任何能读取固件的人都能解出「获取私钥」这一交换过程。属设计层面的安全弱点,非代码缺陷。 AES_RUN_T是死结构体:全工程仅有定义、零引用(grep -rn "AES_RUN_T"只命中aes.h:49),且注释「充电桩单体设置」与结构体字段(公私钥 + 有效/无效数据长度)语义含糊,疑为旧版遗留。- 枚举
AES192定义了但工程未使用:AES_data_Init只写 AES256,实际只用 AES-256/ECB 一种组合;AES192 分支为死代码。 aesInfo[4]越界风险:数组长度 4 与MAX_EVC_II_NUM耦合,但头文件未做任何断言;调用方以buf[0]-1直接索引(evc_ii.c:154),仅有buf[0] == 0的检查,若地址 ≥ 5 则越界。pIV为const void *而非const u8 *:弱化了类型检查,配合零初始化和「CBC 未启用」形成潜在空指针隐患,建议若保留 CBC 支持则初始化为合法 IV 缓冲。- 注释与实现不符:
Nk注释(第 32 行)把字数写成字节数;AES_RUN_T注释与命名风格(pravite系private拼写错误)都表明该头文件经过多轮拼改。