首页 > 编程语言 >C++使用OpenSSL实现AES-256-CBC加密解密实例----亲测OK

C++使用OpenSSL实现AES-256-CBC加密解密实例----亲测OK

时间:2023-11-30 13:04:20浏览次数:49  
标签:CBC AES xxxx encrypted OpenSSL len unsigned iv data


// AesUtil.h
#ifndef __AES_UTIL_H__
#define __AES_UTIL_H__



#ifdef __cplusplus             //告诉编译器,这部分代码按C语言的格式进行编译,而不是C++的
extern "C"{
#endif

string UTIL_aes_cbc_encrypt(const unsigned char *password, unsigned int password_byte_len, const unsigned char *iv, unsigned int iv_byte_len, const unsigned char *data, unsigned int data_len);
int UTIL_aes_cbc_decrypt(const unsigned char *password, unsigned int password_byte_len, const unsigned char *iv, unsigned int iv_byte_len, string encrypted_base64str, unsigned char **out_data, unsigned int *out_data_len);

#ifdef __cplusplus             //告诉编译器,这部分代码按C语言的格式进行编译,而不是C++的
}
#endif

#endif /* __AES_UTIL_H__ */
// AesUtil.cpp
#include<string>
using namespace std;

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<openssl/aes.h>
#include<openssl/rsa.h>
#include<openssl/pem.h>
#include<openssl/err.h>
//#include "xxxx_platform_common.h"
//#include "liblicense_log.h"
#include "Base64Util.h"
#include "AesUtil.h"

#define DEBUG_AESUTIL (1)

#define print_ln(log_level, fmt, ...) do {printf("(%s|%d)" fmt "\r\n", __func__, __LINE__, ##__VA_ARGS__); fflush(stdout);} while(0)
#define xxxx_free(a) do {if(a) {free((void *)a); (a) = NULL;}} while(0)

/*****************************************************************

    aes加密(cbc模式)

    注: password_byte_len 为16字节表示 aes128
        password_byte_len 为32字节表示 aes256

    参数 : password, 输入参数, 密码
           password_byte_len, 输入参数, 密码字节个数
           iv, 输入参数, 向量
           iv_byte_len, 输入参数, 向量字节个数
           data, 输入参数, 待加密数据
           data_len, 输入参数, 待加密数据字节个数
           out_encrypted, 输出参数, 加密后的密文
           out_encrypted_len, 输出参数, 加密后的密文字节个数

     return :  0, 成功
              -1, 失败

*****************************************************************/
static int _aes_cbc_encrypt(const unsigned char *password, unsigned int password_byte_len, const unsigned char *iv, unsigned int iv_byte_len, const unsigned char *data, unsigned int data_len, unsigned char **out_encrypted, unsigned int *out_encrypted_len)
{
    unsigned char tmp_iv[AES_BLOCK_SIZE] = {'\0'};
    unsigned char *data_encrypted = NULL;
    unsigned char *data_bak = NULL;
    unsigned int data_bak_len = 0;
    int padding = 0;
    AES_KEY aes_key;

    if (NULL == password || 0 >= password_byte_len
        || NULL == iv || AES_BLOCK_SIZE != iv_byte_len
        || NULL == data || 0 >= data_len
        || NULL == out_encrypted || NULL == out_encrypted_len
       )
    {
        xxxx_print_ln(xxxx_ERROR, "wrong parameter.");
        return -1;
    }

    if (AES_set_encrypt_key(password, password_byte_len * 8, &aes_key) < 0) {
        xxxx_print_ln(xxxx_ERROR, "AES_set_encrypt_key Failed.");
        return -1;
    }

    // PKCS7Padding
    if (data_len % (AES_BLOCK_SIZE) > 0) {
        padding = AES_BLOCK_SIZE - data_len % (AES_BLOCK_SIZE);
    } else {
        padding = AES_BLOCK_SIZE;
    }

#if DEBUG_AESUTIL
    xxxx_print_ln(xxxx_DEBUG, "padding=%d\r\n", padding);
#endif

    data_bak_len = data_len + padding;
    data_bak = (unsigned char *)calloc(1, data_bak_len);
    data_encrypted = (unsigned char *)calloc(1, data_bak_len);
    if (NULL == data_bak || NULL == data_encrypted) {
        xxxx_print_ln(xxxx_ERROR, "malloc Failed(size=%u).", data_bak_len);
        goto __Failed;
    }

    memcpy((void *)data_bak, (void *)data, data_len);
    memcpy((void *)tmp_iv, (void *)iv, AES_BLOCK_SIZE);

    for (unsigned int index = 0; index < (unsigned int)padding; index++) {
        data_bak[data_len + index] = (char)padding;
    }

    // AES_cbc_encrypt() 在加密的过程中会修改 iv 的内容,因此 iv 参数不能是一个常量, 而且不能在传递给加密函数后再立马传递给解密函数,必须重新赋值之后再传递给解密函数。
    for (unsigned int index = 0; index < data_bak_len / (AES_BLOCK_SIZE); index++) {
        AES_cbc_encrypt((const unsigned char*)(data_bak + index * AES_BLOCK_SIZE),
                               data_encrypted + index * AES_BLOCK_SIZE, AES_BLOCK_SIZE,
                               &aes_key,
                               tmp_iv,
                               AES_ENCRYPT);
    }

    *out_encrypted = data_encrypted;
    *out_encrypted_len = data_bak_len;


//__Success:
    xxxx_free(data_bak);


    return 0;

__Failed:
    xxxx_free(data_bak);
    xxxx_free(data_encrypted);

    return -1;

}


/*****************************************************************

    aes解密(cbc模式)

    注: password_byte_len 为16字节表示 aes128
        password_byte_len 为32字节表示 aes256

    参数 : password, 输入参数, 密码
           password_byte_len, 输入参数, 密码字节个数
           iv, 输入参数, 向量
           iv_byte_len, 输入参数, 向量字节个数
           encrypted, 输入参数, 密文
           encrypted_len, 输入参数, 密文字节个数
           out_data, 输出参数, 原文
           out_data_len, 输出参数, 原文字节个数

     return :  0, 成功
              -1, 失败

*****************************************************************/
static int _aes_cbc_decrypt(const unsigned char *password, unsigned int password_byte_len, const unsigned char *iv, unsigned int iv_byte_len, const unsigned char *encrypted, unsigned int encrypted_len, unsigned char **out_data, unsigned int *out_data_len)
{
    unsigned char tmp_iv[AES_BLOCK_SIZE] = {'\0'};;
    unsigned char *data_bak = NULL;
    char padding = '\0';
    AES_KEY aes_key;

    if (NULL == password || 0 >= password_byte_len
        || NULL == iv || AES_BLOCK_SIZE != iv_byte_len
        || NULL == encrypted || 0 >= encrypted_len || 0 != encrypted_len % (AES_BLOCK_SIZE)
        || NULL == out_data || NULL == out_data_len
       )
    {
        xxxx_print_ln(xxxx_ERROR, "wrong parameter.");
        return -1;
    }

    if (AES_set_decrypt_key(password, password_byte_len * 8, &aes_key) < 0) {
        xxxx_print_ln(xxxx_ERROR, "AES_set_decrypt_key Failed.");
        return -1;
    }

    data_bak = (unsigned char *)calloc(1, encrypted_len);
    if (NULL == data_bak) {
        xxxx_print_ln(xxxx_ERROR, "malloc Failed(size=%u).", encrypted_len);
        goto __Failed;
    }

    memcpy((void *)tmp_iv, (void *)iv, AES_BLOCK_SIZE);

    for (unsigned int index = 0; index < encrypted_len / AES_BLOCK_SIZE; index++) {
        AES_cbc_encrypt((const unsigned char*)(encrypted + index * AES_BLOCK_SIZE),
                       data_bak + index * AES_BLOCK_SIZE, AES_BLOCK_SIZE,
                       &aes_key,
                       tmp_iv,
                       AES_DECRYPT);
    }

    // 去除 PKCS7Padding
    padding = data_bak[encrypted_len - 1];
    if (0 >= padding || 16 < padding) {
        xxxx_print_ln(xxxx_ERROR, "wrong padding227(padding=0x%02x).", padding);
        goto __Failed;
    }

    for (unsigned int index = 0; index < (unsigned int)padding; index++) {
        if (data_bak[encrypted_len - padding + index] != padding) {
            xxxx_print_ln(xxxx_ERROR, "wrong padding233(padding=%02X).", padding);
            goto __Failed;
        } else {
            data_bak[encrypted_len - padding + index] = '\0';
        }
    }

    *out_data = data_bak;
    *out_data_len = encrypted_len - padding;

//__Success:

    return 0;

__Failed:
    xxxx_free(data_bak);

    return -1;
}


