AES CBC和CTR加解密实例

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加解密实例

下文实例使用了第三方开源源码,官方网址:http://www.gladman.me.uk/, 本文测试源码来源:http://gladman.plushost.co.uk/oldsite/AES/index.php,测试时,如下源码文件需加入工程:aes_modes.c、aescrypt.c、aeskey.c、aestab.c。

测试源码如下:

001 #include
002 #include
003 #include
004  
005 #include "aes/aes.h"
006  
007 typedef unsigned char  uint8;
008 typedef char           int8;
009 typedef unsigned short uint16;
010 typedef short          int16;
011 typedef unsigned int   uint32;
012 typedef int            int32;
013  
014 typedef unsigned __int64 uint64;
015 typedef __int64          int64;
016 /******************************
017 For _LINUX
018 typedef long   long    int64;
019 typedef unsigned long  long  uint64;
020 ******************************/
021  
022 using namespace std;
023  
024 //same as function rfc3686_inc
025 void ctr_inc(unsigned char ctr_buf[16])
026 {
027     if(!(++(ctr_buf[15])))
028         if(!(++(ctr_buf[14])))
029             if(!(++(ctr_buf[13])))
030                 ++(ctr_buf[12]);
031 }
032  
033 //same as function rfc3686_init
034 //4Bytes nounce+8Bytes iv+4Bytes counter
035 void ctr_init( unsigned char nonce[4], unsigned char iv[8], unsigned char ctr_buf[16])
036 {
037     memcpy(ctr_buf, nonce, 4);
038     memcpy(ctr_buf +  4, iv, 8);
039     memset(ctr_buf + 12, 0, 4);
040     ctr_inc(ctr_buf);
041 }
042  
043 void print_hex(uint8* buf, uint64 len) {
044     //Print results:
045     for(int i=0;i
046         printf("%02X",buf[i]);
047         if(15 == i%16)
048             printf("\n");
049     }
050     printf("\n");
051 }
052  
053 void main() {
054      
055     uint8   key[]   = {0x10,0xa5,0x88,0x69,0xd7,0x4b,0xe5,0xa3,0x74,0xcf,   0x86,0x7c,0xfb,0x47,0x38,0x59};//AES::DEFAULT_KEYLENGTH
056     uint8   buf[16];//tmp buffer
057  
058     uint8   msg[]   = "HelloWorld!23456";
059     uint64  fsize=strlen((char*)msg);//message size
060     uint8*  DataBuf=new uint8[1024];//Data Buffer
061  
062  
063     //AES with CBC
064     printf("AES with CBC\n");          
065      
066     //Copy data
067     memset(DataBuf,0,1024);
068     strcpy((char*)DataBuf,(char*)msg);
069     uint8* pDataBuf = DataBuf;//tmp pointer
070     uint8   iv1[]   = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,   0x00,0x00,0x00,0x00,0x00,0x00};
071  
072     uint64  iEncryptTimes = fsize/16+1;
073     uint8   iPaddings     = 16-fsize%16;//Padding size
074     uint64  newlen = fsize+iPaddings;//New length
075      
076     //memcpy(DataBuf,iv,16);//Save iv
077     memset(pDataBuf+fsize, iPaddings,iPaddings);//Padding
078     printf("input   =\n");
079     print_hex(DataBuf,newlen);
080     aes_encrypt_ctx en_ctx[1];//Init encrypt
081      
082     //Encrypt
083     for(uint64 i=0;i
084         aes_encrypt_key128(key,en_ctx);
085         aes_cbc_encrypt(pDataBuf,buf,16,iv1,en_ctx);//iv has been changed, ctx has been changed!!!
086         memcpy(pDataBuf,buf,16);
087         pDataBuf += 16;
088     }
089      
090     printf("encrypt =\n");
091     print_hex(DataBuf,newlen);
092      
093     //Decrypt
094     pDataBuf = DataBuf;
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);
100      
101     printf("decrypt =\n");
102     print_hex(buf3,newlen);
103      
104     //================================
105  
106     printf("AES with CTR\n");          
107     //Copy data
108     memset(DataBuf,0,1024);
109     strcpy((char*)DataBuf,(char*)msg);
110     pDataBuf = DataBuf;//tmp pointer
111     uint8   iv3[]   = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,   0x00,0x00,0x00,0x00,0x00,0x00};
112  
113     iEncryptTimes = fsize/16;
114     uint8   iRemain       = fsize%16;
115     uint8   ctr_buf[AES_BLOCK_SIZE];
116      
117     //Save iv(as ctrl buffer)
118     //memcpy(DataBuf,iv,16);
119     printf("input   =\n");
120     print_hex(DataBuf,fsize);
121      
122     //Init encrypt
123     //aes_encrypt_ctx en_ctx[1];
124      
125     //Encrypt
126     for(i=0;i
127         aes_encrypt_key128(key,en_ctx);
128         ctr_init(iv3,iv3+4,ctr_buf);//we set iv as the nouce
129         aes_ctr_encrypt(pDataBuf,buf,16,ctr_buf,ctr_inc,en_ctx);//iv has been changed, ctx has been changed!!!
130         memcpy(pDataBuf,buf,16);
131         pDataBuf += 16;
132     }
133      
134     if(iRemain!=0) {//last times
135         pDataBuf += i*16;
136         aes_encrypt_key128(key,en_ctx);
137         ctr_init(iv3,iv3+4,ctr_buf);//we set iv as the nouce
138         aes_ctr_encrypt(pDataBuf,buf,iRemain,ctr_buf,ctr_inc,en_ctx);//iv has been changed, ctx has been changed!!!
139         memcpy(pDataBuf,buf,iRemain);
140     }
141      
142     printf("encrypt =\n");
143     print_hex(DataBuf,fsize);
144      
145     //Decrypt
146     pDataBuf = DataBuf;
147     uint8   iv4[]       = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,   0x00,0x00,0x00,0x00,0x00,0x00};
148     //uint8 buf3[256]={'\0'};
149     //aes_decrypt_ctx de_ctx[1];
150     //aes_decrypt_key128(key,de_ctx);
151     aes_encrypt_key128(key,en_ctx);
152     ctr_init(iv4,iv4+4,ctr_buf);//we set iv as the nouce
153     aes_ctr_decrypt(pDataBuf,buf3,16,ctr_buf,ctr_inc,en_ctx);
154     printf("decrypt =\n");
155     print_hex(buf3,fsize);
156      
157     printf("\n");
158 }

输出如下(CBC未去掉Padding):

  • AES with CBC
  • input   =
  • 48656C6C6F576F726C64213233343536
  • 10101010101010101010101010101010
  • encrypt =
  • F928E09884AA2BA8CC4B73C09304250C
  • C9A0EEFF2295B5D83BEA0410001BD7C6
  • decrypt =
  • 48656C6C6F576F726C64213233343536
  • 10101010101010101010101010101010
  •  
  • AES with CTR
  • input   =
  • 48656C6C6F576F726C64213233343536
  • encrypt =
  • 1CA0978FE499969C769B6346D46B66F9
  • decrypt =
  • 48656C6C6F576F726C64213233343536

参考资料:

http://zh.wikipedia.org/wiki/高级加密标准

http://zh.wikipedia.org/zh/块密码的工作模式

你可能感兴趣的:(密码学)