【C语言】使用 OpenSSL 进行 AES CBC 加密与解密

news/2024/9/29 1:18:02 标签: c语言, 开发语言

使用 OpenSSL 进行 AES CBC 加密与解密

在这篇文章中,我们将使用 OpenSSL 库实现 AES CBC 模式的加密和解密功能。AES(高级加密标准)是一种对称加密算法,广泛应用于数据保护。本示例展示了如何使用 PKCS#7 填充标准来处理明文的长度,以及如何确保在加密和解密过程中正确管理密钥和初始化向量(IV)。

代码实现

下面是实现 AES CBC 加密与解密的完整代码:

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

// PKCS#7 去除填充的函数
int pkcs7_unpad(unsigned char *data, int len) {  
    int padding = data[len - 1];  
    if (padding < 1 || padding > AES_BLOCK_SIZE) {
        return -2;  // 错误的填充
    }
    for (int i = len - padding; i < len; i++) {
        if (data[i] != padding) return -1;  // 填充不正确
    }
    return len - padding; 
}

// PKCS#7 填充函数
void pkcs7_pad(unsigned char *plaintext, int plaintext_len, int block_size) {  
    int padding = block_size - (plaintext_len % block_size);  
    memset(plaintext + plaintext_len, padding, padding);
}

// AES CBC 解密函数
int aes_cbc_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, unsigned char *iv, unsigned char *plaintext) {
    AES_KEY dec_key;  
    if (AES_set_decrypt_key(key, 256, &dec_key) < 0) {
        return -2;  // 设置解密密钥失败
    }

    int block_size = AES_BLOCK_SIZE;  
    if (ciphertext_len % block_size != 0) {
        return -3;  // 密文长度不是块大小的倍数
    }

    // 进行解密
    AES_cbc_encrypt(ciphertext, plaintext, ciphertext_len, &dec_key, iv, AES_DECRYPT);  
    int plaintext_len = pkcs7_unpad(plaintext, ciphertext_len);  
    if (plaintext_len < 0) {
        return plaintext_len;  // 填充去除失败
    }

    return plaintext_len;  
} 

// AES CBC 加密函数  
int aes_cbc_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, unsigned char *iv, unsigned char *ciphertext) {  
    AES_KEY enc_key;  
    AES_set_encrypt_key(key, 256, &enc_key);  

    int block_size = AES_BLOCK_SIZE;  
    int padding = block_size - (plaintext_len % block_size);  
    int ciphertext_len = plaintext_len + padding;  

    unsigned char plaintext2[ciphertext_len];
    memcpy(plaintext2, plaintext, plaintext_len);
    pkcs7_pad(plaintext2, plaintext_len, block_size);  

    AES_cbc_encrypt(plaintext2, ciphertext, ciphertext_len, &enc_key, iv, AES_ENCRYPT);  

    return ciphertext_len;  
}

int main() {
    // 假设的密钥和IV  
    unsigned char key[AES_BLOCK_SIZE * 2] = "your-256-bit-key-here-xxxxxxxxxx";  
    unsigned char iv[AES_BLOCK_SIZE] = "your-iv-here-xxx";  
    
    // 明文  
    unsigned char plaintext[] = "Hello,World";  
    int plaintext_len = strlen((char *)plaintext);  

    unsigned char *ciphertext_buffer = malloc(plaintext_len + AES_BLOCK_SIZE);  
    if (ciphertext_buffer == NULL) {  
        return 1;  
    }  
    
    int ret_len = aes_cbc_encrypt(plaintext, plaintext_len, key, iv, ciphertext_buffer);
    
    unsigned char iv2[AES_BLOCK_SIZE] = "your-iv-here-xxx";  
    unsigned char *plaintext_buffer2 = malloc(plaintext_len + AES_BLOCK_SIZE);  
    int code = aes_cbc_decrypt(ciphertext_buffer, ret_len, key, iv2, plaintext_buffer2);
    
    printf("Decrypted: %.*s\n", code, plaintext_buffer2);

    free(ciphertext_buffer);
    free(plaintext_buffer2);
    return 0;
}

代码分析

1. 填充与去填充

