TEA可在资源受限单片机上运行,但需手动处理字节序、内存对齐、8字节块对齐,禁用标准库;密钥须为4个uint32_t,输入数据长度必须为8的倍数,需自行实现PKCS#7填充,推荐16或32轮迭代并配套校验机制。

直接上结论:TEA 可以在资源受限的单片机(如 MSP430、STM8、nRF52)上稳定运行,但必须手动处理字节序、内存对齐、无 padding 的块对齐,并禁用标准库依赖。它不是“开箱即用”的算法,而是需要裁剪后嵌入。
TEA 加密函数必须用 uint32_t* 指针操作 8 字节数据块
TEA 本质是 64-bit 分组密码,每次只加密两个连续的 uint32_t(共 8 字节)。它不接受 uint8_t* 或任意长度缓冲区直接传入 —— 这是初学者最常卡住的地方。
- 输入数据必须按 4 字节对齐,且长度严格为 8 的倍数;否则
v[0]和v[1]会读错地址(尤其在小端 MSP430 或 Cortex-M0 上) - 不能直接把
unsigned char buffer[32]强转成uint32_t*后传给tea_encrypt—— 需先用memcpy拆成两两 4 字节块,再逐块处理 - 示例安全调用方式:
uint8_t src[8] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08}; uint32_t v[2]; memcpy(v, src, 8); // 显式拷贝,避开对齐陷阱 tea_encrypt(v, key); memcpy(src, v, 8); // 再写回
密钥必须拆成 4 个 uint32_t,且注意字节序转换
TEA 要求密钥是 128-bit,即 4 个 uint32_t。但你手写的 uint8_t key[16] 是字节流,直接 reinterpret_cast 会因平台字节序出错(比如 STM32 是小端,但密钥常按大端习惯书写)。
- 推荐做法:用宏或静态初始化显式赋值,避免运行时转换
static const uint32_t tea_key[4] = { 0x04030201, // 对应 uint8_t[0..3] = {0x01,0x02,0x03,0x04} 0x08070605, // 同理 0x0C0B0A09, 0x100F0E0D }; - 如果必须从
uint8_t key[16]构建,务必用__builtin_bswap32(GCC)或手动移位翻转,否则加解密必然失败 - 别用
std::vector或动态分配 —— 单片机没 heap 管理,key 必须是 static/const
没有 padding 就没法加密非 8 字节倍数的数据
TEA 本身不处理 padding。如果你要加密 11 字节的报文,encrypt() 函数不会自动补 5 字节 —— 它只会默默加密前 8 字节,剩下 3 字节被忽略或触发越界读(取决于你怎么循环)。
- 必须自己实现 PKCS#7 填充(最简单可靠):
// 填充至 8 字节对齐 uint8_t pad_len = (8 - (len % 8)) % 8; if (pad_len > 0) { memset(buf + len, pad_len, pad_len); len += pad_len; } - 解密后需检查末尾字节值是否一致,并截掉 —— 不验证就直接
len -= buf[len-1]有风险(比如明文末尾恰好是0x03) - 很多单片机项目干脆限定协议层数据长度为 8 的倍数(如固定 32 字节帧),绕过 padding 逻辑,更省 RAM
tea_round 设为 16 还是 32?取决于安全与性能的硬权衡
原始 TEA 推荐 64 轮,但单片机上常用 16 或 32 轮。这不是“越少越快”那么简单 —— 轮数不足会显著降低抗差分分析能力,而 16 轮在 MSP430@6MHz 上约耗时 1.2ms/8 字节,32 轮约 2.3ms。
- 若通信是短周期无线传感(如每秒 10 帧),且密钥不频繁更换,
tea_round = 16可接受 - 若用于固件升级包签名或长期密钥协商,必须用 32 轮以上,且建议换用 XTEA(抗密钥表攻击更强)
- 注意:解密函数里的
sum初始值必须和轮数匹配 —— 16 轮对应0xE3779B90,32 轮对应0xC6EF3720,写错一轮都解不出
真正容易被忽略的是:TEA 没有认证机制,无法检测密文是否被篡改。哪怕只是翻转一个比特,解密后得到的是完全不可预测的乱码,但程序不会报错。在单片机通信中,必须额外加 CRC16 或简单异或校验 —— 这部分逻辑比加密本身更容易出 bug。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











