密钥管理单元(Key Management Unit, KMU)是现代安全芯片中的核心硬件模块,其设计理念源于对密钥全生命周期的硬件级保护需求。与软件密钥管理方案相比,KMU通过专用硬件电路实现了密钥的生成、存储、使用和销毁等关键操作,从根本上杜绝了软件层面可能存在的安全漏洞。
Arm KMU采用分层安全架构设计,主要包含三个关键层级:
这种架构在Cortex-M33/M55等安全处理器中尤为常见,其物理隔离特性可有效抵御以下攻击手段:
KMU的寄存器空间采用内存映射IO(MMIO)方式访问,主要分为控制寄存器和密钥寄存器两大类:
| 寄存器类型 | 地址偏移范围 | 核心功能 | 访问权限 |
|---|---|---|---|
| 控制寄存器 | 0x000-0x0AF | 配置密钥导出参数、状态监控 | RW/RO |
| KMUDKPA |
0x0B0-0x12F | 设置密钥槽n的目标端口地址 | RW |
| KMUKSK |
0x130-0x52C | 存储密钥槽n的m号密钥字(共8字) | RW |
| 随机延迟寄存器 | 0x530-0x538 | 引入操作延迟防止时序分析 | RAZ/WI |
| 外设ID寄存器 | 0xFD0-0xFEC | 提供KMU硬件识别信息 | RO |
密钥导出是KMU最核心的功能,涉及两个关键参数寄存器:
DPAI(Destination Port Address Increment)
c复制#define DPAI_NO_INCREMENT 0x00 // 单地址写入(如寄存器映射)
#define DPAI_4BYTE_STEP 0x01 // AES密钥填充常用
#define DPAI_16BYTE_STEP 0x04 // 适合SHA-256场景
DPWD(Destination Port Write Delay)
实践提示:DPAI和DPWD的协同配置需考虑目标设备的特性。例如,当向AES加速器导出密钥时,通常需要设置DPAI=0x01(4字节步进)和DPWD=0x10,以匹配AES引擎的密钥加载时序。
密钥管理的基本操作遵循以下硬件强制流程:
初始化密钥槽
c复制// 步骤1:解锁密钥槽(假设n=0)
KMUKSC[0].LKS = 0; // 清除锁定位
// 步骤2:设置目标地址(必须32位对齐)
KMUDKPA[0] = (uint32_t)&AES_KEYREG & 0xFFFFFFFC;
// 步骤3:按顺序写入密钥字
KMUKSK[0][0] = key_word0; // 必须从索引0开始
KMUKSK[0][1] = key_word1;
...
KMUKSK[0][7] = key_word7;
密钥验证机制
c复制KMUKSC[0].VKS = 1; // 启动校验
while(KMUIS.VKSB == 0); // 等待校验完成
if(KMUIS.VKSE) {
// 处理校验错误
}
安全锁定
c复制KMUKSC[0].LKS = 1; // 永久锁定密钥槽
KMU内置三种随机延迟寄存器用于防御时序分析:
| 寄存器 | 延迟范围 | 实现原理 |
|---|---|---|
| KMURD_8 | 0-7个时钟周期 | 3位PRBG计数器 |
| KMURD_16 | 0-15个时钟周期 | 4位PRBG计数器 |
| KMURD_32 | 0-31个时钟周期 | 5位PRBG计数器 |
使用示例:
c复制// 引入随机延迟(建议在敏感操作前调用)
void kmu_random_delay(void) {
volatile uint32_t dummy;
dummy = *((volatile uint32_t*)0x40053000); // 读取KMURD_8
(void)dummy;
}
KMU在硬件层面实现了以下保护措施:
以下代码展示如何安全地将AES密钥导入加密引擎:
c复制#define AES_KEY_BASE 0x50060000 // 假设AES引擎密钥寄存器地址
void load_aes_key(uint8_t slot_num, const uint32_t key[8]) {
// 1. 配置目标地址(AES密钥寄存器通常需要4字节步进)
KMUDKPA[slot_num] = AES_KEY_BASE;
KMUDPAC.DPAI = 0x01; // 4字节地址递增
// 2. 写入密钥(硬件强制顺序写入)
for(int i=0; i<8; i++) {
KMUKSK[slot_num][i] = key[i];
}
// 3. 验证并锁定
KMUKSC[slot_num].VKS = 1;
while(!KMUIS.VKSB);
if(!KMUIS.VKSE) {
KMUKSC[slot_num].LKS = 1;
}
}
利用KMU的32个密钥槽实现动态密钥轮换:
c复制// 密钥槽状态机
typedef struct {
uint8_t active_slot;
uint8_t standby_slot;
uint32_t rotation_counter;
} kmu_ctx;
void key_rotation(kmu_ctx *ctx) {
// 1. 在新槽位写入密钥
uint32_t new_key[8] = {...}; // 通过TRNG生成
load_aes_key(ctx->standby_slot, new_key);
// 2. 切换活动槽位
AES_CTRL.KEY_SEL = ctx->standby_slot;
// 3. 更新状态
uint8_t tmp = ctx->active_slot;
ctx->active_slot = ctx->standby_slot;
ctx->standby_slot = tmp;
ctx->rotation_counter++;
}
| KMUIS状态位 | 含义 | 处理方法 |
|---|---|---|
| WDADDKPA | 非法目标地址 | 检查KMUDKPA |
| WDALSBDKPA | 地址未对齐 | 确保地址bit[1:0]=0b00 |
| MWKSW | 重复写入密钥字 | 先执行密钥槽无效化操作 |
| AKSWPI | 密钥槽正在被导出 | 等待当前导出完成 |
批量导出模式:
c复制// 设置连续导出多个密钥槽
KMUDPAC.BME = 1; // 启用批量模式
KMUDKPA[0] = DEV1_KEY_ADDR;
KMUDKPA[1] = DEV2_KEY_ADDR;
KMUKSC[0].EKS = 1; // 触发批量导出
预计算地址增量:
延迟平衡技术:
c复制// 在非关键路径插入伪延迟,平衡功耗特征
if(sensitive_operation) {
kmu_random_delay();
}
当KMU用于通过CC EAL4+等安全认证的系统时,需特别注意:
关键寄存器保护:
随机数质量验证:
c复制// 实施NIST SP 800-22测试
void prng_validation(void) {
uint32_t samples[1000];
for(int i=0; i<1000; i++) {
samples[i] = KMURD_32;
}
// 执行频率测试、游程测试等...
}
物理防护配合:
实际项目中,我们曾遇到一个典型案例:某IoT设备因未正确配置DPWD参数,导致通过功耗分析可推断出AES密钥。解决方案是通过示波器捕获总线时序,将DPWD设置为目标AES引擎最大延迟的120%,有效掩盖了密钥相关的功耗特征。