PY32F002A 试用 ChaCha20 流密码加密 FlashStore 存储数据
ChaCha20 是什么ChaCha20 是一种流密码(stream cipher),RFC 8439 标准。它是 TLS 1.3、QUIC、WireGuard 等新一代协议的默认加密算法之一,Google 在移动端全面用它替代 AES。和 AES 不同,它不需要硬件加速器,纯软件就能在 MCU 上高效运行。
核心特性:
- 对称加密:加密和解密是同一个操作(XOR 密钥流),调用同一个函数
- 无对齐要求:数据不需要 4 字节对齐,任意长度都能处理
- 资源友好:Cortex-M0+ 上 -Os 编译仅占约 700 字节 Flash,约 200 字节栈
- 输入参数:32 字节密钥 + 12 字节 nonce(同一密钥下 nonce 不能重复)
在 PY32F002A 上的用法结合之前移植的 FlashStore A/B 分区存储,把 ChaCha20 作为加密层叠加在上面: - 保存: 明文 → ChaCha20 加密 → FlashStore_Save → 写入 Flash
- 加载: FlashStore_Load → 密文 → ChaCha20 解密 → 明文
复制代码核心代码三行: - chacha20_crypt(data, size, key, nonce); // 加密(或解密,同一函数)
- FlashStore_Save(&cfg, data, size); // 存到闪存
- FlashStore_Load(&cfg, data, size); // 读回
- chacha20_crypt(data, size, key, nonce); // 解密
复制代码
实测:加密一句名言用 "Stay hungry, stay foolish." 做测试,32 字节密钥 + 12 字节 nonce。
明文: - 53 74 61 79 20 68 75 6e 67 72 79 2c 20 73 74 61 │Stay hungry, sta
- 79 20 66 6f 6f 6c 69 73 68 2e 00 00 00 00 00 00 │y foolish.......
复制代码加密后 — 完全不可读: - 3a 28 1d a0 11 62 cd 14 4a 03 07 03 93 67 63 73 │:(...b..J....gcs
- 69 d1 59 2f a1 dd 95 06 2d 14 b5 28 29 ee 9f 0a │i.Y/....-..()...
复制代码FlashStore 存盘再读回,解密还原 — 一字不差。
资源占用PY32F002A(Cortex-M0+,48MHz,-Os):
| 模块 | Flash | 说明 | | flash_store | 594 B | A/B 分区核心 | | flash_store_port | 230 B | HAL 适配 | | chacha20 | ~700 B | 加密/解密 | | 合计 | ~1.5 KB | 含加密的可靠闪存存储 |
如果只需要存储不需要加密,去掉 ChaCha20 即可,约 800 字节搞定。
完整源码只有 100 行,零依赖,复制到任何 MCU 项目即可使用。 - #include "chacha20.h"
- #include <string.h>
- #define QR(a, b, c, d) do { \
- (a) += (b); (d) ^= (a); \
- (d) = ((d) << 16) | ((d) >> 16); \
- (c) += (d); (b) ^= (c); \
- (b) = ((b) << 12) | ((b) >> 20); \
- (a) += (b); (d) ^= (a); \
- (d) = ((d) << 8) | ((d) >> 24); \
- (c) += (d); (b) ^= (c); \
- (b) = ((b) << 7) | ((b) >> 25); \
- } while (0)
- static uint32_t ld32(const uint8_t *p) {
- uint32_t v;
- memcpy(&v, p, sizeof(v));
- return v;
- }
- static void st32(uint8_t *p, uint32_t v) {
- memcpy(p, &v, sizeof(v));
- }
- static void chacha20_block(uint8_t out[64], const uint32_t init[16]) {
- uint32_t x[16];
- memcpy(x, init, sizeof(x));
- for (int i = 0; i < 10; i++) {
- QR(x[0], x[4], x[ 8], x[12]);
- QR(x[1], x[5], x[ 9], x[13]);
- QR(x[2], x[6], x[10], x[14]);
- QR(x[3], x[7], x[11], x[15]);
- QR(x[0], x[5], x[10], x[15]);
- QR(x[1], x[6], x[11], x[12]);
- QR(x[2], x[7], x[ 8], x[13]);
- QR(x[3], x[4], x[ 9], x[14]);
- }
- for (int i = 0; i < 16; i++)
- st32(out + i * 4, x[i] + init[i]);
- }
- void chacha20_crypt(uint8_t *data, size_t size,
- const uint8_t key[32], const uint8_t nonce[12]) {
- if (size == 0) return;
- uint32_t state[16];
- state[0] = 0x61707865u;
- state[1] = 0x3320646eu;
- state[2] = 0x79622d32u;
- state[3] = 0x6b206574u;
- for (int i = 0; i < 8; i++)
- state[4 + i] = ld32(key + i * 4);
- state[12] = 1;
- for (int i = 0; i < 3; i++)
- state[13 + i] = ld32(nonce + i * 4);
- uint8_t keystream[64];
- size_t offset = 0;
- while (offset < size) {
- chacha20_block(keystream, state);
- size_t chunk = size - offset;
- if (chunk > 64) chunk = 64;
- for (size_t i = 0; i < chunk; i++)
- data[offset + i] ^= keystream[i];
- offset += chunk;
- state[12]++;
- }
- }
复制代码头文件: - #ifndef CHACHA20_H
- #define CHACHA20_H
- #include <stddef.h>
- #include <stdint.h>
- void chacha20_crypt(uint8_t *data, size_t size,
- const uint8_t key[32], const uint8_t nonce[12]);
- #endif
复制代码
build 31 July 2026 03:59 (UTC+8)
|