8 位机搬 AES 常遇到 Flash 吃紧、一帧跑太久。按 Microchip AN953 的实测数据拆解 AES、XTEA、SKIPJACK 与 PRBS 四种方案的 ROM、RAM 和每字节周期,给出按场景选型的一张表与七步落地。
一台电池供电的采集终端要把 100 字节参数帧加密后走无线,工程师直接把 PC 上的 AES 例程搬到 8 位机,编译后发现 Flash 被占去一大块;按 AN953 的实测折算,这一帧光加密就要 21.5 万个指令周期,而换成 XTEA 16 轮约 10.8 万,PRBS 不到 1.5 万。结论先给:8 位机上选加密算法,先算 ROM 和每字节周期,再谈安全等级;AN953 的实测里 AES 的 C 版要 6104 字节 ROM、2153 周期/字节,XTEA 16 轮只要 1950 字节、1075 周期/字节,PRBS 汇编版更是 48 字节、22~40 周期/字节——差的是几十倍,不是百分之几。
本文按 Microchip 应用笔记 AN953《Data Encryption Routines for the PIC18》DS00953A 整理,算法参数、资源占用与实测周期均取自该文档的表 7、表 8 与例程;测试平台与编译器版本以原文为准。
AN953 给 PIC18 准备了四条路:AES、XTEA、SKIPJACK,以及一个用伪随机二进制序列做异或的轻量方案。它们不是同一档次的东西,先看分组、密钥和轮数。
| 算法 | 分组长度 | 密钥长度 | 轮数/迭代 | 定位 |
|---|---|---|---|---|
| AES(Rijndael) | 16 字节 | 16 字节 | 10 轮 | 标准算法,互通性最好,代价最高 |
| XTEA | 8 字节 | 16 字节 | 建议 64,常用 32 或 16 | 代码小、轮数可调,折中首选 |
| SKIPJACK | 8 字节 | 10 字节(80 位) | 32 轮 | 密钥偏短,已显老旧 |
| PRBS 异或 | 逐字节流式 | 由反馈抽头与初值决定 | KeyJump 可调 | 速度优先,安全等级低 |
AES 是 NIST 在 2000 年 10 月 2 日采纳的标准,用来替代 DES,本实现固定 16 字节分组和 16 字节密钥,因此走 10 轮;手册表 1 同时给出 24 字节密钥 12 轮、32 字节密钥 14 轮的组合。加密流程分五步:密钥扩展、列混合、行移位、S 盒替换、轮密钥加,最后一轮不做列混合。
XTEA 的特点是算法本身极小,安全性靠迭代次数堆出来。作者建议 64 轮用于高安全场合,32 轮“几十年内应该够用”,安全要求低的场合 16 轮就够。SKIPJACK 是 1980 年代 NSA 为政府文档开发的算法,1998 年才解密公开,80 位密钥配 64 位分组,计数器从 1 数到 32 决定轮密钥;密钥偏短,过时的速度会比 AES、XTEA 快。PRBS 则是线性反馈移位寄存器加异或,8 位反馈系统在抽头 8、7、6、1 时是最大长度序列,KeyJump 用来打破规律周期。
先看代码占多少。表 8 给的是纯算法模块的占用,不含待加密数据缓冲区。
| 算法 | C 版 ROM | C 版 RAM | 汇编版 ROM | 汇编版 RAM |
|---|---|---|---|---|
| PRBS 异或(带 KeyJump) | 226 字节 | 12 字节 | 48 字节 | 11 字节 |
| XTEA | 1950 字节 | 38 字节 | 962 字节 | 25 字节 |
| SKIPJACK | 3616 字节 | 34 字节 | 无 | 无 |
| AES | 6104 字节 | 33 字节 | 4400 字节 | 45 字节 |
以 C 版为例,AES 的 6104 字节是 PRBS 226 字节的 27 倍,是 XTEA 1950 字节的 3.1 倍。换成汇编,AES 4400 字节仍是 XTEA 962 字节的 4.6 倍、PRBS 48 字节的 91 倍。如果器件只有 8 KB Flash,AES 的 C 版一下占去约四分之三,留给业务逻辑的空间非常紧。
RAM 反而不是主要矛盾:四种方案都在 11~45 字节之间,真正吃 RAM 的是待加密的数据缓冲和上层协议栈。选型时先卡 ROM,再看 RAM,顺序不要反。
表 7 给的是每字节周期数和对应吞吐,C 与汇编分开列。这里的 cycles/byte 指平均到每个明文字节的指令周期,与数据长度、密钥取值和迭代次数都有关系,原表也标注了这些前提。
| 方案 | C 加密周期/字节 | C 解密周期/字节 | 汇编加密周期/字节 | 汇编解密周期/字节 |
|---|---|---|---|---|
| PRBS,KeyJump=1 | 92~146 | 92~146 | 22~40 | 22~40 |
| XTEA,16 轮 | 1075 | 1280 | 464 | 464 |
| XTEA,32 轮 | 2133 | 2194 | 926 | 926 |
| SKIPJACK | 2812 | 2817 | 无 | 无 |
| AES | 2153 | 2940 | 367 | 620~687 |
几个结论直接能用来做预算。第一,C 与汇编差距巨大:AES 从 2153 降到 367 周期/字节,接近 5.9 倍;XTEA 16 轮从 1075 降到 464,也有 2.3 倍。时间紧的场合,换汇编比换算法更有效。
第二,解密通常比加密慢。AES 的 C 版加密 2153、解密 2940,原因是解密密钥要么现场推导、要么预先算好存起来,原表专门标注了这一项取决于实现方式;XTEA 在 16 轮时加密 1075、解密 1280,差距小一些。
第三,轮数是直接的乘法。XTEA 从 16 轮加到 32 轮,C 版周期从 1075 涨到 2133,几乎翻倍;PRBS 的 KeyJump 从 1 加到 5,汇编版从 22~40 涨到 97~120。安全等级不是免费的,选轮数就是选预算。
除了 PRBS 异或,AES、XTEA、SKIPJACK 都是分组算法:解密前只要有一个比特出错,整个分组就会解成乱码。手册例 9 给了很直观的数字——明文 0x0102030405060708090A0B0C0D0E0F 加密后是 0x0A940BB5416EF045F1C39458C653EA5A,把最低字节异或 0x01 后再解密,得到的是 0xF0FDF04AD3AFED45BB676E5B3B1685CD,原来的数据完全找不回来。
所以块加密之后一定要加完整性校验:在块内嵌一个校验字节或验证字段,解密后先校验再使用;校验失败就丢弃整帧、请求重传,而不是把乱码送进业务逻辑。手册还提到一个反向用法——故意在密文里引入可预期的错误,攻击者不知道规则,即使拿到算法和密钥也解不对;这能提高门槛,但不能替代密钥管理。
密钥本身才是根。AES 模块允许把解密密钥预置在代码里,也允许用函数现场推导;两种方式各有风险,前者省时间但密钥就躺在 Flash 里,后者多花周期但可以用器件唯一信息参与推导。手册的原话是:只要密钥不公开,AES、SKIPJACK、XTEA 都算安全;密钥一旦公开,数据就裸奔。
| 场景 | 约束 | 首选 | 依据 |
|---|---|---|---|
| 电池供电,每秒多帧,只防误读 | Flash 小于 4 KB,功耗优先 | PRBS 汇编版 | 48 字节 ROM,22~40 周期/字节 |
| 无线参数帧,要抗抓包,Flash 8~16 KB | 一帧百字节级,实时性中等 | XTEA 16 轮汇编版 | 962 字节 ROM,464 周期/字节 |
| 与服务器或上位机互通,必须标准算法 | 协议规定 AES,Flash 充足 | AES 汇编版 | 4400 字节 ROM,367 周期/字节 |
| 老系统沿用 80 位密钥 | 只能兼容 SKIPJACK | SKIPJACK C 版 | 3616 字节 ROM,2812 周期/字节 |
手册的总结与这张表一致:速度优先、安全要求低就选 PRBS;不计成本要最高安全就选 XTEA 32 轮以上或 AES;代码大小、速度和安全三者要平衡,就选 XTEA 16 轮。这句话放在今天仍然成立,尤其是 Flash 只有几 KB 的老平台。
/* XTEA 单分组:64 位数据、128 位密钥;16 轮为例,32/64 轮改循环上限 */
#define DELTA 0x9E3779B9UL
void xtea_encode_block(uint32_t *v, const uint32_t *key)
{
uint32_t sum = 0;
uint8_t i;
for (i = 0; i < 16; i++) {
v[0] += ((v[1] << 4 ^ v[1] >> 5) + v[1]) ^ (sum + key[sum & 0x03]);
sum += DELTA;
v[1] += ((v[0] << 4 ^ v[0] >> 5) + v[0]) ^ (sum + key[(sum >> 11) & 0x03]);
}
}
调用时每处理完 8 字节就重新进入一次函数,sum 从 0 开始,密钥指针保持只读;不要为了省事把 sum 做成静态变量跨块复用,那会把上一块的中间状态带进下一块,解密端如果按标准流程实现就对不上。
| 现象 | 根因 | 改法 |
|---|---|---|
| 加密后长度对,解密全是乱码 | 密钥或 sum 没按块重置 | 每块从 sum=0、密钥首地址开始 |
| 只有最后一小段解错 | 明文没补齐到分组长度 | 按 16 字节(AES)或 8 字节(XTEA)填充 |
| 偶发整帧校验失败 | 无线链路误码,块加密放大成整块报废 | 加校验与重传,必要时降低单帧长度 |
| 周期比预算多一倍 | 用了 C 版且开了高优化等级以外的调试选项 | 对比表 7,时间敏感路径换汇编 |
| Flash 不够 | 选了 AES C 版 | 换 XTEA 16 轮,ROM 从 6104 降到 1950 |
| 换密钥后老设备解不开 | 密钥长度或轮数与对端不一致 | 把算法、轮数、填充规则写进协议版本号 |
一句话总结:8 位机的加密选型是道算术题——先用 cycles/byte 乘帧长算时间,再用 ROM 占用卡 Flash,最后才看安全等级;XTEA 16 轮是多数场景的平衡点,PRBS 适合只求快的场合,AES 留给必须与外部系统互通的项目。
还想接着看:单片机固件加密与代码保护实战指南、EEPROM 数据可靠性保护设计、PIC18 查表与程序存储器读写。
本文基于 Microchip 应用笔记 AN953《Data Encryption Routines for the PIC18》DS00953A 技术资料整理优化。
沧州艾诺威电子 — 国家高新技术企业,20+项国家专利
嵌入式系统开发 · 物联网方案 · AI智能硬件 · 一站式交付
电话:13930711029 | 邮箱:tech@czinv.com | 24小时内响应