/*****************************************************************

    aes加密(cbc模式)

    注: password_byte_len 为16字节表示 aes128
        password_byte_len 为32字节表示 aes256

    参数 : password, 输入参数, 密码
           password_byte_len, 输入参数, 密码字节个数
           iv, 输入参数, 向量
           iv_byte_len, 输入参数, 向量字节个数
           data, 输入参数, 待加密数据
           data_len, 输入参数, 待加密数据字节个数

     return : 长度>0, 成功, 返回加密后的密文的 base64 字符串
              长度=0, 失败

*****************************************************************/
string UTIL_aes_cbc_encrypt(const unsigned char *password, unsigned int password_byte_len, const unsigned char *iv, unsigned int iv_byte_len, const unsigned char *data, unsigned int data_len)
{
    unsigned char *encrypted_out = NULL;
    unsigned int encrypted_len = 0;
    int ret = 0;
    string encrypted_base64 = "";

    if (NULL == password || 0 >= password_byte_len
        || NULL == iv || AES_BLOCK_SIZE != iv_byte_len
        || NULL == data || 0 >= data_len
       )
    {
        xxxx_print_ln(xxxx_ERROR, "wrong parameter.");
        return "";
    }

    ret = _aes_cbc_encrypt(password, password_byte_len, iv, iv_byte_len, data, data_len, &encrypted_out, &encrypted_len);
    if (0 != ret) {
        return "";
    }

    string hex = hex_2_string(encrypted_out, encrypted_len);

#if DEBUG_AESUTIL
    xxxx_print_ln(xxxx_DEBUG, "UTIL_aes_cbc_encrypt encrypted_len=%u|%lu|%s|", encrypted_len, hex.length(), hex.c_str());
#endif

    encrypted_base64 = UTIL_base64_encode((const unsigned char *)encrypted_out, encrypted_len);

    xxxx_free(encrypted_out);

    return encrypted_base64;
}


/*****************************************************************

    aes解密(cbc模式)

    注: password_byte_len 为16字节表示 aes128
        password_byte_len 为32字节表示 aes256

    参数 : password, 输入参数, 密码
           password_byte_len, 输入参数, 密码字节个数
           iv, 输入参数, 向量
           iv_byte_len, 输入参数, 向量字节个数
           encrypted_base64str, 输入参数, 密文的 base64 字符串
           out_data, 输出参数, 原文
           out_data_len, 输出参数, 原文字节个数

     return :  0, 成功
              -1, 失败

*****************************************************************/
int UTIL_aes_cbc_decrypt(const unsigned char *password, unsigned int password_byte_len, const unsigned char *iv, unsigned int iv_byte_len, string encrypted_base64str, unsigned char **out_data, unsigned int *out_data_len)
{
    unsigned char *encrypted = NULL;
    unsigned int encrypted_len = 0;
    int ret = 0;

    if (NULL == password || 0 >= password_byte_len
        || NULL == iv || AES_BLOCK_SIZE != iv_byte_len
        || 0 >= encrypted_base64str.length()
        || NULL == out_data || NULL == out_data_len
       )
    {
        xxxx_print_ln(xxxx_ERROR, "wrong parameter.");
        return -1;
    }

    ret = UTIL_base64_decode(encrypted_base64str, &encrypted, &encrypted_len);
    if (0 != ret) {
        xxxx_print_ln(xxxx_ERROR, "base64_decode() failed.");
        return -1;
    }

    string hex = hex_2_string(encrypted, encrypted_len);

#if DEBUG_AESUTIL
    xxxx_print_ln(xxxx_DEBUG, "UTIL_aes_cbc_encrypt encrypted_len=%u|%lu|%s|", encrypted_len, hex.length(), hex.c_str());
#endif

    ret = _aes_cbc_decrypt(password, password_byte_len, iv, iv_byte_len, encrypted, encrypted_len, out_data, out_data_len);

    xxxx_free(encrypted);

    return ret;
}

#if DEBUG_AESUTIL
int test1()
{
    unsigned char *out_data = NULL;
    unsigned int out_data_len = 0;
    string str = "1234567812345678sunday i CommING, I wanna dry my 卡, thanks";
    const char *key = "12345678123456781234567812345678";
    const char *iv = "1234567812345678";


    xxxx_print_ln(xxxx_DEBUG, "str(origin):%lu|%s|", str.length(), str.c_str());

    string encrypted_base64 = UTIL_aes_cbc_encrypt((const unsigned char *)key, strlen(key), (const unsigned char *)iv, strlen(iv), (const unsigned char *)str.c_str(), str.length());
    xxxx_print_ln(xxxx_DEBUG, "encrypted_base64=%s|", encrypted_base64.c_str());
    if (0 >= encrypted_base64.length()) {
        xxxx_print_ln(xxxx_ERROR, "Encrypt Failed.");
        return -1;
    }

    if (0 == UTIL_aes_cbc_decrypt((const unsigned char *)key, strlen(key), (const unsigned char *)iv, strlen(iv), encrypted_base64, &out_data, &out_data_len)) {
        //解密后的结果
        xxxx_print_ln(xxxx_INFO, "Decrypt Success: %d|%s|", out_data_len, out_data);
    } else {
        xxxx_print_ln(xxxx_ERROR, "Decrypt Failed.");
    }

    xxxx_free(out_data);

    return 0;
}

