uzairashfaq85/-Side-Channel-Analysis-on-AES-128
GitHub: uzairashfaq85/-Side-Channel-Analysis-on-AES-128
针对STM32微控制器AES-128实现的相关性功耗分析攻击项目,包含硬件改造、功耗采集、多模型统计分析与密钥恢复完整流程。
Stars: 0 | Forks: 0
# AES-128 侧信道分析

针对运行在 STM32 Nucleo 微控制器上的硬件 AES-128 实现的一次实践性**相关性功耗分析 (CPA)** 攻击。通过捕获加密过程中的功耗轨迹,我们利用统计泄漏模型恢复了完整的 128 位密钥。
## 目录
1. [项目概述](#project-overview)
2. [硬件设置与修改](#hardware-setup--modification)
3. [攻击方法论](#attack-methodology)
4. [仓库结构](#repository-structure)
5. [任务 1 — Python CPA 攻击](#task-1--python-cpa-attack)
6. [任务 2 — MATLAB 功耗模型对比](#task-2--matlab-power-model-comparison)
7. [Jupyter Notebook (Scared)](#jupyter-notebook-scared)
8. [结果](#results)
9. [技术栈](#tech-stack)
10. [设置与使用](#setup--usage)
## 项目概述
侧信道攻击利用无意的物理信息泄漏(功耗、电磁辐射、时间),而不是攻击密码算法的数学结构。本项目对 AES-128 执行了一次 **CPA 攻击**:
- 目标设备 (STM32 Nucleo) 加密随机明文块,同时我们用示波器记录其瞬时功耗。
- 对于 16 个密钥字节中的每一个,我们测试所有 256 种可能的假设,对预期的功耗进行建模(使用 `SubBytes(plaintext ⊕ key_guess)` 的汉明重量),并找出其建模功耗与真实轨迹相关性最强的假设。
- 正确的密钥假设会产生一个尖锐的相关性峰值;而所有其他假设则保持在零附近。
## 硬件设置与修改
为了最大化信噪比 (SNR),STM32 Nucleo 开发板进行了物理修改:
| 修改 | 目的 |
|---|---|
| 在 VDD 电源线上插入**分流电阻** | 将电流消耗转换为可测量的电压 |
| 从电源轨移除**去耦电容** | 防止信号平滑,暴露高频功耗尖峰 |
| 在 AES 固件中添加 **GPIO 触发** | 将示波器捕获同步到加密开始的精确时刻 |
功耗轨迹是使用低噪声示波器探头捕获的。每条轨迹覆盖 AES 第一轮的完整过程(1 000 个样本)。为了攻击,收集了一个包含 **10 000 条轨迹** 及其对应明文的数据集。
## 攻击方法论
```
PC --[UART]--> STM32 Nucleo
| (AES-128 encryption + GPIO trigger)
Oscilloscope --> power_trace.bin
PC --> plaintext.bin
```
### CPA 工作流程
1. **数据收集**
- PC 通过 UART 发送随机的 128 位明文。
- 示波器从 GPIO 触发点开始捕获功耗轨迹。
- 数据集:10 000 条轨迹 × 1 000 个样本,存储为 `double` 精度二进制。
2. **泄漏建模**
- **目标:** 第一轮 `SubBytes` 输出 — `V = SubBytes(P ⊕ K)`。
- **模型:** 汉明重量 (HW) — 假设功耗与 `V` 中置位位的数量成正比。
- 对于 16 个密钥字节中的每一个,生成 256 个功耗假设:`H[k] = HW(SubBytes(P ⊕ k))`。
3. **统计分析**
- 计算 `H[k]` 与轨迹矩阵的每个样本列之间的皮尔逊相关系数。
- 具有最高绝对相关性的密钥字节假设即为恢复出的密钥字节。
- 对所有 16 个字节独立重复攻击。
4. **功耗模型对比** (任务 2)
- MATLAB 脚本额外评估了 **8 种单位泄漏模型**(位 0 到 位 7)以及汉明重量模型。
- 针对每种模型测量成功恢复所需的最小轨迹数量。
## 仓库结构
```
.
├── README.md
├── .gitignore
├── Task1_Python_Code_Files/
│ ├── AES_CPA_Scared.ipynb # End-to-end CPA attack using the Scared library
│ ├── CPA_Attack_Simple.py # Modular, fully vectorised CPA attack (main script)
│ ├── cpa_attack.py # Alternative implementation (struct-based loader)
│ ├── data/ # [gitignored] Binary input datasets
│ │ ├── datapoints.bin # Raw power traces (10 000 × 1 000 samples)
│ │ ├── plaintexts_SCA.bin # Corresponding 128-bit plaintexts
│ │ ├── HW.bin # Hamming Weight lookup table
│ │ └── SubBytes.bin # AES SubBytes lookup table
│ └── plots/ # [gitignored] Generated correlation plots
│ ├── CPA_attack_full_key.png
│ └── Tiny_AES_CPA_attack_full_key.png
└── Task2_MATLAB_Code_Files/
├── lab_task2_123.m # CPA attack + 9-model comparison in MATLAB
├── attack_data_10k.mat # [gitignored] 10 000 captured power traces
├── constants.mat # [gitignored] SubBytes table and HW lookup
├── dpa_attack_results.mat # [gitignored] Saved attack results
└── matlab_code.mat # [gitignored] Auxiliary MATLAB data
```
## 任务 1 — Python CPA 攻击
提供了两个 Python 脚本,它们以略有不同的代码组织实现了相同的攻击。
### `CPA_Attack_Simple.py` (推荐)
一个清晰、完全模块化的实现:
| 函数 | 描述 |
|---|---|
| `load_plaintexts()` | 加载并将明文二进制文件重塑为 `(N, 16)` |
| `load_traces_transposed()` | 加载轨迹二进制文件,将按列存储转置为 `(N, 1000)` |
| `compute_hamming_weight_table()` | 构建 256 项 HW 查找表 |
| `cpa_recover_key_byte()` | 针对一个密钥字节的向量化相关计算 — 返回最佳猜测 + 256 个相关值 |
| `recover_full_aes_key()` | 遍历所有 16 个字节,返回完整密钥 + 配置文件 |
| `plot_key_correlations()` | 将 4×4 网格的相关性条形图保存为 PNG |
正确密钥以**红色**突出显示;所有其他假设为浅蓝色。
### cpa_attack.py
一个使用 `struct.unpack` 加载轨迹的等效实现。核心相关计算是相同的。该脚本还提供了一个 `plot_single_byte()` 辅助函数,用于快速检查单个字节。
### 运行
```
cd Task1_Python_Code_Files
# 将 plaintexts_SCA.bin, datapoints.bin, SubBytes.bin, HW.bin 放入 data/
python CPA_Attack_Simple.py
# 输出:plots/CPA_attack_full_key.png + 恢复的密钥打印到控制台
```
## 任务 2 — MATLAB 功耗模型对比
`lab_task2_123.m` 在所有 16 个密钥字节上对比了 **9 种泄漏模型**:
| # | 模型 | 描述 |
|---|---|---|
| 1 | Hamming Weight | 中间值中置位位的总和 |
| 2–9 | Bit 0 – Bit 7 | 中间值的单个位(LSB 到 MSB) |
对于每个模型和每个密钥字节,脚本:
1. 对所有 256 个密钥假设计算 `V = SubBytes(D XOR K)`。
2. 根据选定的模型构建假设功耗矩阵 `H`。
3. 计算**全集合**皮尔逊相关性(使用所有 10 000 条轨迹)以确定真实的密钥字节。
4. 从 `[100, 500, 1000, 2000, 5000, 10000]` 中找出**最小轨迹数**,该数量已能恢复相同的密钥字节。
结果保存在 `results` 结构体中,并打印每种模型所需的平均轨迹数。
### 运行
打开 MATLAB,导航到 `Task2_MATLAB_Code_Files/`,并运行:
```
lab_task2_123
```
## Jupyter Notebook (Scared)
`Task1_Python_Code_Files/AES_CPA_Scared.ipynb` 使用 **[Scared](https://gitlab.com/eshard/scared)** SCA 框架演示了相同的攻击:
| 步骤 | 描述 |
|---|---|
| 1 | 将明文和轨迹加载到 `TraceHolderSet` (THS) 中 |
| 2 | 定义 `FirstSubBytes` 选择函数 |
| 3 | 使用 `HammingWeight` 模型和 `maxabs` 判别式实例化 `CPAAttack` |
| 4 | 运行 `att.run(container)` |
| 5 | 通过 `np.argmax(att.scores, axis=0)` 提取密钥 |
| 6 | 可视化每字节的相关性轨迹(正确 vs. 错误假设) |
安装依赖:
```
pip install scared numpy matplotlib
```
## 结果
| 指标 | 作品集就绪摘要 |
|---|---|
| 密钥恢复完整性 | **16 / 16 字节已恢复** |
| 端到端攻击成功率 | 在收集的数据集上为 **100%** |
| 最有效的泄漏模型 | **Hamming Weight (HW)** |
| 可靠 HW 恢复所需的轨迹 | **~1,000–2,000 条轨迹** |
| 使用的总采集量 | **10,000 条轨迹 × 1,000 个样本** |
Hamming Weight 模型持续需要最少的轨迹。单位模型需要更多轨迹,但在数据充足时可以成功,其中高位(接近 MSB)由于泄漏方差较高,通常表现略好。
## 技术栈
| 层级 | 工具 |
|---|---|
| **硬件** | STM32 Nucleo, 示波器, 低噪声探头 |
| **固件** | C (STM32 HAL/LL), GPIO 触发 |
| **Python 分析** | Python 3.10+, NumPy, Matplotlib, Scared |
| **MATLAB 分析** | MATLAB R2022b+ |
| **Notebook** | Jupyter, ipykernel |
## 设置与使用
### Python (任务 1 & Notebook)
```
# 创建并激活虚拟环境
python -m venv .venv
.venv\Scripts\activate # Windows
source .venv/bin/activate # Linux / macOS
# 安装依赖
pip install numpy matplotlib scared
# 运行任务 1
cd Task1_Python_Code_Files
python CPA_Attack_Simple.py
# 运行 Notebook
cd Task1_Python_Code_Files
jupyter notebook AES_CPA_Scared.ipynb
```
### MATLAB (任务 2)
1. 打开 MATLAB。
2. 切换目录到 `Task2_MATLAB_Code_Files/`。
3. 确保 `attack_data_10k.mat` 和 `constants.mat` 存在。
4. 运行 `lab_task2_123`。
**作者:** Uzair Ashfaq
**日期:** 2025年11月
标签:AES-128, ChipWhisperer, CPA攻击, MATLAB, Python, STM32, 云资产清单, 侧信道攻击, 信号处理, 功耗分析, 命令控制, 密码学, 密钥恢复, 嵌入式安全, 手动系统调用, 数据采集, 无后门, 汉明重量, 物理攻击, 相关功耗分析, 硬件安全, 网络安全, 逆向工具, 逆向工程, 隐私保护