程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> AES CBC和CTR加解密實例教程

AES CBC和CTR加解密實例教程

編輯:關於C語言
 

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。

測試源碼如下:

#include <iostream>
#include <string>
#include <time.h>

#include "aes/aes.h"

typedef unsigned char uint8;
typedef char int8;
typedef unsigned short uint16;
typedef short int16;
typedef unsigned int uint32;
typedef int int32;

typedef unsigned __int64 uint64;
typedef __int64 int64;
/******************************
For _LINUX
typedef long long int64;
typedef unsigned long long uint64;
******************************/

using namespace std;

//same as function rfc3686_inc
void ctr_inc(unsigned char ctr_buf[16])
{
if(!(++(ctr_buf[15])))
if(!(++(ctr_buf[14])))
if(!(++(ctr_buf[13])))
++(ctr_buf[12]);
}

//same as function rfc3686_init
//4Bytes nounce+8Bytes iv+4Bytes counter
void ctr_init( unsigned char nonce[4], unsigned char iv[8], unsigned char ctr_buf[16])
{
memcpy(ctr_buf, nonce, 4);
memcpy(ctr_buf + 4, iv, 8);
memset(ctr_buf + 12, 0, 4);
ctr_inc(ctr_buf);
}

void print_hex(uint8* buf, uint64 len) {
//Print results:
for(int i=0;i<len;i++) {
printf("%02X",buf[i]);
if(15 == i%16)
printf("\n");
}
printf("\n");
}

void main() {

uint8 key[] = {0x10,0xa5,0x88,0x69,0xd7,0x4b,0xe5,0xa3,0x74,0xcf, 0x86,0x7c,0xfb,0x47,0x38,0x59};//AES::DEFAULT_KEYLENGTH
uint8 buf[16];//tmp buffer

uint8 msg[] = "HelloWorld!23456";
uint64 fsize=strlen((char*)msg);//message size
uint8* DataBuf=new uint8[1024];//Data Buffer


//AES with CBC
printf("AES with CBC\n");

//Copy data
memset(DataBuf,0,1024);
strcpy((char*)DataBuf,(char*)msg);
uint8* pDataBuf = DataBuf;//tmp pointer
uint8 iv1[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00};

uint64 iEncryptTimes = fsize/16+1;
uint8 iPaddings = 16-fsize%16;//Padding size
uint64 newlen = fsize+iPaddings;//New length

//memcpy(DataBuf,iv,16);//Save iv
memset(pDataBuf+fsize, iPaddings,iPaddings);//Padding
printf("input =\n");
print_hex(DataBuf,newlen);
aes_encrypt_ctx en_ctx[1];//Init encrypt

//Encrypt
for(uint64 i=0;i<iEncryptTimes;i++) {
aes_encrypt_key128(key,en_ctx);
aes_cbc_encrypt(pDataBuf,buf,16,iv1,en_ctx);//iv has been changed, ctx has been changed!!!
memcpy(pDataBuf,buf,16);
pDataBuf += 16;
}

printf("encrypt =\n");
print_hex(DataBuf,newlen);

//Decrypt
pDataBuf = DataBuf;
uint8 iv2[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00};
uint8 buf3[256]={'\0'};
aes_decrypt_ctx de_ctx[1];
aes_decrypt_key128(key,de_ctx);
aes_cbc_decrypt(pDataBuf,buf3,newlen,iv2,de_ctx);

printf("decrypt =\n");
print_hex(buf3,newlen);

//================================

printf("AES with CTR\n");
//Copy data
memset(DataBuf,0,1024);
strcpy((char*)DataBuf,(char*)msg);
pDataBuf = DataBuf;//tmp pointer
uint8 iv3[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00};

iEncryptTimes = fsize/16;
uint8 iRemain = fsize%16;
uint8 ctr_buf[AES_BLOCK_SIZE];

//Save iv(as ctrl buffer)
//memcpy(DataBuf,iv,16);
printf("input =\n");
print_hex(DataBuf,fsize);

//Init encrypt
//aes_encrypt_ctx en_ctx[1];

//Encrypt
for(i=0;i<iEncryptTimes;i++) {
aes_encrypt_key128(key,en_ctx);
ctr_init(iv3,iv3+4,ctr_buf);//we set iv as the nouce
aes_ctr_encrypt(pDataBuf,buf,16,ctr_buf,ctr_inc,en_ctx);//iv has been changed, ctx has been changed!!!
memcpy(pDataBuf,buf,16);
pDataBuf += 16;
}

if(iRemain!=0) {//last times
pDataBuf += i*16;
aes_encrypt_key128(key,en_ctx);
ctr_init(iv3,iv3+4,ctr_buf);//we set iv as the nouce
aes_ctr_encrypt(pDataBuf,buf,iRemain,ctr_buf,ctr_inc,en_ctx);//iv has been changed, ctx has been changed!!!
memcpy(pDataBuf,buf,iRemain);
}

printf("encrypt =\n");
print_hex(DataBuf,fsize);

//Decrypt
pDataBuf = DataBuf;
uint8 iv4[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00};
//uint8 buf3[256]={'\0'};
//aes_decrypt_ctx de_ctx[1];
//aes_decrypt_key128(key,de_ctx);
aes_encrypt_key128(key,en_ctx);
ctr_init(iv4,iv4+4,ctr_buf);//we set iv as the nouce
aes_ctr_decrypt(pDataBuf,buf3,16,ctr_buf,ctr_inc,en_ctx);
printf("decrypt =\n");
print_hex(buf3,fsize);

printf("\n");
}
輸出如下(CBC未去掉Padding):

  • AES with CBC
  • input   =
  • 48656C6C6F576F726C64213233343536
  • 10101010101010101010101010101010
  • encrypt =
  • F928E09884AA2BA8CC4B73C09304250C
  • C9A0EEFF2295B5D83BEA0410001BD7C6
  • decrypt =
  • 48656C6C6F576F726C64213233343536
  • 10101010101010101010101010101010
  •  
  • AES with CTR
  • input   =
  • 48656C6C6F576F726C64213233343536
  • encrypt =
  • 1CA0978FE499969C769B6346D46B66F9
  • decrypt =
  • 48656C6C6F576F726C64213233343536
 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved