mytechnotalent/encryption

GitHub: mytechnotalent/encryption

Ouroboros 加密引擎的 Rust 嵌入式实现,提供抗物理与侧信道攻击的固件级密码保护。

Stars: 0 | Forks: 0

![image](https://static.pigsec.cn/wp-content/uploads/repos/cas/65/6579b849189eb7cd3c0df026f0d4dd3992a9499003fd0a1f09b796de51cfab2f.png)
# 加密 Ouroboros 加密引擎的 100% 严格、泛型嵌入式密码学 Rust 实现,旨在与原始 AVR 汇编的安全保证和常数时间执行保持绝对一致。
## 入门指南 由于 `encryption` 是一个 `#![no_std]` 泛型库,您需要在系统上安装 Rust 工具链。请根据您的操作系统按照以下步骤操作。
### 1. 安装 Rust 工具链 如果您尚未安装 Rust,请通过 [rustup](https://rustup.rs/) 进行安装: **macOS / Linux:** ``` curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh ``` *(在 Windows 上,请从官方网站下载并运行 `rustup-init.exe`)。* 接下来,如果您打算为 AVR 等嵌入式目标编译此库,您将需要 `nightly` 工具链和 `rust-src` 组件: ``` rustup default nightly rustup component add rust-src ```
### 2. 构建项目 您可以原生构建泛型 `encryption` crate。`Cargo.toml` 已配置为 `#![no_std]`。 要构建项目: ``` cargo build ```
### 3. 运行测试 本项目包含一系列广泛的单元测试,用于验证 Speck-128/256 密码、Davies-Meyer 哈希、CTR 模式解密以及常数时间 MAC 验证。 您可以直接在您的主机上运行测试: ``` cargo test ```
### 4. 运行主机终端演示 该代码库包含一个基于主机的模拟硬件演示。该演示不仅仅是打印 "hello world",而是使用您计算机的终端完全模拟裸机固件!它会将您的终端设置为 raw 模式,并通过与微控制器上使用的完全相同的 `OuroborosEngine` 处理按键操作。 要在 **Linux、Mac (Intel / Apple Silicon)** 上原生运行演示: ``` cargo run --bin demo ``` **交互过程:** 1. 您将看到 `> ` 提示符。 2. 输入密码(例如 `hello`)并按 Enter。(引擎会将您的击键回显到终端)。 3. 演示将正好挂起 10 秒钟,用于计算 24,576 次 Speck 迭代。 4. 如果密码正确,它将打印解密后的 payload(例如 `world`)。如果不正确,则不会打印任何内容。 5. 它将再次提示 `> ` 以进行下一次输入。
### 5. 在 RP2350 (Raspberry Pi Pico 2) 上运行 该代码库还包含针对 RP2350 微控制器的硬件实现。此实现利用了板载 LED (GPIO 25) 并创建了一个 USB CDC ACM (Serial) 设备用于 UART 通信。 要将固件刷入 Raspberry Pi Pico 2: 1. 按住 **BOOTSEL** 按钮的同时通过 USB 将 Pico 2 连接到计算机,以将其作为大容量存储设备挂载。 cd rp2350 cargo build --release picotool uf2 convert target/thumbv8m.main-none-eabihf/release/rp2350 -t elf rp2350.uf2 --family rp2350-arm-s picotool load -x rp2350.uf2 *注意:由于 Spotlight 索引的原因,macOS Finder 在将 UF2 文件复制到 Pico 的 BOOTSEL 驱动器时有时会卡住。我们使用 `picotool load -x` 来安全地刷入并执行 UF2,而不依赖 Finder。* 2. 刷入完成后,打开串行终端以与 USB 设备通信: - 在 macOS/Linux 上:`screen /dev/tty.usbmodem* 115200` - 在 Windows 上:使用 PuTTY 或类似工具连接到新的 COM 端口。 3. 输入 `hello` 并按 Enter。板载 LED 将会亮起整整 10 秒钟,同时串行终端输出 `world`。输入任何其他密码将导致相同的 10 秒常数时间延迟,此时 LED 保持熄灭且没有任何输出。
## 安全威胁模型与对抗姿态 虽然 `encryption` 使用了数学上可靠的密码学,但真正的安全性取决于威胁向量。
### 前提条件:密码熵 **此引擎中的所有安全保证都假设用户部署了高熵、非字典密码**(例如,256 位的随机字符串)。如果使用了像 `hello` 这样的弱字典词,密码可以轻易地被离线暴力破解,从而使所有其他防御措施形同虚设。 假设使用了密码学安全的高熵密码,我们的官方对抗姿态如下:
### 1. 远程 / 软件攻击向量(固件提取):100% 安全 如果攻击者黑客了您的计算机并窃取了 `rp2350.uf2` 固件文件,或者纯粹通过 USB/UART 串行接口与设备进行交互(无物理访问权限): * **固件不包含任何密钥:** 固件 `.uf2` 文件包含加密的密文和算法蓝图,但主密码从不存储在设备上。 * **暴力破解与量子密码分析:** 该引擎使用 Speck-256(符合 NIST 对称密钥后量子合规性),并封装在 24,576 次迭代的 Davies-Meyer KDF 中。这种密码学“焦油坑”使得通过串行端口在计算上不可能猜出高熵密钥空间,同时削弱了量子 Grover 算法在理论上带来的二次加速优势。 * **结论:** 从软件的角度来看,即使攻击者完全提取了固件,该 payload 在数学上也是无法穿透的。它是 100% 安全的。
### 2. 物理 / 硬件攻击向量:高度抗性 即使攻击者对裸机微控制器(如 RP2040、RP2350 或 AVR ATmega)拥有**物理访问权限**,并利用专门的硬件黑客实验室,软件密码学在数学上也能抵抗芯片级的旁路攻击: * **故障注入(EMFI / 电压毛刺):** 攻击者可能会在 Cortex-M33 ALU 评估 MAC 验证分支时,精确地直接向其发射纳秒级电磁脉冲,导致 CPU 产生幻觉并跳过内存擦除。然而,**这并不能旁路掉任何有价值的东西**。由于密钥经过了密码学拉伸并混合到 CTR 流中,payload 本身将被解密为随机垃圾数据。攻击者仍然缺乏真正的密钥。 * **侧信道分析(DPA / CPA):** 通过执行多达 24,576 次 Speck 迭代,引擎创建了一个庞大且充满噪声的 10 秒功耗轨迹,这使得从噪声中逐位提取汉明重量的统计相关性呈指数级困难。 * **冷启动 RAM 提取:** 内存擦除以常数时间执行。除非设备被盗,并精确地在 10 秒执行窗口内、数据衰减之前使用液氮进行冷冻,否则解密后的 payload 永远不会驻留在 SRAM 中。
## 密码学设计 ### Speck-128/256 Ouroboros 引擎使用来自 Simon/Speck 系列(NSA,2013 年)的 **Speck-128/256** 分组密码。Speck 是一种专为受限硬件优化的 Add-Rotate-XOR (ARX) 密码。 **参数:** | 参数 | 值 | |---|---| | 分组大小 | 128 位(2 × 64 位字) | | 密钥大小 | 256 位(4 × 64 位字) | | 轮数 | 34 | | 字大小 | 64 位 | | 旋转常数 | `alpha = 8`, `beta = 3` | **轮函数:** 每次加密轮次使用轮密钥 `k_i` 转换 128 位状态 `(x, y)`: ``` x' = ((x >>> 8) + y) mod 2^64 XOR k_i y' = (y <<< 3) XOR x' ``` 其中 `>>>` 表示右循环移位,`<<<` 表示左循环移位。 **密钥扩展:** 给定被拆分为 `(k_0, l_0, l_1, l_2)` 的 256 位密钥(每个为 64 位字,小端序): ``` l_{i+3} = (k_i + (l_{i mod 3} >>> 8)) mod 2^64 XOR i k_{i+1} = (k_i <<< 3) XOR l_{i+3} ``` 循环 `i = 0..32`,产生 34 个轮密钥 `k_0..k_33`。 **AVR 实现:** 64 位字以小端序存储在 8 个连续的字节寄存器中。汇编使用了: - **`speck_round_half1`**:通过寄存器 R0–R7 的字节移位旋转实现 `x >>> 8`,随后与 R8–R15(`y` 字和密钥)进行多精度 64 位加法。 - **`speck_round_half2`**:通过带有进位反馈的寄存器 R8–R15 之间三条顺序执行的 `LSL`/`ROL` 链实现 `y <<< 3`,随后与 R0–R7 进行 XOR。 所有 34 轮都在一个循环中执行;每一轮都调用这两个半函数,并从 SRAM 中的 `round_keys` 加载中间密钥材料。 **密钥扩展循环缓冲区 (`l_buf`):** 密钥扩展使用一个 32 字节的 SRAM 循环缓冲区 (`l_buf`),其中保存了三个 8 字节的 `l` 值。访问时使用通过重复减法计算的模 3 寻址,以避免使用 `DIV` 指令(AVR 缺乏此指令): ``` offset = (i mod 3) * 8 ```
### Davies-Meyer 密钥拉伸 用户的口令(零填充至 32 字节)在 Davies-Meyer 哈希结构中作为 Speck-128/256 的**密钥**,该结构在一个初始化为 SHA-256 初始常量前 128 位的 16 字节哈希缓冲区上运行 **24,576 次迭代**: ``` IV = 0x6A09E667_BB67AE85_3C6EF372_A54FF53A ``` 密钥拉伸过程如下: ``` H_0 = IV H_j = E(K_user, H_{j-1}) for j = 1..24576 H_final = H_24576 XOR IV ``` 最后的前馈 XOR(即 Davies-Meyer 步骤)确保 `H_final` 不能通过反向破译密码来直接恢复。生成的 16 字节 `H_final` 存储在 `hash_buf` 中,并用作 CTR nonce。 **工作因子:** 每次 `encrypt_block` 调用都会执行 34 轮 Speck 加密。在 8 MHz 频率下,单次 `encrypt_block` 调用大约耗时: ``` T_enc ~= (34 * 103 cycles) / 8,000,000 Hz ~= 437 us Over 24,576 iterations: T_hash ~= 24576 * 437 us ~= 10.74 seconds ``` 每次尝试的这 10 秒窗口使得在线暴力破解在**设备本身上变得不可行**,并为离线模拟创造了巨大的成本障碍。攻击者必须为每个候选密码如实地复制 24,576 次顺序 Speck-128/256 加密过程。
### CTR 模式解密 密钥拉伸后,将生成 CTR 模式密钥流以解密驻留在 flash 中的密文表。块索引 `b in {0, 1, 2}` 的 CTR 块构造如下: ``` CTR_b = H_final[0:8] || b || (7 zero bytes) ``` 其中 `H_final[0:8]` 是来自拉伸哈希的 8 字节 nonce,`b` 是 8 位块计数器。使用相同的用户密钥通过 Speck-128/256 加密 16 字节的 CTR 块以生成密钥流: ``` KS_b = E(K_user, CTR_b) ``` 48 字节密文条目的块 `b` 的解密过程: ``` P_b = C_b XOR KS_b ``` 三个解密后的 16 字节块连接起来形成 48 字节的 `result_buf`: - 字节 0–15:字节码 payload - 字节 16–47:MAC 填充(`32 * 0xAA`)
### 无分支 MAC 验证 解密后,如果密码正确,`result_buf` 的字节 16–47 必须等于 `0xAA`。验证以**常数时间**执行,没有依赖于数据的分支,从而防止计时侧信道攻击: **错误累积(OR 归约):** 设 `P[i]` 表示 `result_buf[i]`。通过 `SUBI 0xAA` 检查每个字节;差异通过 `OR` 累积到 `delta in [0, 255]` 中: ``` delta = OR_reduce( P[16..47] - 0xAA ) ``` **掩码生成(2 的补码技巧):** AVR 指令 `NEG`、`SBC`、`COM` 实现了无分支转换: ``` m = 0xFF if delta == 0 (all bytes match) m = 0x00 if delta != 0 (any mismatch) ``` 证明:如果 `delta == 0`:`NEG(0) = 0`,`carry = 0`;`SBC(0,0,0) = 0`;`COM(0) = 0xFF` ✓ 如果 `delta != 0`:`NEG(``delta``) =` `256 - delta`,`carry = 1`;`SBC(256-delta, 256-delta, 1)` = -1 = 0xFF`;`COM(0xFF) = 0x00` ✓ **无分支结果掩码:** ``` P[i] = P[i] AND m, for i = 0..47 ``` 如果 MAC 验证失败,整个 48 字节缓冲区将被清零。随后字节码分发器会立即遇到 `0x00`(END 操作码),从而不执行任何操作
### 盲选密码 该引擎包含一个驻留在 flash 中的 `N` 个加密 48 字节条目表(`table_ciphers`)。无论是否提前匹配成功,所有 `N` 个条目都**始终**会被完整尝试,以防止计时预言机攻击: ``` found ← 0xFF (sentinel = "not found") for i = 0 to N-1: decrypt entry i → result_buf verify MAC → mask_i (0xFF or 0x00) r0 ← i AND mask_i ; 0 if fail, i if pass found ← (found AND NOT mask_i) OR r0 ``` 在 AVR 中的实现如下: ``` MOV R0, R22 ; R0 = i AND R0, R17 ; R0 = i if pass, 0 if fail COM R17 ; invert mask AND R23, R17 ; R23 = old_found if fail, 0 if pass OR R23, R0 ; R23 = (pass ? i : old_found) ``` 在所有 `N` 次迭代之后,如果 `found != 0xFF`,则获胜条目将被重新解密并分发。解密和验证操作的总次数始终精确为 `N`,与密码或表内容无关。
*Ouroboros 引擎 —— 密码在此吞噬其自身的尾巴。*
参见 [LICENSE](https://github.com/mytechnotalent/encryption/blob/main/LICENSE)。
标签:Rust, 云资产清单, 加密算法, 可视化界面, 密码学, 嵌入式开发, 手动系统调用, 无标准库(no_std), 网络流量审计, 逆向工程, 通知系统