我从网上下载了一套AES加密算法的C++实现,代码如下:

(1)aes.h

#ifndef SRC_UTILS_AES_H
#define SRC_UTILS_AES_H class AES
{
public:
AES(unsigned char* key);
virtual ~AES();
unsigned char* Cipher(unsigned char* input);    // 加密,传入的数组大小必须是16字节
unsigned char* InvCipher(unsigned char* input);  // 解密,传入的数组也必须是16字节
void* Cipher(void* input, int length=);      // 可以传入数组,大小必须是16的整数倍,如果不是将会越界操作;如果不传length而默认为0,那么将按照字符串处理,遇'\0'结束
void* InvCipher(void* input, int length);      // 必须传入数组和大小,必须是16的整数倍 private:
unsigned char Sbox[];
unsigned char InvSbox[];
unsigned char w[][][]; void KeyExpansion(unsigned char* key, unsigned char w[][][]);
unsigned char FFmul(unsigned char a, unsigned char b); void SubBytes(unsigned char state[][]);
void ShiftRows(unsigned char state[][]);
void MixColumns(unsigned char state[][]);
void AddRoundKey(unsigned char state[][], unsigned char k[][]); void InvSubBytes(unsigned char state[][]);
void InvShiftRows(unsigned char state[][]);
void InvMixColumns(unsigned char state[][]);
}; #endif // SRC_UTILS_AES_H

(2)aes.cpp

 #include "aes.h"
#include "string.h" AES::AES(unsigned char* key)
{
unsigned char sBox[] =
{ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76, /**/
0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0, /**/
0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15, /**/
0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75, /**/
0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84, /**/
0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf, /**/
0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8, /**/
0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2, /**/
0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73, /**/
0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb, /**/
0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79, /*a*/
0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08, /*b*/
0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a, /*c*/
0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e, /*d*/
0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf, /*e*/
0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16 /*f*/
};
unsigned char invsBox[] =
{ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb, /**/
0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb, /**/
0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e, /**/
0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25, /**/
0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92, /**/
0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84, /**/
0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06, /**/
0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b, /**/
0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73, /**/
0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e, /**/
0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b, /*a*/
0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4, /*b*/
0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f, /*c*/
0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef, /*d*/
0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61, /*e*/
0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d /*f*/
};
memcpy(Sbox, sBox, );
memcpy(InvSbox, invsBox, );
KeyExpansion(key, w);
} AES::~AES()
{ } unsigned char* AES::Cipher(unsigned char* input)
{
unsigned char state[][];
int i,r,c; for(r=; r<; r++)
{
for(c=; c< ;c++)
{
state[r][c] = input[c*+r];
}
} AddRoundKey(state,w[]); for(i=; i<=; i++)
{
SubBytes(state);
ShiftRows(state);
if(i!=)MixColumns(state);
AddRoundKey(state,w[i]);
} for(r=; r<; r++)
{
for(c=; c< ;c++)
{
input[c*+r] = state[r][c];
}
} return input;
} unsigned char* AES::InvCipher(unsigned char* input)
{
unsigned char state[][];
int i,r,c; for(r=; r<; r++)
{
for(c=; c< ;c++)
{
state[r][c] = input[c*+r];
}
} AddRoundKey(state, w[]);
for(i=; i>=; i--)
{
InvShiftRows(state);
InvSubBytes(state);
AddRoundKey(state, w[i]);
if(i)
{
InvMixColumns(state);
}
} for(r=; r<; r++)
{
for(c=; c< ;c++)
{
input[c*+r] = state[r][c];
}
} return input;
} void* AES::Cipher(void* input, int length)
{
unsigned char* in = (unsigned char*) input;
int i;
if(!length) // 如果是0则当做字符串处理
{
while(*(in+length++));
in = (unsigned char*) input;
}
for(i=; i<length; i+=)
{
Cipher(in+i);
}
return input;
} void* AES::InvCipher(void* input, int length)
{
unsigned char* in = (unsigned char*) input;
int i;
for(i=; i<length; i+=)
{
InvCipher(in+i);
}
return input;
} void AES::KeyExpansion(unsigned char* key, unsigned char w[][][])
{
int i,j,r,c;
unsigned char rc[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36};
for(r=; r<; r++)
{
for(c=; c<; c++)
{
w[][r][c] = key[r+c*];
}
}
for(i=; i<=; i++)
{
for(j=; j<; j++)
{
unsigned char t[];
for(r=; r<; r++)
{
t[r] = j ? w[i][r][j-] : w[i-][r][];
}
if(j == )
{
unsigned char temp = t[];
for(r=; r<; r++)
{
t[r] = Sbox[t[(r+)%]];
}
t[] = Sbox[temp];
t[] ^= rc[i-];
}
for(r=; r<; r++)
{
w[i][r][j] = w[i-][r][j] ^ t[r];
}
}
}
} unsigned char AES::FFmul(unsigned char a, unsigned char b)
{
unsigned char bw[];
unsigned char res=;
int i;
bw[] = b;
for(i=; i<; i++)
{
bw[i] = bw[i-]<<;
if(bw[i-]&0x80)
{
bw[i]^=0x1b;
}
}
for(i=; i<; i++)
{
if((a>>i)&0x01)
{
res ^= bw[i];
}
}
return res;
} void AES::SubBytes(unsigned char state[][])
{
int r,c;
for(r=; r<; r++)
{
for(c=; c<; c++)
{
state[r][c] = Sbox[state[r][c]];
}
}
} void AES::ShiftRows(unsigned char state[][])
{
unsigned char t[];
int r,c;
for(r=; r<; r++)
{
for(c=; c<; c++)
{
t[c] = state[r][(c+r)%];
}
for(c=; c<; c++)
{
state[r][c] = t[c];
}
}
} void AES::MixColumns(unsigned char state[][])
{
unsigned char t[];
int r,c;
for(c=; c< ; c++)
{
for(r=; r<; r++)
{
t[r] = state[r][c];
}
for(r=; r<; r++)
{
state[r][c] = FFmul(0x02, t[r])
^ FFmul(0x03, t[(r+)%])
^ FFmul(0x01, t[(r+)%])
^ FFmul(0x01, t[(r+)%]);
}
}
} void AES::AddRoundKey(unsigned char state[][], unsigned char k[][])
{
int r,c;
for(c=; c<; c++)
{
for(r=; r<; r++)
{
state[r][c] ^= k[r][c];
}
}
} void AES::InvSubBytes(unsigned char state[][])
{
int r,c;
for(r=; r<; r++)
{
for(c=; c<; c++)
{
state[r][c] = InvSbox[state[r][c]];
}
}
} void AES::InvShiftRows(unsigned char state[][])
{
unsigned char t[];
int r,c;
for(r=; r<; r++)
{
for(c=; c<; c++)
{
t[c] = state[r][(c-r+)%];
}
for(c=; c<; c++)
{
state[r][c] = t[c];
}
}
} void AES::InvMixColumns(unsigned char state[][])
{
unsigned char t[];
int r,c;
for(c=; c< ; c++)
{
for(r=; r<; r++)
{
t[r] = state[r][c];
}
for(r=; r<; r++)
{
state[r][c] = FFmul(0x0e, t[r])
^ FFmul(0x0b, t[(r+)%])
^ FFmul(0x0d, t[(r+)%])
^ FFmul(0x09, t[(r+)%]);
}
}
}

  上面的加密算法是没问题的,但是接口有两个需要注意的地方,也就是在头文件中备注的地方:

