网上实现AES的例子很多,但是错误的和遗漏的也很多,大概是一知半解的人和转载的人很多导致的,所以我打算自己撸一遍算法,以保证后续使用的时候既能保证正确又能开箱即用,也仅供其他人参考。
1. 算法流程
算法流程中,在之前的笔记中讲到的部分是:
- AES加密算法-密钥扩展;扩展密钥,加密过程给的原始密码不能用来直接去加密,要进行一系列步骤扩展成每一轮都是用的密钥,这个密钥不仅要求非线性(S盒替换),还要求密钥有一定的扩散(你可以是试着设置密码给1111,2222这样的密码来分析加密过程的对应关系)。
- AES加密算法-S盒构造;字节替换,非线形替换就是用S盒的值替换原来的值,这是加密部分唯一的非线形处理部分,这样明文和密文之间不会有一一对应的关系.
先贴具体的流程图,如下图参考:
2. 单个步骤细节
行移位和列混淆以及轮密钥相加;皆是为了保证非线形处理后的密文不能存在一种数学上的线形特征。
2.1 循环行移位
之前在密钥扩展的时候讲过循环左移位,不过那是四个字节的左移,这里是4x4的左移动,代码实现如下:
1 | void shift_rows(uint8_t *state) { |
2.2 列混淆
1 | // 列混淆 |
2.3 轮密钥相加
1 | // 这里是简单的4x4矩阵相加(XOR) |
2.4 字节替换(S盒替换)
之前密钥扩展时用到了字节替换(S盒替换),但那是一个4字节的替换,这里是4x4矩阵里逐个替换.
1
2
3
4
5
6
7
8
9
10
11
12
13
14 void sub_bytes(uint8_t *state) {
uint8_t i, j;
uint8_t row, col;
for (i = 0; i < 4; i++) {
for (j = 0; j < Nb; j++) {
// state对应位置的值作为行索引和列索引
row = (state[Nb*i+j] & 0xf0) >> 4;
col = state[Nb*i+j] & 0x0f;
state[Nb*i+j] = s_box[16*row+col];
}
}
}
3. 算法整体实现
3.1 加密流程
参考第一节流程图的代码实现如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40void cipher(uint8_t *in, uint8_t *out, uint8_t *w) {
// w的值为扩展密钥
uint8_t state[4*Nb];
uint8_t r, i, j;
// 直接将明文的4xNb字节初始化到state中.
for (i = 0; i < 4; i++) {
for (j = 0; j < Nb; j++) {
state[Nb*i+j] = in[i+4*j];
}
}
// 轮密钥相加
add_round_key(state, w, 0);
// Nr是轮数,128位加密是10轮,256位加密是14轮
// 这个轮数是可以增加的,论文中建议这么多轮
for (r = 1; r < Nr; r++) {
// S盒替换
sub_bytes(state);
// 循环左移动
shift_rows(state);
// 列混淆
mix_columns(state);
// 轮密钥相加
// 注意: 使用的w,根据r值不同而位置不同
// 密钥不同
add_round_key(state, w, r);
}
// 最后一轮的处理没有列混淆
sub_bytes(state);
shift_rows(state);
add_round_key(state, w, Nr);
// 将中间结果给out
for (i = 0; i < 4; i++) {
for (j = 0; j < Nb; j++) {
out[i+4*j] = state[Nb*i+j];
}
}
}
3.2 实例:
1 | int main() { |
附录:
4x4矩阵乘法,两个4x4的矩阵乘法,就是值等于各项乘积之和.1
2
3
4
5
6
7void coef_mult(uint8_t *a, uint8_t *b, uint8_t *d) {
// gmult是4字节与4字节的乘法
d[0]=gmult(a[0],b[0])^gmult(a[3],b[1])^gmult(a[2],b[2])^gmult(a[1],b[3]);
d[1]=gmult(a[1],b[0])^gmult(a[0],b[1])^gmult(a[3],b[2])^gmult(a[2],b[3]);
d[2]=gmult(a[2],b[0])^gmult(a[1],b[1])^gmult(a[0],b[2])^gmult(a[3],b[3]);
d[3]=gmult(a[3],b[0])^gmult(a[2],b[1])^gmult(a[1],b[2])^gmult(a[0],b[3]);
}