之前写过aes加密算法简单说明,本篇用openssl对aes的ecb和cbc模式进行代码编写。
现在拿128位的aes加解密进行说明。
首先强调的是,在openssl提供的函数中,加密和解密每次只能针对16个字节,故加密字符串和密钥都需要自己进行补齐处理。
本文中的加密内容用pkcs7进行补齐,注意pkcs7不是aes加解密算法里面的,一般一些高档语言,会提供进一步的封装,但是openssl里面,本人目前未看到aes的函数中有补齐的部分。

补齐是非常重要的,关于这个,大家若不明白,可以查看aes加密算法简单说明,里面对pkcs7补齐进行了比较详细的说明。

我们首先来看调用的部分:
从下面代码可以看出,分别对aes的ecb和cbc模式给予了加解密演示,其中cbc比aes多了一个向量iv,密码是128位。

// OpensslAesTest.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include "aes_ecb.h"
#include "aes_cbc.h"

int main()
{
	{
		CAesEcb cAesEcb;
		cAesEcb.SetEncryptKey("1234567890123456");
		///加密
		std::string strInput = "1234567890123456123456789012345";
		std::string strOutput;
		cAesEcb.EncryptString(strInput, strOutput);

		///解密
		std::string strDecryptOut;
		cAesEcb.DecryptString(strOutput, strDecryptOut);
		int i = 0;
		i++;
	}

	{
		CAesCbc cAesCbc;
		cAesCbc.SetEncryptKey("1234567890123456");
		cAesCbc.SetEncryptIv("0123456789abcdef");
		///加密
		std::string strInput = "1234567890123456123456789012345";
		std::string strOutput;
		cAesCbc.EncryptString(strInput, strOutput);

		///解密
		std::string strDecryptOut;
		cAesCbc.DecryptString(strOutput, strDecryptOut);
		int i = 0;
		i++;
	}
	
	return 0;
}

我们现在来看下ecb模式的EncryptString的实现
首先函数的实现第一步就是实现对strInPut的补齐,然后从AES_ecb_encrypt可以看出,是对补齐后的内容分段加密,最后将加密后的字符串进行base64编码。
注意:加密后的内容中间可能存在ascii为0的字符,所以加密后的字符串不要赋值于string,否则会出问题。

bool CAesEcb::EncryptString(std::string strInPut, std::string& strOutPut)
{
	Pkcs7Padding(strInPut);
	int iInputLen = strInPut.length();
	unsigned char *temp = new unsigned char[iInputLen + 1];
	memset(temp, 0, iInputLen + 1);

	AES_KEY aes;
	AES_set_encrypt_key((const unsigned char *)m_strKey.c_str(), 128, &aes);
	
	const unsigned char* pInput = (const unsigned char*)strInPut.c_str();
	iInputLen = strInPut.length();
	for (int i = 0; i < iInputLen / 16; i++)
	{
		AES_ecb_encrypt(pInput + i * 16, temp + i * 16, &aes, AES_ENCRYPT);
	}
	char *pOutput = new char[iInputLen * 4 / 3 + 3];

	int iOutputLen = Base64Encode((const char *)temp, iInputLen, pOutput);

	strOutPut = std::string(pOutput, iOutputLen);

	delete[] temp;
	delete[] pOutput;

	return true;
}

我们再来看下cbc模式的EncryptString的实现
首先也是补齐,然后填充向量iv数组,每次AES_cbc_encrypt加密后,iv会发生改变,作为下一轮的加密向量,此处需要注意。

bool CAesCbc::EncryptString(std::string strInPut, std::string& strOutPut)
{
	Pkcs7Padding(strInPut);
	unsigned char iv[17] = { 0 };
	memcpy(iv, m_strIv.c_str(), 16);
	int iInputLen = strInPut.length();
	unsigned char *temp = new unsigned char[iInputLen + 1];
	memset(temp, 0, iInputLen + 1);

	AES_KEY aes;
	AES_set_encrypt_key((const unsigned char *)m_strKey.c_str(), 128, &aes);

	const unsigned char* pInput = (const unsigned char*)strInPut.c_str();
	iInputLen = strInPut.length();
	for (int i = 0; i < iInputLen / 16; i++)
	{
		AES_cbc_encrypt(pInput + i * 16, temp + i * 16, 16, &aes, iv, AES_ENCRYPT);
	}
	char *pOutput = new char[iInputLen * 4 / 3 + 3];

	int iOutputLen = Base64Encode((const char *)temp, iInputLen, pOutput);

	strOutPut = std::string(pOutput, iOutputLen);

	delete[] temp;
	delete[] pOutput;

	return true;
}

现在本人给出代码结构:

android openssl aes jni 加密大文件 openssl实现aes加密解密_c语言


其中Base64下面的文件为base64编解码,这个大家也可以在网上搜,此处就不展示了。

OpensslAesTest.cpp的内容,前面已经粘贴了,此处不再展示,下面列举剩余四个文件的内容。

aes_ecb.h

#pragma once

#include <string>

class CAesEcb 
{
public:
	CAesEcb();
	~CAesEcb();
public:
	void Pkcs7Padding(std::string& strInPut);
	void Pkcs7UnPadding(std::string& strInPut);
	void SetEncryptKey(std::string strKey);
	bool EncryptString(std::string strInPut, std::string& strOutPut);
	bool DecryptString(std::string strInPut, std::string& strOutPut);
private:
	std::string m_strKey;
};

aes_ecb.cpp

#include "aes_ecb.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/aes.h>
#include <openssl/evp.h>  
#include <openssl/bio.h>  
#include <openssl/buffer.h>
#include <openssl/md5.h>
#include "Base64.h"

CAesEcb::CAesEcb()
{

}


CAesEcb::~CAesEcb()
{

}

void CAesEcb::Pkcs7Padding(std::string& strInPut)
{
	char cPadding = 16 - strInPut.length() % 16;
	int iPaddingNum = cPadding;
	for (int i = 0; i < iPaddingNum; i++)
	{
		strInPut += cPadding;
	}
}

void CAesEcb::Pkcs7UnPadding(std::string& strInPut)
{
	int iInputLen = strInPut.length();
	int iRemovedByte = strInPut[iInputLen - 1];

	strInPut = std::string(strInPut.c_str(), iInputLen - iRemovedByte);
}


void CAesEcb::SetEncryptKey(std::string strKey)
{
	m_strKey = strKey;
}

bool CAesEcb::EncryptString(std::string strInPut, std::string& strOutPut)
{
	Pkcs7Padding(strInPut);
	int iInputLen = strInPut.length();
	unsigned char *temp = new unsigned char[iInputLen + 1];
	memset(temp, 0, iInputLen + 1);

	AES_KEY aes;
	AES_set_encrypt_key((const unsigned char *)m_strKey.c_str(), 128, &aes);
	
	const unsigned char* pInput = (const unsigned char*)strInPut.c_str();
	iInputLen = strInPut.length();
	for (int i = 0; i < iInputLen / 16; i++)
	{
		AES_ecb_encrypt(pInput + i * 16, temp + i * 16, &aes, AES_ENCRYPT);
	}
	char *pOutput = new char[iInputLen * 4 / 3 + 3];

	int iOutputLen = Base64Encode((const char *)temp, iInputLen, pOutput);

	strOutPut = std::string(pOutput, iOutputLen);

	delete[] temp;
	delete[] pOutput;

	return true;
}

bool CAesEcb::DecryptString(std::string strInPut, std::string& strOutPut)
{
	char *pOutStr = new char[strInPut.length()];
	int iOutput = Base64Decode(strInPut.c_str(), strInPut.length(), pOutStr);

	AES_KEY aes;
	AES_set_decrypt_key((const unsigned char *)m_strKey.c_str(), 128, &aes);

	unsigned char *pDescrypt = new  unsigned char[iOutput + 1];
	memset(pDescrypt, 0, iOutput + 1);
	for (int i = 0; i < iOutput / 16; i++)
	{
		AES_ecb_encrypt((const unsigned char *)pOutStr + i * 16, pDescrypt + i * 16, &aes, AES_DECRYPT);
	}
	strOutPut = std::string((const char *)pDescrypt);

	Pkcs7UnPadding(strOutPut);
	return true;
}