1、数组的大小必须是16字节或者16的整数倍。

2、不能直接使用字符串输出,因为加密后的数组内容可能有'\0',字符串会被截断。

  为了更方便的使用此加密算法,我封装了一个接口类,声明如下:

(3)aes_encryptor.h

#ifndef SRC_UTILS_AES_ENCRYPTOR_H
#define SRC_UTILS_AES_ENCRYPTOR_H #include <string> class AES; class AesEncryptor
{
public:
AesEncryptor(unsigned char* key);
~AesEncryptor(void); std::string EncryptString(std::string strInfor);
std::string DecryptString(std::string strMessage); void EncryptTxtFile(const char* inputFileName, const char* outputFileName);
void DecryptTxtFile(const char* inputFileName, const char* outputFileName); private:
void Byte2Hex(const unsigned char* src, int len, char* dest);
void Hex2Byte(const char* src, int len, unsigned char* dest);
int Char2Int(char c); private:
AES* m_pEncryptor;
}; #endif // SRC_UTILS_AES_ENCRYPTOR_H

(4)aes_encryptor.cpp

 #include "aes.h"
#include "aes_encryptor.h"
#include "log.h" #include <fstream>
using namespace std; AesEncryptor::AesEncryptor(unsigned char* key)
{
m_pEncryptor = new AES(key);
} AesEncryptor::~AesEncryptor(void)
{
delete m_pEncryptor;
} void AesEncryptor::Byte2Hex(const unsigned char* src, int len, char* dest) {
for (int i=; i<len; ++i) {
sprintf_s(dest + i * , , "%02X", src[i]);
}
} void AesEncryptor::Hex2Byte(const char* src, int len, unsigned char* dest) {
int length = len / ;
for (int i=; i<length; ++i) {
dest[i] = Char2Int(src[i * ]) * + Char2Int(src[i * + ]);
}
} int AesEncryptor::Char2Int(char c) {
if ('' <= c && c <= '') {
return (c - '');
}
else if ('a' <= c && c<= 'f') {
return (c - 'a' + );
}
else if ('A' <= c && c<= 'F') {
return (c - 'A' + );
}
return -;
} string AesEncryptor::EncryptString(string strInfor) {
int nLength = strInfor.length();
int spaceLength = - (nLength % );
unsigned char* pBuffer = new unsigned char[nLength + spaceLength];
memset(pBuffer, '\0', nLength + spaceLength);
memcpy_s(pBuffer, nLength + spaceLength, strInfor.c_str(), nLength);
m_pEncryptor->Cipher(pBuffer, nLength + spaceLength); // 这里需要把得到的字符数组转换成十六进制字符串
char* pOut = new char[ * (nLength + spaceLength)];
memset(pOut, '\0', * (nLength + spaceLength));
Byte2Hex(pBuffer, nLength + spaceLength, pOut); string retValue(pOut);
delete[] pBuffer;
delete[] pOut;
return retValue;
} string AesEncryptor::DecryptString(string strMessage) {
int nLength = strMessage.length() / ;
unsigned char* pBuffer = new unsigned char[nLength];
memset(pBuffer, '\0', nLength);
Hex2Byte(strMessage.c_str(), strMessage.length(), pBuffer); m_pEncryptor->InvCipher(pBuffer, nLength);
string retValue((char*)pBuffer);
delete[] pBuffer;
return retValue;
} void AesEncryptor::EncryptTxtFile(const char* inputFileName, const char* outputFileName) {
ifstream ifs; // Open file:
ifs.open(inputFileName);
if (!ifs) {
UNILOGW("AesEncryptor::EncryptTxtFile() - Open input file failed!");
return ;
} // Read config data:
string strInfor;
string strLine;
while (!ifs.eof()) {
char temp[];
memset(temp, '\0', );
ifs.read(temp, );
strInfor += temp;
}
ifs.close(); // Encrypt
strLine = EncryptString(strInfor); // Writefile
ofstream ofs;
ofs.open(outputFileName);
if (!ofs) {
UNILOGW("AesEncryptor::EncryptTxtFile() - Open output file failed!");
return ;
}
ofs << strLine;
ofs.close();
} void AesEncryptor::DecryptTxtFile(const char* inputFile, const char* outputFile) {
ifstream ifs; // Open file:
ifs.open(inputFile);
if (!ifs) {
UNILOGW("AesEncryptor::DecryptTxtFile() - Open input file failed!");
return ;
} // Read config data:
string strInfor;
string strLine;
while (!ifs.eof()) {
char temp[];
memset(temp, '\0', );
ifs.read(temp, );
strInfor += temp;
}
ifs.close(); // Encrypt
strLine = DecryptString(strInfor); // Writefile
ofstream ofs;
ofs.open(outputFile);
if (!ofs) {
UNILOGW("AesEncryptor::DecryptTxtFile() - Open output file failed!");
return ;
}
ofs << strLine;
ofs.close();
}

  从代码中可以看到增加了以下特性:

