AES加密的C语言实现了基本密码块的加密,这里有两个问题,一是分组加密的一组必须是4x4个字节,这导致被加密的文件大小可能不是4x4的整数倍,这个时候就需要额外填充字符;二是将大块文件分组加密,会导致相同的明文有相同的密文,所以需采取不同的加密模式.本篇是AES加密算法的完结篇.
1. AES的padding问题
首先说一下,在AES加密与解密的过程中如果需要加密的数据不是16的倍数的时候,需要对原来的数据做padding操作;padding分为以下几种,不同的padding对加密与解密有影响,所以要保证padding的方式是一致的。
- ANSI X.923
在ANSI X.923的方式下,先是填充00,最后一个字节填充padded的字节个数。
例子: | DD DD DD DD DD DD DD DD | DD DD DD 00 00 00 00 05 | - ISO 10126
在ISO 10126的方式下,先是填充随机值,最后一个字节填充padded的字节个数。
例子: | DD DD DD DD DD DD DD DD | DD DD DD 95 81 28 A7 05 | - PKCS7
在PKCS7的方式下,如果一共需要padded多少个字节,所有填充的地方都填充这个值。
例子: | DD DD DD DD DD DD DD DD | DD DD DD 05 05 05 05 05 | - ISO/IEC 7816-4
在ISO/IEC 7816-4方式下,第一个填充的字节是80,后面的都填充00。
例子: | DD DD DD DD DD DD DD DD | DD DD DD 80 00 00 00 00 | - Zero padding
在Zero padding方式下,每一个需要填充的字节都填00。
例子: | DD DD DD DD DD DD DD DD | DD DD DD 00 00 00 00 00 |
2. AES的加密模式
- 1.电码本模式(Electronic Codebook Book (ECB));
- 2.密码分组链接模式(Cipher Block Chaining (CBC));
- 3.计算器模式(Counter (CTR));
- 4.密码反馈模式(Cipher FeedBack (CFB));
- 5.输出反馈模式(Output FeedBack (OFB))。
3. 我的实现
现在实现使用的padding方式是PKCS7,加密模式使用了ECB模式。
3.1 加密的API接口,具体实现在前面的笔记有记录
1 | // aes api |
3.2 加密处理
1 | std::ifstream is (filename, std::ifstream::binary); |
3. 代码实现上的若干问题
- 密钥扩展问题,128位加密是16字节(16*8),256位加密是32字节,每一轮的加密轮数也不一样,分别是10轮和14轮。
1
2
3
4
5
6
7
8
9
10
11uint8_t key[KEY_LEN] = {0};
strncpy((char*)&key, password.c_str(),KEY_LEN);
switch (sizeof(key)) {
default:
case 16: Nk = 4; Nr = 10; break;
case 24: Nk = 6; Nr = 12; break;
case 32: Nk = 8; Nr = 14; break;
}
uint8_t* w = (uint8_t*)malloc(Nb*(Nr+1)*4);
key_expansion(key, w); - 性能优化问题,目前intel处理器上,硬件实现了AESENC/AESENCLAST指令;golang的源码实现中,就使用的是这个指令,如果是日常应用,又不担心有硬件后门,可以使用golang版本的aes加密;这里把源码贴出来。你可以理解为AESENC指令实现了cipher函数的功能。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19// crypto/aes/asm_amd64.s(line:8)
TEXT ·encryptBlockAsm(SB),NOSPLIT,$0
MOVQ nr+0(FP), CX
MOVQ xk+8(FP), AX
MOVQ dst+16(FP), DX
MOVQ src+24(FP), BX
MOVUPS 0(AX), X1
MOVUPS 0(BX), X0 // 读取Block到X0寄存器
ADDQ $16, AX
PXOR X1, X0
SUBQ $12, CX
JE Lenc196
JB Lenc128
Lenc256:
MOVUPS 0(AX), X1 // 加密16字节
AESENC X1, X0
MOVUPS 16(AX), X1 //加密16字节
AESENC X1, X0
ADDQ $32, AX