2. AES加密指令基础
任务目标
本案例使用RISC-V标量加密扩展中的aes32esmi指令,实现AES-128加密算法的一轮(Round)变换。通过该案例,掌握aes32esmi指令的编码格式、操作语义及其在AES轮函数中的具体调用方式。
指令语义
aes32esmi指令执行AES的ShiftRows、SubBytes、MixColumns和AddRoundKey四个步骤中与单列相关的组合操作。其伪代码定义为:
aes32esmi rd, rs1, rs2, bs
// 从rs2中取字节bs(0~3),经S盒替换后与rs1的对应列进行MixColumns运算,
// 结果异或rs1后写入rd的低32位,rd高32位清零。
该指令一次处理一个字节,完成一轮加密需要4次aes32esmi调用(分别对应状态矩阵的4列),每列调用4次(对应4个字节),共16次调用。
核心代码实现
// aes_round.c
#include <stdint.h>
// RISC-V AES 扩展指令内联汇编封装
// bs: 字节选择(0~3),对应状态矩阵列中的字节位置
static inline uint32_t aes32esmi(uint32_t rs1, uint32_t rs2, int bs) {
uint32_t rd;
asm volatile (
"aes32esmi %0, %1, %2, %3"
: "=r"(rd)
: "r"(rs1), "r"(rs2), "i"(bs)
);
return rd;
}
// AES-128 单轮加密(不含初始AddRoundKey)
// state: 16字节状态矩阵,按列主序排列为4个32位字
// round_key: 当前轮密钥,同样按列主序排列
void aes_round_enc(uint32_t state[4], const uint32_t round_key[4]) {
uint32_t t[4];
// 对每一列执行4次aes32esmi,完成ShiftRows+SubBytes+MixColumns
for (int col = 0; col < 4; col++) {
uint32_t col_in = state[col];
uint32_t col_out = 0;
// 字节0:行不移位
col_out ^= aes32esmi(col_in, col_in, 0);
// 字节1:行循环左移1位(对应列索引(col+1)%4)
col_out ^= aes32esmi(col_in, state[(col+1)%4], 1);
// 字节2:行循环左移2位
col_out ^= aes32esmi(col_in, state[(col+2)%4], 2);
// 字节3:行循环左移3位
col_out ^= aes32esmi(col_in, state[(col+3)%4], 3);
t[col] = col_out;
}
// 加轮密钥
for (int i = 0; i < 4; i++) {
state[i] = t[i] ^ round_key[i];
}
}
// 测试入口:执行一轮加密并打印结果
#include <stdio.h>
int main() {
// 测试向量(FIPS-197附录B中间值)
// 初始状态:经过初始AddRoundKey后的值
uint32_t state[4] = {
0x00102030, 0x40506070, 0x8090a0b0, 0xc0d0e0f0
};
// 第一轮轮密钥
uint32_t round_key[4] = {
0x47460601, 0x1cdc0e82, 0x96b98b3d, 0x6aae8c7d
};
aes_round_enc(state, round_key);
printf("Round output:\n");
for (int i = 0; i < 4; i++) {
printf("%08x ", state[i]);
}
printf("\n");
return 0;
}
编译与运行
# 使用支持K扩展的GCC交叉编译器
riscv64-unknown-elf-gcc -march=rv32imac_zkse -mabi=ilp32 -o aes_round aes_round.c
# 在QEMU中运行(需支持K扩展)
qemu-riscv32 -cpu rv32,zkse=on ./aes_round
验证方法
程序输出应与FIPS-197标准中AES-128第一轮加密后的中间值一致。预期输出为:
Round output:
89d810e8 855aedab 0d4158e0 7d9cfe8f
该值对应FIPS-197附录B中第一轮Round 1 output的State值(按列主序排列)。若输出与此一致,则说明aes32esmi指令的调用方式、字节选择顺序及列混合逻辑均正确。
关键说明
aes32esmi的bs参数为立即数,表示从rs2中选取的字节位置,对应ShiftRows后该列中来自不同行的字节。- 状态矩阵按列主序存储:
state[0]的低字节为第0行第0列元素,高字节为第3行第0列元素。 - 本实现仅完成一轮加密变换,不含密钥扩展和初始AddRoundKey,适用于验证指令功能或作为完整AES实现的轮函数模块。