前几天需要使用AES加密,其他语言都是现成的类库,new 个实例 + 传个参数 = 搞定!
C++的也有现成的crypto++之类的库,不过太大了,一个库就40多M,没法接受,只能自己寻找资料自力更生(我们就是原始人。。。。)
其实不复杂,算法部分到处都有,但是麻烦就在最后一公里上,怎么弄个字符串传进去再传出来一个字符串,困扰了一天!
首先需要搞清楚几个概念:
AES加密分几种方法:ECB和其他几种;
ECB的方式不需要IV(初始向量:就是再秘钥基础上再偏移一下更难破解),只需要有秘钥就可以了;
其他方式都需要有秘钥和IV。
其次,AES加密需要整组整组的加密,也就是说少于16个字符需要补足16个字符,正好等于16个字符需要再额外加上16个字符,这个东西叫padding,有None, pkcs5padding, pkcs7padding等等种类,具体可以看看这哥们的文章,C#和JAVA支持的方式不一样,这也会导致不同语言加的密解不开。。。。
最后,加密算法操作的和返回的都是unsigned char数组,而我们需要通常是string 进,string出。而且出来的都是”XDFSLDJFF==“ 这样的东西,这个东西就是BASE64编码后的东西了。
我就是把这些麻烦的东西汇总了一下,写个能操纵字符串的类,方便以后的同学们使用!
(我是在这个在线工具对比的结果)
具体的工程在我的资源里可以下载
感谢@yakovchang2017 @ruyi366 的反馈,我当时只做了16个字符内的,超过16字符确实是会报错,下面的改了下,把StringToHex加一个destlen就好了。
没想到还能帮到一些朋友,如果有需要的朋友直接用下面的代码覆盖aeshelper.cpp就可以了。带来误解也给大家说声抱歉!:)
#include "AesHelper.h"
#include "aes.h"
#include "zbase64.h"
CAesHelper::CAesHelper(void)
{
}
CAesHelper::~CAesHelper(void)
{
}
void CAesHelper::StringToHex(const char* pSrc, unsigned char* pDest, int nDestLen)
{
int nSrcLen = 0;
if( pSrc != 0 )
{
nSrcLen = strlen(pSrc);
memcpy(pDest, pSrc, nSrcLen > nDestLen ? nDestLen : nSrcLen);
}
Padding(pDest, nSrcLen > nDestLen ? nDestLen : nSrcLen);
}
void CAesHelper::Padding( unsigned char* pSrc, int nSrcLen )
{
if( nSrcLen < KEYCODELENGTH )
{
unsigned char ucPad = KEYCODELENGTH - nSrcLen;
for( int nID = KEYCODELENGTH; nID > nSrcLen; --nID )
{
pSrc[nID - 1] = ucPad;
}
}
}
std::string CAesHelper::Encrypt( std::string strSrc, std::string strKey )
{
ZBase64 tool;
aes_context ctx;
const char* pSrc = 0;
const char* pTmpSrc = 0;
unsigned char* pDest = 0;
unsigned char* pTmpDest = 0;
int nSrcLen = 0;
int nDestLen = 0;
unsigned char buf[KEYCODELENGTH];
unsigned char key[KEYCODELENGTH];
StringToHex( strKey.c_str(), key, KEYCODELENGTH );
aes_set_key( &ctx, key, 128);
pSrc = strSrc.c_str();
nSrcLen = strSrc.size();
nDestLen = (nSrcLen / KEYCODELENGTH) * KEYCODELENGTH + KEYCODELENGTH;
pDest = new unsigned char[nDestLen];
memset( pDest, 0, nDestLen );
pTmpSrc = pSrc;
pTmpDest = pDest;
while( (pTmpSrc - pSrc) < nSrcLen )
{
StringToHex(pTmpSrc, buf, KEYCODELENGTH);
aes_encrypt( &ctx, buf, buf );
memcpy( pTmpDest, buf, KEYCODELENGTH );
pTmpSrc += KEYCODELENGTH;
pTmpDest += KEYCODELENGTH;
}
if( (pTmpDest - pDest) < nDestLen ) // if the source size % KEYCODELENGTH == 0 then need to add an extra buffer
{
StringToHex(0, buf, KEYCODELENGTH);
aes_encrypt( &ctx, buf, buf );
memcpy( pTmpDest, buf, KEYCODELENGTH );
}
std::string strRet = tool.Encode(pDest, nDestLen);
delete [] pDest;
return strRet;
}
std::string CAesHelper::Decrypt( std::string strSrc, std::string strKey )
{
ZBase64 tool;
aes_context ctx;
const char* pSrc = 0;
const char* pTmpSrc = 0;
unsigned char* pDest = 0;
unsigned char* pTmpDest = 0;
int nSrcLen = 0;
int nDestLen = 0;
unsigned char buf[KEYCODELENGTH];
unsigned char key[KEYCODELENGTH];
StringToHex(strKey.c_str(), key, KEYCODELENGTH);
aes_set_key( &ctx, key, 128);
std::string strSrcHex = tool.Decode(strSrc.c_str(), strSrc.size(), nSrcLen);
pSrc = strSrcHex.data();
nDestLen = nSrcLen;
pDest = new unsigned char[nDestLen];
memset( pDest, 0, nDestLen );
pTmpSrc = pSrc;
pTmpDest = pDest;
while( (pTmpSrc - pSrc) < nSrcLen )
{
memcpy(buf, pTmpSrc, KEYCODELENGTH);
aes_decrypt( &ctx, buf, buf );
memcpy(pTmpDest, buf, KEYCODELENGTH);
pTmpSrc += KEYCODELENGTH;
pTmpDest += KEYCODELENGTH;
}
unsigned char ucTest = 0;
while(ucTest = *(pTmpDest - 1))
{
if( ucTest > 0 && ucTest <= 0x10 )
*(pTmpDest-1) = 0;
else
break;
pTmpDest--;
}
std::string strRet = (char*)pDest;
delete [] pDest;
return strRet;
}