AES(Advanced Encryption Standard,高级加密标准)又叫Rijndael加密法,用来替代DES算法。常见AES加密模式有ECB、CBC、CFB、OFB和CTR等五种, CFB、OFB都带反馈,做流加密用的多,CBC和CTR、ECB多用于独立block加密,由于ECB算法有点小缺点,所以CBC和CTR这两种加解密方式用的较多,也是很多标准规范要求的实现算法,下面看一下这两种算法原理。
AES跟Rijndael相比有点小区别,就是使用固定块(block size)为128bits(16字节)(原Rijndael块大小更灵活),密钥长度支持128、192或256位。
一、AES CBC加解密原理
CBC加解密原理如下图所示(图片来源维基百科,参考文末地址):
CBC加密原理:明文跟向量异或,再用KEY进行加密,结果作为下个BLOCK的初始化向量。解密原理:使用密钥先对密文解密,解密后再同初始向量异或得到明文。
CBC需要对明文块大小进行Padding(补位),由于前后加密的相关性,只能实施串行化动作,无法并行运算。另外,CBC需要参量:密钥和初始化向量。
二、AES CTR加解密原理
CTR加密原理:用密钥对输入的计数器加密,然后同明文异或得到密文。解密原理:用密钥对输入计数器加密,然后同密文异或得到明文。
CTR不需要Padding,而且采用了流密钥方式加解密,适合于并行运算,CTR涉及参量:Nounce随机数、Counter计数器和密钥。Nounce随机数和Counter计数器整体可看作计数器,因为只要算法约定好,就可以回避掉串行化运算。
三、AES CBC和CTR加解密实例
测试源码如下:
007 | typedef unsigned char uint8; |
009 | typedef unsigned short uint16; |
011 | typedef unsigned int uint32; |
014 | typedef unsigned __int64 uint64; |
015 | typedef __int64 int64; |
025 | void ctr_inc(unsigned char ctr_buf[16]) |
027 | if (!(++(ctr_buf[15]))) |
028 | if (!(++(ctr_buf[14]))) |
029 | if (!(++(ctr_buf[13]))) |
035 | void ctr_init( unsigned char nonce[4], unsigned char iv[8], unsigned char ctr_buf[16]) |
037 | memcpy (ctr_buf, nonce, 4); |
038 | memcpy (ctr_buf + 4, iv, 8); |
039 | memset (ctr_buf + 12, 0, 4); |
043 | void print_hex(uint8* buf, uint64 len) { |
045 | for ( int i=0;i<len;i++) { |
046 | printf ( "%02X" ,buf[i]); |
055 | uint8 key[] = {0x10,0xa5,0x88,0x69,0xd7,0x4b,0xe5,0xa3,0x74,0xcf, 0x86,0x7c,0xfb,0x47,0x38,0x59}; |
058 | uint8 msg[] = "HelloWorld!23456" ; |
059 | uint64 fsize= strlen (( char *)msg); |
060 | uint8* DataBuf= new uint8[1024]; |
064 | printf ( "AES with CBC\n" ); |
067 | memset (DataBuf,0,1024); |
068 | strcpy (( char *)DataBuf,( char *)msg); |
069 | uint8* pDataBuf = DataBuf; |
070 | uint8 iv1[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00}; |
072 | uint64 iEncryptTimes = fsize/16+1; |
073 | uint8 iPaddings = 16-fsize%16; |
074 | uint64 newlen = fsize+iPaddings; |
077 | memset (pDataBuf+fsize, iPaddings,iPaddings); |
079 | print_hex(DataBuf,newlen); |
080 | aes_encrypt_ctx en_ctx[1]; |
083 | for (uint64 i=0;i<iEncryptTimes;i++) { |
084 | aes_encrypt_key128(key,en_ctx); |
085 | aes_cbc_encrypt(pDataBuf,buf,16,iv1,en_ctx); |
086 | memcpy (pDataBuf,buf,16); |
090 | printf ( "encrypt =\n" ); |
091 | print_hex(DataBuf,newlen); |
095 | uint8 iv2[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00}; |
096 | uint8 buf3[256]={ '\0' }; |
097 | aes_decrypt_ctx de_ctx[1]; |
098 | aes_decrypt_key128(key,de_ctx); |
099 | aes_cbc_decrypt(pDataBuf,buf3,newlen,iv2,de_ctx); |
101 | printf ( "decrypt =\n" ); |
102 | print_hex(buf3,newlen); |
106 | printf ( "AES with CTR\n" ); |
108 | memset (DataBuf,0,1024); |
109 | strcpy (( char *)DataBuf,( char *)msg); |
111 | uint8 iv3[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00}; |
113 | iEncryptTimes = fsize/16; |
114 | uint8 iRemain = fsize%16; |
115 | uint8 ctr_buf[AES_BLOCK_SIZE]; |
120 | print_hex(DataBuf,fsize); |
126 | for (i=0;i<iEncryptTimes;i++) { |
127 | aes_encrypt_key128(key,en_ctx); |
128 | ctr_init(iv3,iv3+4,ctr_buf); |
129 | aes_ctr_encrypt(pDataBuf,buf,16,ctr_buf,ctr_inc,en_ctx); |
130 | memcpy (pDataBuf,buf,16); |
136 | aes_encrypt_key128(key,en_ctx); |
137 | ctr_init(iv3,iv3+4,ctr_buf); |
138 | aes_ctr_encrypt(pDataBuf,buf,iRemain,ctr_buf,ctr_inc,en_ctx); |
139 | memcpy (pDataBuf,buf,iRemain); |
142 | printf ( "encrypt =\n" ); |
143 | print_hex(DataBuf,fsize); |
147 | uint8 iv4[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00}; |
151 | aes_encrypt_key128(key,en_ctx); |
152 | ctr_init(iv4,iv4+4,ctr_buf); |
153 | aes_ctr_decrypt(pDataBuf,buf3,16,ctr_buf,ctr_inc,en_ctx); |
154 | printf ( "decrypt =\n" ); |
155 | print_hex(buf3,fsize); |
输出如下(CBC未去掉Padding):
- AES with CBC
- input =
- 48656C6C6F576F726C64213233343536
- 10101010101010101010101010101010
- encrypt =
- F928E09884AA2BA8CC4B73C09304250C
- C9A0EEFF2295B5D83BEA0410001BD7C6
- decrypt =
- 48656C6C6F576F726C64213233343536
- 10101010101010101010101010101010
-
- AES with CTR
- input =
- 48656C6C6F576F726C64213233343536
- encrypt =
- 1CA0978FE499969C769B6346D46B66F9
- decrypt =
- 48656C6C6F576F726C64213233343536
参考资料: