0%

AES加密算法8-golang版

本文主要讲述golang源码中的AES加密和我自己实现的AES的加密算法之间的相互加解密,根据前面的笔记发现golang源码的AES使用的是硬件指令加解密,效率非常高,而软件实现的算法细节比较详细但是速度过慢,但能够互相印证;这一版的实现逐步实现了PKCS7填充和CBC加密模式.

1. CBC处理流程

CBC的工作模式是,初始化的明文和IV向量相加(XOR),加密后的密文和下一个明文相加(XOR)然后加密;这样的好处是就算各组的明文一样,密文也是不一样的,缺点是不能并行加密。
具体的流程如下图:

2. golang版本实现

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
// 这个是初始化向量
// 可以看成随机种子
var commonIV = []byte{
0x00, 0x01, 0x02, 0x03,
0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b,
0x0c, 0x0d, 0x0e, 0x0f}

//AES加密,CBC
func CBCEncrypterAES(origData, key []byte) ([]byte, error) {
// 根据key的长度判断是128,256的加密
c, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
// 初始化IV
encrypter := cipher.NewCBCEncrypter(c, commonIV)
// PKCS7填充处理
blockSize := c.BlockSize()
origData = PKCS7Padding(origData, blockSize)
crypted := make([]byte, len(origData))
copy(crypted, origData)
// 加密处理
encrypter.CryptBlocks(crypted, crypted)
return crypted, nil
}

3. c++实现

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// 初始化IV
static uint8_t commonIV[] = {
0x00, 0x01, 0x02, 0x03,
0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b,
0x0c, 0x0d, 0x0e, 0x0f};

std::ifstream is (filename, std::ifstream::binary);
std::ofstream os (filename + ".enc", std::ifstream::binary);
if (is) {
// 得到文件的长度length
is.seekg (0, is.end);
int length = is.tellg();
is.seekg (0, is.beg);
uint8_t in[16] = {0};
uint8_t out[16] = {0}; // 128
// 初始化IV
memcpy(out,commonIV,sizeof(commonIV));

while(length > 0) {
// 读取文件块
is.read ((char*)in,(length>=16?16:length));
if (!is) break;
// PKCS7填充处理
if(length < 16) {
int num = 16 - length;
for (int i= length;i<16;i++) {
in[i] = num;
}
}

// state ^ IV
for (int i=0;i<4;i++) {
in[4*0+i] ^= out[4*0+i];
in[4*1+i] ^= out[4*1+i];
in[4*2+i] ^= out[4*2+i];
in[4*3+i] ^= out[4*3+i];
}

// 加密
cipher(in /* in */, out /* out */, w /* expanded key */);
os.write((char*)out, sizeof(out));
// PKCS7填充处理
if (length == 16) {
for(int i=0;i<16;i++) in[i] = 16;
cipher(in,out,w);
os.write((char*)out, sizeof(out));
}

length = length - is.gcount();
}

is.close();
os.close();
}

3. 开箱即用