openssl - EVP之对称加密篇

时间:2021-10-13 18:31:10


该部分主要用到了EVP_CIPHER和EVP_CIPHER_CTX两个数据结构。其中,EVP_CIPHER包含了用到的加密算法标识、
密钥长度、IV长度和算法的函数指针等信息;EVP_CIPHER_CTX则包含了一个EVP_CIPHER指针、使用的ENGINE以及
需要操作的数据等信息。

用到的主要函数则包括以下一些(如果返回值为int类型,则返回1表示成功,返回0表示失败):
// 初始化及释放相应数据结构

// 初始化EVP_CIPHER_CTX结构体
void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *a);
// 清除EVP_CIPHER_CTX结构体
int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *a);

// 分配空间,并初始化EVP_CIPHER_CTX结构体
EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void);
// 释放EVP_CIPHER_CTX结构体
void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *a);

// 执行加解密操作的函数

// 初始化一个加解密操作
// enc为1表示加密,0表示解密,-1表示保持不变
int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx,
                      const EVP_CIPHER *cipher,
                      ENGINE *impl,
                      const unsigned char *key,
                      const unsigned char *iv,
                      int enc);

// 添加并加密
int EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl);

// 完成块填充(经过测试,解密需要用EVP_CipherFinal,用EVP_CipherFinal_ex得不到正确的值,不知道什么原因。)
int EVP_CipherFinal(EVP_CIPHER_CTX *ctx, unsigned char *outm, int *outl);
int EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *outm, int *outl);

对于其他的辅助函数,也不再一一介绍。且看下面的例子。

#include "stdafx.h"

#include <openssl/evp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char** argv)
{
const EVP_CIPHER* evp_cipher = NULL;
EVP_CIPHER_CTX evp_cipher_ctx;
char buffer[1024];
int len = 0;
int i = 0;

if (4 != argc)
{
printf("usage: cipher \n");
exit(EXIT_FAILURE);
}

// 将加密函数添加到内部表
OpenSSL_add_all_ciphers();

// 根据名称获取加密算法,如AES-192-OFB等
evp_cipher = EVP_get_cipherbyname(argv[1]);
if (NULL == evp_cipher)
{
printf("no such algorithm: %s\n", argv[1]);
exit(EXIT_FAILURE);
}

// 初始化加密上下文
EVP_CIPHER_CTX_init(&evp_cipher_ctx);

// 初始化加密算法
if (0 == EVP_CipherInit_ex(&evp_cipher_ctx, evp_cipher, NULL, (const unsigned char *)argv[2], NULL, 1))
{
printf("EVP_CipherInit_ex() failed!\n");
exit(EXIT_FAILURE);
}

// 加密
if (0 == EVP_CipherUpdate(&evp_cipher_ctx, (unsigned char *)buffer, &len, (const unsigned char *)argv[3], strlen(argv[3])))
{
printf("EVP_CipherUpdate() failed!\n");
exit(EXIT_FAILURE);
}

//这边还需要EVP_CipherFinal_ex,原作者忽视了.可以参考我的另外一篇<< 利用OpenSSL中EVP封装调用对称加密算法的通用代码>>
// 显示加密结果
// int nLastBufLen = 0;
// EVP_CipherFinal(&evp_cipher_ctx,buffer+len,&nLastBufLen);
// len += nLastBufLen;


// 清除加密上下文
EVP_CIPHER_CTX_cleanup(&evp_cipher_ctx);

EVP_cleanup();

return EXIT_SUCCESS;
}


解密的示例:

SymmetricalAlgorithm.h

class CSymmetricalAlgorithm
{
public:
CSymmetricalAlgorithm();
virtual ~CSymmetricalAlgorithm();

/*
unsigned char* lpszCipehrContent = new unsigned char[nCipherSize];
unsigned char* lpszOutBuf = new unsigned char[nCipherSize];
int nRealSize = CSymmetricalAlgorithm::OpensslAes256Ecb(lpszOutBuf,lpszCipehrContent,nCipherSize,(unsigned char*)strKey.c_str());
//调整数据
memset(lpszOutBuf + nRealSize, 0, nCipherSize - nRealSize);
*/

static int OpensslAes256Ecb(unsigned char* lpuszOutbuf,
unsigned char* lpuszInbuf,
unsigned int unBufLen,
unsigned char* lpuszKey);

static int DecryptByAes128Ecb(unsigned char* lpuszOutbuf,
unsigned char* lpuszInbuf,
unsigned int unBufLen,
unsigned char* lpuszKey);

static int OpensslAes256Cbc(unsigned char* lpuszOutbuf,
unsigned char* lpuszInbuf,
unsigned int unBufLen,
unsigned char* lpuszKey,
unsigned char* lpuszIV);

static int OpensslAes128Cbc(unsigned char* lpuszOutbuf,
unsigned char* lpuszInbuf,
unsigned int unBufLen,
unsigned char* lpuszKey,
unsigned char* lpuszIV);

static int Openssl3DesEcb(unsigned char* lpuszOutbuf,
unsigned char* lpuszInbuf,
unsigned int unBufLen,
unsigned char* lpuszKey);

static int OpensslDesEcb(unsigned char* lpuszOutbuf,
unsigned char* lpuszInbuf,
unsigned int unBufLen,
unsigned char* lpuszKey);

private:
static int DecryptByOpensslEvpSymmetry(const int nType,
unsigned char* lpuszOutbuf,
unsigned char* lpuszInbuf,
unsigned int unBufLen,
unsigned char* lpuszKey,
unsigned char* lpuszIV,
bool bDiscardDecryptPadding = false
);

enum
{
AES_256_ECB = 1,
AES_128_ECB = 2,
AES_256_CBC = 3,
AES_128_CBC = 4,
DES_ECB = 5,
_3DES_ECB = 6,
};
};

