C++封装AES加密类,(ECB + BASE64 + pkcs5padding),直接操纵和返回字符串

前几天需要使用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;
}

 

 

 

 

 

AES/ECB/PKCS7PaddingAES/ECB/PKCS5Padding是两种常见的AES加密模式和填充方式。它们的区别在于填充方式的不同。 PKCS5Padding和PKCS7Padding都是用于填充数据块的,以确保数据块的长度满足加密算法的要求。它们的主要区别在于对于数据块长度不满足加密算法要求时的处理方式。 PKCS5Padding是针对8字节数据块的填充方式,当数据块长度不满8字节时,会使用特定的字节填充数据块,填充的字节值等于需要填充的字节数。例如,如果数据块长度为6字节,则会填充2个字节的值为0x02的字节。 PKCS7Padding是通用的填充方式,可以用于任意长度的数据块。当数据块长度不满足加密算法要求时,会使用特定的字节填充数据块,填充的字节值等于需要填充的字节数。例如,如果数据块长度为6字节,则会填充2个字节的值为0x02的字节。 因此,PKCS5Padding和PKCS7Padding的区别在于对于数据块长度不满足加密算法要求时的处理方式不同。 下面是一个示例代码,演示了AES/ECB/PKCS5PaddingAES/ECB/PKCS7Padding的使用: ```java import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; public class AESExample { public static void main(String[] args) throws Exception { String key = "0123456789abcdef"; String plaintext = "Hello World"; // AES/ECB/PKCS5Padding Cipher cipher1 = Cipher.getInstance("AES/ECB/PKCS5Padding"); SecretKeySpec keySpec1 = new SecretKeySpec(key.getBytes(), "AES"); cipher1.init(Cipher.ENCRYPT_MODE, keySpec1); byte[] encrypted1 = cipher1.doFinal(plaintext.getBytes()); System.out.println("AES/ECB/PKCS5Padding Encrypted: " + new String(encrypted1)); // AES/ECB/PKCS7Padding Cipher cipher2 = Cipher.getInstance("AES/ECB/PKCS7Padding"); SecretKeySpec keySpec2 = new SecretKeySpec(key.getBytes(), "AES"); cipher2.init(Cipher.ENCRYPT_MODE, keySpec2); byte[] encrypted2 = cipher2.doFinal(plaintext.getBytes()); System.out.println("AES/ECB/PKCS7Padding Encrypted: " + new String(encrypted2)); } } ```
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值