我们使用 PKCS#7 填充标准来处理明文长度。这种填充方式确保了明文的长度是块大小的倍数,便于后续的加密操作。

2. AES 加密与解密

aes_cbc_encrypt 函数负责加密明文,而 aes_cbc_decrypt 函数则负责解密密文。在这两个函数中,我们都使用了相同的密钥和初始化向量。

3. 主函数

main 函数中,我们定义了明文、密钥和 IV。我们调用加密和解密函数,并打印出解密后的结果。

总结

本文展示了如何使用 OpenSSL 实现 AES CBC 模式的加密与解密。通过合理的填充和去填充机制,我们确保了数据的完整性与安全性。在实际应用中,请确保密钥和 IV 的安全性,以防止潜在的安全风险。

补充

环境:安装OpenSSL

1. Ubuntu/Debian

打开终端,运行以下命令:

sudo apt update
sudo apt install openssl libssl-dev
2. CentOS

对于 CentOS ,可以使用以下命令:

sudo yum install openssl openssl-devel

编译

gcc -o main main.c -lcrypto

http://www.niftyadmin.cn/n/5682185.html

相关文章

使用 CMake 创建和调用动态库在 Windows 和 Ubuntu上的差异

使用 CMake 创建和调用动态库在 Windows 和 Ubuntu上的差异 确实&#xff0c;您指出的非常正确。在 Windows 平台上&#xff0c;当使用 CMake 配置和构建项目时&#xff0c;应当链接到 DLL 的导入库&#xff08;.lib 文件&#xff09;&#xff0c;而不是直接链接到 .dll 文件。…

Python面向对象学习笔记

Python面向对象学习笔记 建议大学学习代码的过程中&#xff0c;自己一步步敲一下代码&#xff0c;用代码验证所学的或者所说的&#xff0c;这样学习效果会比较好&#xff0c;同时遇到不会的&#xff0c;就去搜索查询&#xff0c;结合chatgpt更好的编程。 python创建包 demo…

Metahuman sdk官方 AI驱动口型蓝图优化

combo stream ATL stream ( audio to lip sync) 以上时实时驱动口型 非实时驱动口型可以在metahuman blueprint里直接加上talk component&#xff0c;实现聊天/回复功能。 Talk sound可以放自己的声音/ talk chat是回复你输入的message和你聊天/ talk text是念出你输入的me…

[功耗分析]wifi组播锁现象

一、摘要 虎牙app后台会申请wifi 组播锁&#xff0c;友商wifi 组播锁也没有进行管控且该设备的电流满足要求&#xff0c;故wifi 组播锁的现象维持当前现状即可 机器 虎牙直播app短待机下平均电流 MI 14 16.5618.3817.47mA Pixcel 13.8216.5615.19mA 备注 只要有 虎牙直…

目标检测论文常用评价指标(Evaluation Metrics)总结

评价指标&#xff08;Evaluation Metrics&#xff09; 混淆矩阵&#xff08;Confusion Matrix&#xff09;归一化混淆矩阵&#xff08;Normalized Confusion Matrix&#xff09;精确度&#xff08;Precision&#xff09;召回率&#xff08;Recall&#xff09;F1值&#xff08;F…

车间调度问题数学建模与CPLEX优化

完成了这些基础研究工作&#xff0c;整理成文档以供参考 序言... i 第一章 引言... 1 1.1 车间调度问题概述... 1 1.2 车间调度问题分类表示法... 5 1.3 车间调度对制造企业的作用... 6 1.4 本章小结... 7 第二章 CPLEX基础... 8 2.1 CPLEX概述... 8 2.1.1 CPLEX简介.…

【数据挖掘】2023年 Quiz 1-3 整理 带答案

目录 Quiz 1Quiz 2Quiz 3Quiz 1 Problem 1(30%). Consider the training data shown below. Here, A , B A, B A,B, and

Cpp::STL—string类的使用与理解(上)(8)

文章目录 前言一、string类对象的构造函数string()string(const char* s)string(size_t n, char c)string(const string& s)string(const string& str&#xff0c;size_t pos&#xff0c;size_t len npos) 二、string类对象的容量操作size与lengthcapacitycapacity返回…