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

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

时间:2023-11-20 12:23:34浏览次数:44  
标签:CBC AES xxxx encrypted OpenSSL len unsigned iv data

摘自:https://blog.csdn.net/GerZhouGengCheng/article/details/106103039

// 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://www.cnblogs.com/LiuYanYGZ/p/17843653.html

相关文章

  • Base64编码、解码 C语言例子(使用OpenSSL库)----亲测OK
    摘自:https://www.dandelioncloud.cn/article/details/1498198300963708930 //Base64Util.h#ifndef__BASE64_UTIL_H__#define__BASE64_UTIL_H__#ifdef__cplusplus//告诉编译器,这部分代码按C语言的格式进行编译,而不是C++的extern"C"{#endifstring......
  • openssl做HMAC实例(C++)----自测OK
    摘自:https://blog.csdn.net/mijichui2153/article/details/1047414601、HMAC简介(1)MAC(MessageAuthenticationCode,消息认证码算法),可以将其认为是含有秘钥的散列(Hash)函数算法;即兼容了MD和SHA算法,并在此基础上加上了秘钥。因此MAC算法也经常被称作HMAC算法。当然HMAC就是“基......
  • openssl做HMAC实例(C++)原文
    摘自:https://blog.csdn.net/mijichui2153/article/details/1047414601、HMAC简介(1)MAC(MessageAuthenticationCode,消息认证码算法),可以将其认为是含有秘钥的散列(Hash)函数算法;即兼容了MD和SHA算法,并在此基础上加上了秘钥。因此MAC算法也经常被称作HMAC算法。当然HMAC就是“基......
  • OpenSSL - Certificate Generation
    WewillusetheOpenSSL(https://www.openssl.org/source/)tooltogenerateself-signedcertificates.Acertificateauthority(CA)isresponsibleforstoring,signing,and issuingdigitalcertificates.Thismeanswewillfirstgenerateaprivatekeyanda......
  • openssl创建证书
    安装brewinstallopenssl使用root@MACdeMBPrem_key#opensslreq-x509-newkeyrsa:4096-keyoutkey.pem-outcert.pem-days365Generatinga4096bitRSAprivatekey....................................................................................................
  • OpenSSL学习(Secure Socket Layer)2023/11/13
    示例OpenSSL版本为OpenSSL3.0.215Mar2022(Library:OpenSSL3.0.215Mar2022)别搞错了!搞错容易在sm2签名验签出问题生成自签名证书opensslreq-x509-newkeyrsa:2048-keyoutmykey.pem-outmycert.pem-days365req:表示进行证书请求和生成。-x509:表示生成自......
  • CentOS7编译安装openssl1.1.1
    Centos7默认提供的openssl版本是1.0.2的,想要升级openssl版本则需要手动进行编译一、下载openssl1.1.1cd/usr/local/src/wget--no-check-certificatehttps://www.openssl.org/source/openssl-1.1.1d.tar.gz二、创建安装目录mkdir-p/usr/local/openssl 三、解压......
  • Node opensslErrorStack 错误解决方法记录
    从Git仓库中下载了一个老项目,使用npminstall安装后没有问题,当我使用npmrundev的时候遇到了OpenSSL相关错误,例如opensslErrorStack:['error:03000086:digitalenveloperoutines::initializationerror']网上找了一下相关信息,然后顺利解决了,记录分享给大家问题原因:这种错......
  • openssl 加密
    对称加密算法查询,显示当前环境下所有支持的算法列表。print_r(openssl_get_cipher_methods());php8.1.11的加密算法[0]=>aes-128-cbc[1]=>aes-128-cbc-hmac-sha1[2]=>aes-128-cbc-hmac-sha256[3]=>aes-128-ccm[4]=>aes-128-cfb[5]=>a......
  • Soil Erosion Maesures
    Soilerosionisaseriousenvironmentalissue.Stepsshouldbetakentocurbthisproblem.Followingaresomeofthemethodsofsoilerosionprevention: 1.IncreasevegetationcoverIncreasingvegetationcovercaneffectivelypreventsoilerosion,impro......