aes-cbc模式加密——密码分组链接模式(Cipher Block Chaining (CBC))
aes-cbc模式加密在加密和解密是需要一个初始化向量(Initialization Vector, IV),在每次加密之前或者解密之后,使用初始化向量与明文或密文异或。
1. 加密
加密时,明文首先与IV异或,然后将结果进行块加密,得到的输出就是密文,同时本次的输出密文作为下一个块加密的IV。
加密过程代码:
1 cypher_t* aes_cbc_encrypt(uint8_t* key, cypher_t* data_in) 2 { 3 //pad last block with 0 4 cypher_t* data_in_padding = block_padding(data_in); 5 cypher_t* cypher_out = (cypher_t*)malloc(sizeof(uint8_t) + data_in->len_data); 6 cypher_out->len_data = data_in_padding->len_data; 7 8 uint8_t iv[16] = {0}; 9 memcpy(iv, IV, 16); 10 uint8_t temp_out[16] = {0}; 11 for (uint8_t index = 0; index < data_in_padding->len_data/16 ; ++index){ 12 array_xor(16, temp_out, data_in_padding->data + (index * 16), iv); //明文与iv异或 13 _aes128_encryption(key, cypher_out->data + index * 16, temp_out); //进行块加密得到密文,同时密文是下次加密的iv 14 memcpy(iv, cypher_out->data + index * 16, 16); //本次的密文是下次加密的iv 15 } 16 free(data_in_padding); 17 return cypher_out; 18 }
2. 解密
解密时,先将密文的第一个块进行块解密,然后将结果与IV异或,就能得到明文,同时,本次解密的输入密文作为下一个块解密的IV。
解密过程代码:
1 cypher_t* aes_cbc_decrypt(uint8_t* key, cypher_t* data_in) 2 { 3 cypher_t* cypher_padding = block_padding(data_in); 4 cypher_t* plain = (cypher_t*)malloc(data_in->len_data); 5 plain->len_data = cypher_padding->len_data; 6 uint8_t iv[16] = {0}; 7 memcpy(iv, IV, 16); 8 uint8_t temp_out[16] = {0}; 9 for (uint8_t index = 0; index < cypher_padding->len_data/16 ; ++index){ 10 _aes128_decryption(key, temp_out, cypher_padding->data + (index*16)); //密文块解密 11 array_xor(16, plain->data + (index*16), temp_out, iv); //与iv异或得到明文 12 memcpy(iv, cypher_padding->data + (index*16), 16); //设置下次解密用到的iv 13 } 14 free(cypher_padding); 15 return plain; 16 }
测试程序:
1 int main() 2 { 3 uint8_t key[16] = { 4 0x01, 0x02, 0x03, 0x04, 0x0a, 0x0b, 0x0c, 0x0d, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff 5 }; 6 uint8_t iv[16] = { 7 0xa, 0xb, 0xc, 0xd, 0x1, 0x2, 0x3, 0x3, 0xa, 0xa, 0xa, 0xa, 0xf, 0xf, 0xf, 0xf 8 }; 9 uint8_t* text = "hello aes_cbc encryption!"; 10 11 printf("密钥:"); 12 for (int i = 0; i < 16; ++i){ 13 if (i%4 == 0 && i != 0) 14 printf(" "); 15 if (i % 16 == 0 && i != 0) 16 printf("\n"); 17 printf("%02x ", key[i]); 18 } 19 printf("\n"); 20 printf("明文:%s\n\n", text); 21 22 set_iv(iv); 23 //--------------------------aes cbc encrypt-------------------------------------- 24 cypher_t* plain = (cypher_t*)malloc(sizeof(uint8_t) + strlen(text)); 25 plain->len_data = strlen(text); 26 memcpy(plain->data, text, plain->len_data); 27 cypher_t* cypher = aes_cbc_encrypt(key, plain); 28 puts("密文:"); 29 for (int i = 0; i < cypher->len_data; ++i){ 30 if (i%4 == 0 && i != 0) 31 printf(" "); 32 if (i % 16 == 0 && i != 0) 33 printf("\n"); 34 printf("%02x ", cypher->data[i]); 35 36 } 37 printf("\n\n"); 38 free(plain); 39 //--------------------------aes cbc decrypt-------------------------------------- 40 cypher_t* decrypted_plain = aes_cbc_decrypt(key, cypher); 41 puts("解密之后:"); 42 for (int i = 0; i < decrypted_plain->len_data; ++i){ 43 if (i%4 == 0 && i != 0) 44 printf(" "); 45 if (i % 16 == 0 && i != 0) 46 printf("\n"); 47 printf("%02x ", decrypted_plain->data[i]); 48 } 49 printf("\n\n"); 50 printf("解密之后的明文字符串输出:\n%s", decrypted_plain); 51 printf("\n\n"); 52 free(decrypted_plain); 53 return 0; 54 }
输出:
密钥:01 02 03 04 0a 0b 0c 0d 00 00 00 00 ff ff ff ff
明文:hello aes_cbc encryption!密文:
76 ae bb ed d2 c3 a6 16 00 4a 4b 3b 33 67 96 07
85 7c 70 c5 0b 7e f2 b6 75 ff fc 67 f4 99 c0 8a解密之后:
68 65 6c 6c 6f 20 61 65 73 5f 63 62 63 20 65 6e
63 72 79 70 74 69 6f 6e 21 00 00 00 00 00 00 00解密之后的明文字符串输出:
hello aes_cbc encryption!
完整代码在 https://github.com/FANCY0047/aes-cbc.git
注:aes加密解密函数来源于互联网