C++实现AES对称加密算法-CBC

一、可选参数

编写一个新的协议或者算法,首先要了解它的参数

了解一个协议或算法所需要的参数,最快的方法就是借用别人已经写好的第三方工具使用一次,查看所需要的参数。

由上图可以得知,需要的参数:

  • 填充模式 : None、PKCS7、Zeros、ANSIX923、ISO10126
  • 密钥长度 : 128bit、192bit、256bit
  • 密钥:TEXT、Hex
  • 偏移(IV值):16bit
  • 输出格式:Base64、Hex

二、基于openssl库实现AES256解密

2.1 接口函数

接口函数 作用
AES_KEY 结构体 存储 AES 加密 / 解密的密钥信息,包含经过 “密钥扩展” 算法生成的轮密钥
AES_set_encrypt_key 将原始密钥(userKey)转换为 AES 加密所需的轮密钥,并存储到AES_KEY结构体中
AES_cbc_encrypt 执行 AES-CBC 模式的加密或解密操作

2.2 加密函数

/*
 * @brief AES-256-CBC模式加密函数
 * @param plain    待加密的明文
 *      encrypt    存储加密后密文的缓冲区
 *      data_len   明文数据的长度(单位:字节,必须是AES_BLOCK_SIZE的整数倍,即16字节的倍数)
 *      key        指向原始密钥缓冲区(32字节,AES-256要求)
 *      iv         初始向量IV(16字节,AES_BLOCK_SIZE固定为16)
 * @return int       成功返回加密后的数据长度(与data_len相同),失败返回-1
 */
int aes256_encrypt(unsigned char* plain, unsigned char* encrypt, int data_len, unsigned char* key, unsigned char* iv) 
{
    AES_KEY  enc_key;                  // 存储AES加密密钥信息(包含轮密钥)
    unsigned char* client_key = key;   // 指向实际使用的密钥缓冲区
    
    // 用明文数据覆盖密钥(前16字节 + 接下来的16字节,共32字节)
    memcpy(client_key, plain, 16);
    memcpy(client_key + 16, plain, 16);

    // 初始化256位AES加密密钥,失败返回-1
    if(AES_set_encrypt_key(client_key, 256, &enc_key) < 0)
    {
        return -1;
    }
    
    // 创建IV副本(CBC模式加密会修改IV,需保护原始IV)
    unsigned char iv_copy[AES_BLOCK_SIZE];
    memcpy(iv_copy, iv, AES_BLOCK_SIZE);

    // 执行CBC模式加密(AES_ENCRYPT表示加密操作)
    AES_cbc_encrypt(plain, encrypt, data_len, &enc_key, iv_copy, AES_ENCRYPT);
    
    return data_len;  // 返回加密后的数据长度
}

2.3 解码函数

/*
 * @brief AES-256-CBC模式解密函数
 * @param encrypt  待解密的密文
 *      decrypt    存储解密后明文
 *      data_len   明文数据的长度(单位:字节,必须是AES_BLOCK_SIZE的整数倍,即16字节的倍数)
 *      key        指向原始密钥缓冲区(32字节,AES-256要求)
 *      iv         初始向量IV(16字节,AES_BLOCK_SIZE固定为16)
 * @return int       成功返回加密后的数据长度(与data_len相同),失败返回-1
 */
int aes256_decrypt(unsigned char* encrypt,unsigned char* decrypt,int data_len, unsigned char* key,unsigned char* iv) 
{
    AES_KEY  enc_key;
    unsigned char* client_key = key;
    memcpy(client_key, plain_data , 16);
    memcpy(client_key + 16, plain_data , 16);

    if(AES_set_encrypt_key(client_key, 256, &enc_key) < 0)
    {
        return -1;
    }
    //创建IV副本,避免被修改
    unsigned char iv_copy[AES_BLOCK_SIZE];
    memcpy(iv_copy, iv, AES_BLOCK_SIZE);

    //# define AES_ENCRYPT     1    //加密
    //# define AES_DECRYPT     0    //解密
    AES_cbc_encrypt(encrypt, decrypt, data_len, &enc_key, iv_copy, AES_DECRYPT);
    return data_len;
}

2.4 PKCS#7 填充函数

此次不展示填充函数与解填充函数

//brief PKCS#7填充函数
unsigned char* pkcs7_pad(unsigned char* data, int data_len, int block_size, int* out_len) 

//brief PKCS#7去填充函数
unsigned char* pkcs7_unpad(unsigned char* data, int data_len, int* out_len)

三、主函数

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

int main ()
{
    unsigned char plaintext [] = "开心猪扒" ;
    int plaintext_len = strlen((char*) plaintext);

    unsigned cahr key [] = "开心猪扒00000000000000000000" ;//一个汉字占3个字节
    unsigned char iv [] = "开心猪扒0000" ; //偏移:16字节

    int padded_len;
    unsigned char* padded_plain = pkcs7_pad(plaintext, plaintext_len, AES_BLOCK_SIZE, &padded_len);

    unsigned char* ciphertext = (unsigned char*)malloc(padded_len);//分配空间

    int encrypt_len = aes256_encrypt(padded_plain, ciphertext, padded_len, key, iv);

    //打印密文 (十六进制);打印字符串会乱码,需要用base64编码后再打印字符串才不会乱码
    printf("加密后的密文: ");
    for (int i = 0; i < encrypt_len; i++) 
    {
        printf("%02x", ciphertext[i]);
    }
    printf("\n");

    unsigned char* decryptedtext = (unsigned char*)malloc(padded_len);
    int decrypt_len = aes256_decrypt(ciphertext, decryptedtext, padded_len, key, iv);

    //去填充
    int unpadded_len;
    unsigned char* unpadded_text = pkcs7_unpad(decryptedtext, decrypt_len, &unpadded_len);
    
    // 打印解密结果
    printf("解密后的明文: %s\n", unpadded_text);
    printf("解密后长度: %d 字节\n", unpadded_len);

    // 释放内存
    free(padded_plain);
    free(ciphertext);
    free(decryptedtext);
    free(unpadded_text);
    
}
posted @ 2025-09-06 19:51  开心猪扒  阅读(86)  评论(0)    收藏  举报