1、支持对std::string 字符串类型的加密,并返回相应的字符串,这个字符串是将加密后的内容转换成十六进制表示的,所以不存在截断的问题。当然了,解密的时候也需要转换成真正的unsigned char数组;

2、支持直接对文本文件进行加密,指定输入和输出的文件名即可。

PS: 多说一句,从网上看别人封装的代码时,先看评论和反应,有的时候网友写个带漏洞的程序坑死人不负责的。

最新文章

  1. 【翻译】利用Qt设计师窗体在运行时创建用户界面(Creating a user interface from a Qt Designer form at run-time)
  2. hdu1520
  3. Mac系统搭建java开发环境
  4. [python]逆水行舟不进则退(1)
  5. Android Handler Message总结
  6. SQL疑难杂症【2】解决SQL订阅过程中找不到已经创建的订阅
  7. python之字串
  8. ios开发——实用技术篇Swift篇&amp;录音
  9. Delphi编写自定义控件以及接口的使用(做了一个TpgDbEdit)
  10. 【边做项目边学Android】小白会遇到的问题--This Android SDK requires Android Developer Toolkit version 23.0.0 or above
  11. PHP session 跨子域问题总结
  12. NSString+URLEncoding
  13. spring和mybatis整合进行事务管理
  14. AT NEW 和 AT END OF 的用法
  15. Java API获取topic所占磁盘空间(Kafka 1.0.0)
  16. Bootstrap 前端框架 遇到的问题 解决方案
  17. git pull 解决 refusing to merge unrelated histories 错误
  18. 在GitHub中下载的项目,如何运行
  19. 【BZOJ3514】 Codechef MARCH14 GERALD07加强版
  20. Nodejs-- web服务器

热门文章

  1. [转]SQL Relay使用
  2. 球形环境映射之angular与latlong格式互换
  3. Spring面向切面之AOP深入探讨
  4. zenefits oa - random(5) to generate a random(7)
  5. C#实现自动发送QQ消息
  6. iOS--UIView和UIWindow用法
  7. Mercurial笔记(hg命令)
  8. 使用第三方框架vapor和swift 搭建本地服务器
  9. [读书笔记]java中的volatile关键词
  10. Bootstrap-17