之前写过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
#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;
}
现在本人给出代码结构:
其中Base64下面的文件为base64编解码,这个大家也可以在网上搜,此处就不展示了。
OpensslAesTest.cpp的内容,前面已经粘贴了,此处不再展示,下面列举剩余四个文件的内容。
aes_ecb.h
#pragma once
#include
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
#include
#include
#include
#include
#include
#include
#include
#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
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
#include
#include
#include
#include
#include
#include
#include
#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;
}