SymmetricalAlgorithm.cpp

#include "stdafx.h"

#include <openssl/evp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SymmetricalAlgorithm.h"

CSymmetricalAlgorithm::CSymmetricalAlgorithm()
{

}

CSymmetricalAlgorithm::~CSymmetricalAlgorithm()
{
}


int CSymmetricalAlgorithm::OpensslAes256Ecb(unsigned char* lpuszOutbuf,
unsigned char* lpuszInbuf,
unsigned int unBufLen,
unsigned char* lpuszKey)
{
return DecryptByOpensslEvpSymmetry(AES_256_ECB,
lpuszOutbuf,
lpuszInbuf,
unBufLen,
lpuszKey,
NULL,
true);
}

int CSymmetricalAlgorithm::OpensslAes256Cbc(unsigned char* lpuszOutbuf,
unsigned char* lpuszInbuf,
unsigned int unBufLen,
unsigned char* lpuszKey,
unsigned char* lpuszIV)
{
return DecryptByOpensslEvpSymmetry(AES_256_CBC, lpuszOutbuf, lpuszInbuf, unBufLen, lpuszKey, lpuszIV, true);
}

int CSymmetricalAlgorithm::OpensslAes128Cbc(unsigned char* lpuszOutbuf,
unsigned char* lpuszInbuf,
unsigned int unBufLen,
unsigned char* lpuszKey,
unsigned char* lpuszIV)
{
return DecryptByOpensslEvpSymmetry(AES_128_CBC, lpuszOutbuf, lpuszInbuf, unBufLen, lpuszKey, lpuszIV, true);
}

int CSymmetricalAlgorithm::Openssl3DesEcb(unsigned char* lpuszOutbuf,
unsigned char* lpuszInbuf,
unsigned int unBufLen,
unsigned char* lpuszKey)
{
return DecryptByOpensslEvpSymmetry(_3DES_ECB, lpuszOutbuf, lpuszInbuf, unBufLen, lpuszKey, NULL, true);
}


int CSymmetricalAlgorithm::OpensslDesEcb(unsigned char* lpuszOutbuf,
unsigned char* lpuszInbuf,
unsigned int unBufLen,
unsigned char* lpuszKey)
{
return DecryptByOpensslEvpSymmetry(DES_ECB, lpuszOutbuf, lpuszInbuf, unBufLen, lpuszKey, NULL, true);
}

int CSymmetricalAlgorithm::DecryptByAes128Ecb(unsigned char* lpuszOutbuf,
unsigned char* lpuszInbuf,
unsigned int unBufLen,
unsigned char* lpuszKey)
{
return DecryptByOpensslEvpSymmetry(AES_128_ECB, lpuszOutbuf, lpuszInbuf, unBufLen, lpuszKey, NULL, true);
}

int CSymmetricalAlgorithm::DecryptByOpensslEvpSymmetry(const int nType,
unsigned char* lpuszOutbuf,
unsigned char* lpuszInbuf,
unsigned int unBufLen,
unsigned char* lpuszKey,
unsigned char* lpuszIV,
bool bDiscardDecryptPadding)
{
int iOutSize = unBufLen;

// 将加密函数添加到内部表
OpenSSL_add_all_ciphers();
const EVP_CIPHER * cipher = NULL;
EVP_CIPHER_CTX ctx;
switch (nType)
{
case AES_256_ECB:
{
cipher = EVP_aes_256_ecb();
}
break;

case AES_128_ECB:
{
cipher = EVP_aes_128_ecb();
}
break;

case AES_256_CBC:
{
cipher = EVP_aes_256_cbc();
}
break;

case AES_128_CBC:
{
cipher = EVP_aes_128_cbc();
}
break;

case _3DES_ECB:
{
cipher = EVP_des_ede3_ecb();
}
break;
case DES_ECB:
{
cipher = EVP_des_ecb();
}
break;
}


// 初始化EVP_CIPHER_CTX结构体
EVP_CIPHER_CTX_init(&ctx);

// 初始化一个解密操作
EVP_CipherInit_ex(&ctx, cipher, NULL, lpuszKey, lpuszIV, false);

//解密
EVP_CipherUpdate(&ctx, lpuszOutbuf, &iOutSize, lpuszInbuf, unBufLen);

//处理最后块填充部分
int unLastBufLen = 0;

//这个返回0xC
EVP_CipherFinal(&ctx, lpuszOutbuf + iOutSize, &unLastBufLen);

//这个返回0x10
//EVP_EncryptFinal_ex(&ctx, lpuszOutbuf + iOutSize,&unLastBufLen);
iOutSize += unLastBufLen;

EVP_CIPHER_CTX_cleanup(&ctx);
EVP_cleanup();

//对称解密,加解密缓冲区大小是一样的.
if (true == bDiscardDecryptPadding)
{
memset(lpuszOutbuf + iOutSize, 0, unBufLen - iOutSize);
}
return iOutSize;
}