aes_cbc.h

#pragma once

#include <string>

class CAesCbc
{
public:
	CAesCbc();
	~CAesCbc();
public:
	void Pkcs7Padding(std::string& strInPut);
	void Pkcs7UnPadding(std::string& strInPut);
	void SetEncryptKey(std::string strKey);
	void SetEncryptIv(std::string strIv);
	bool EncryptString(std::string strInPut, std::string& strOutPut);
	bool DecryptString(std::string strInPut, std::string& strOutPut);
private:
	std::string m_strKey;
	std::string m_strIv;
};

aes_cbc.cpp

#include "aes_cbc.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/aes.h>
#include <openssl/evp.h>  
#include <openssl/bio.h>  
#include <openssl/buffer.h>
#include <openssl/md5.h>
#include "Base64.h"

CAesCbc::CAesCbc()
{

}


CAesCbc::~CAesCbc()
{

}

void CAesCbc::Pkcs7Padding(std::string& strInPut)
{
	char cPadding = 16 - strInPut.length() % 16;
	int iPaddingNum = cPadding;
	for (int i = 0; i < iPaddingNum; i++)
	{
		strInPut += cPadding;
	}
}

void CAesCbc::Pkcs7UnPadding(std::string& strInPut)
{
	int iInputLen = strInPut.length();
	int iRemovedByte = strInPut[iInputLen - 1];

	strInPut = std::string(strInPut.c_str(), iInputLen - iRemovedByte);
}


void CAesCbc::SetEncryptKey(std::string strKey)
{
	m_strKey = strKey;
}

void CAesCbc::SetEncryptIv(std::string strIv)
{
	m_strIv = strIv;
}

bool CAesCbc::EncryptString(std::string strInPut, std::string& strOutPut)
{
	Pkcs7Padding(strInPut);
	unsigned char iv[17] = { 0 };
	memcpy(iv, m_strIv.c_str(), 16);
	int iInputLen = strInPut.length();
	unsigned char *temp = new unsigned char[iInputLen + 1];
	memset(temp, 0, iInputLen + 1);

	AES_KEY aes;
	AES_set_encrypt_key((const unsigned char *)m_strKey.c_str(), 128, &aes);

	const unsigned char* pInput = (const unsigned char*)strInPut.c_str();
	iInputLen = strInPut.length();
	for (int i = 0; i < iInputLen / 16; i++)
	{
		AES_cbc_encrypt(pInput + i * 16, temp + i * 16, 16, &aes, iv, AES_ENCRYPT);
	}
	char *pOutput = new char[iInputLen * 4 / 3 + 3];

	int iOutputLen = Base64Encode((const char *)temp, iInputLen, pOutput);

	strOutPut = std::string(pOutput, iOutputLen);

	delete[] temp;
	delete[] pOutput;

	return true;
}

bool CAesCbc::DecryptString(std::string strInPut, std::string& strOutPut)
{
	unsigned char iv[17] = { 0 };
	memcpy(iv, m_strIv.c_str(), 16);

	char *pOutStr = new char[strInPut.length()];
	int iOutput = Base64Decode(strInPut.c_str(), strInPut.length(), pOutStr);

	AES_KEY aes;
	AES_set_decrypt_key((const unsigned char *)m_strKey.c_str(), 128, &aes);

	unsigned char *pDescrypt = new  unsigned char[iOutput + 1];
	memset(pDescrypt, 0, iOutput + 1);
	for (int i = 0; i < iOutput / 16; i++)
	{
		AES_cbc_encrypt((const unsigned char *)pOutStr + i * 16, pDescrypt + i * 16, 16, &aes, iv, AES_DECRYPT);
	}
	strOutPut = std::string((const char *)pDescrypt);

	Pkcs7UnPadding(strOutPut);
	return true;
}