int main()
{
    test1();


    return 0;
}
#endif
g++ Base64Util.cpp AesUtil.cpp -lcrypto

 



标签:CBC,AES,xxxx,encrypted,OpenSSL,len,unsigned,iv,data
From: https://blog.51cto.com/u_3078781/8628183

相关文章

  • C++使用OpenSSL实现Base64编码、解码实例----亲测OK
    摘自:https://www.dandelioncloud.cn/article/details/1498198300963708930 //Base64Util.h#ifndef__BASE64_UTIL_H__#define__BASE64_UTIL_H__#ifdef__cplusplus//告诉编译器,这部分代码按C语言的格式进行编译,而不是C++的extern"C"{#endifstringUTIL......
  • C++ CryptoPP使用AES加解密
    Crypto++(CryptoPP)是一个用于密码学和加密的C++库。它是一个开源项目,提供了大量的密码学算法和功能,包括对称加密、非对称加密、哈希函数、消息认证码(MAC)、数字签名等。Crypto++的目标是提供高性能和可靠的密码学工具,以满足软件开发中对安全性的需求。高级加密标准(Advanc......
  • nginx依赖包:pcre、zlib、OpenSSL、gd-devel
    学习自:《nginx经典教程》13页1、问题来源在安装nginx时,有一步需要安装依赖包:sudoyuminstallgcc-c++pcrepcre-develzlibzlib-developensslopenssl-devel这一段是啥意思,这些包有什么用?2、依赖包gcc-c++configure脚本中使用的C编译器为cc。该依赖包为C编译器......
  • AES加密
    AES加密高级加密标准(AES,AdvancedEncryptionStandard)是一种对称密钥加密算法,用于保护敏感信息。它取代了原先的数据加密标准(DES),因为DES已经不再被认为足够安全密钥是AES算法实现加密和解密的根本,对称加密对明文的加密和解密需要使用同一个密钥AES支持三种长度的密钥:128位,192位......
  • Base64编码、解码 C语言例子(使用OpenSSL库)
    #include<stdio.h>#include<string.h>#include<unistd.h>#include<openssl/pem.h>#include<openssl/bio.h>#include<openssl/evp.h>intbase64_encode(char*in_str,intin_len,char*out_str){BIO*b64,*bio;......
  • DASCTF X CBCTF 2023 yet another sandbox
    本来想直接复现昨天的DASCTF,但是前面的一个DASCTF已经开始看了,那就放到下次再写。yetanothersandboxjs沙箱逃逸。下载复现获得一个c写的readflag,有个js的模块文件app.mjs:importexpressfrom'express';importpathfrom'path';const__dirname=path.resolve();......
  • php mcrypt转openssl
    由于新版本的php不支持mcrypt,改成支持openssl 所以记一下常用函数的改变1mcrypt_get_block_size($this->mcrypt,$this->mode);改成了openssl_cipher_iv_length("aes-256-cbc")//aes-256-cbc是加密算法openssl_cipher_iv_length("aes-256-cbc")是一个函数调用,用于获取AES-......
  • 20232303 关于OpenSSL的学习
    关于OpenSSL的学习sm2加密解密请忽略原来遗留下的文件,它们与本任务无关,只看新生成的文件就好。问题与解答-opensslecparam-nameSM2-genkey-outsm2-key.pem这是一个使用OpenSSL工具生成SM2密钥的命令。opensslecparam是OpenSSL的椭圆曲线操作命令。-name......
  • c# AES 解密 快手店铺 java的AES加密方法
    JAVA版本的解密:/***参数说明:*message:带解密的密文*privateKey:加密密钥**/StringdecodeMessage=PlatformEventSecurityUtil.decode(message,privateKey);/***方法详情**/privatestaticfinalStringCIPHER_ALGORITHM="AES/CBC/PKCS5Padding"......
  • C++使用OpenSSL实现AES-256-CBC加密解密实例----亲测OK
    摘自:https://blog.csdn.net/GerZhouGengCheng/article/details/106103039//AesUtil.h#ifndef__AES_UTIL_H__#define__AES_UTIL_H__#ifdef__cplusplus//告诉编译器,这部分代码按C语言的格式进行编译,而不是C++的extern"C"{#endifstringUTIL_aes_cbc_e......