用 OpenSSL 库实现 3DES(三重DES)加密

用 OpenSSL 库实现 3DES(三重DES)加密操作。以下是代码的详细解析:

1. 包含头文件和命名空间:

cpp 复制代码
#include <iostream>
#include <openssl/evp.h>
#include <openssl/err.h>
  • #include : 引入 C++ 标准库,用于输入输出操作。
  • #include <openssl/evp.h>: 引入 OpenSSL 的 EVP (Envelope) API,这是 OpenSSL 提供的高级加解密接口。
  • #include <openssl/err.h>: 引入 OpenSSL 错误处理头文件,用于打印 OpenSSL 错误。

2. 定义 main 函数并初始化数据:

cpp 复制代码
int main(int argc, char *argv[])
{
    const unsigned char data[] = "1234567812345678"; // 输入
    int data_size = sizeof(data) - 1;                // 计算数据长度,不包括'\0'
    cout << "data_size = " << data_size << endl;
  • data[]: 需要加密的输入数据(字符串 "1234567812345678")。
  • data_size: 计算数据长度,这里使用 sizeof(data) - 1,因为 sizeof(data) 会包括末尾的 '\0' 字符,因此需要减去 1。

3. 定义加密参数:

cpp 复制代码
unsigned char out[1024] = {0};                      // 输出
unsigned char key[] = "123456789012345678901234"; // 24 字节的密钥(3DES)
unsigned char iv[8] = {0};                          // 8 字节的初始化向量(IV)
  • out[]: 用来存储加密后的输出数据。
  • key[]: 3DES 使用的密钥,3DES 算法需要 24 字节的密钥。此处密钥被设置为 - "123456789012345678901234",总长度为 24 字节。
  • iv[]: 初始化向量(IV),用于加密过程中的随机化,长度为 8 字节。

4. 选择加密算法和打印加密参数:

cpp 复制代码
// 三重DES 3DES 算法
auto cipher = EVP_des_ede3_cbc();
// 获取算法的分组大小
int block_size = EVP_CIPHER_block_size(cipher);
int key_size = EVP_CIPHER_key_length(cipher);
int iv_size = EVP_CIPHER_iv_length(cipher);
cout << "block_size = " << block_size << endl;
cout << "key_size = " << key_size << endl;
cout << "iv_size = " << iv_size << endl;
  • EVP_des_ede3_cbc(): 使用 OpenSSL 的 EVP API 来选择三重 DES(3DES)加密算法,这里使用的是 3DES 的 CBC 模式(密码分组链接模式)。
  • EVP_CIPHER_block_size(cipher): 获取加密算法的分组大小(即块大小)。对于 3DES,块大小为 8 字节。
  • EVP_CIPHER_key_length(cipher): 获取密钥的长度。对于 3DES,密钥长度为 24 字节。
  • EVP_CIPHER_iv_length(cipher): 获取 IV(初始化向量)的长度。对于 3DES,IV 长度为 8 字节。

5. 初始化加解密上下文并开始加密:

cpp 复制代码
// 加解密上下文
auto ctx = EVP_CIPHER_CTX_new();
// 加密算法初始化


int re = EVP_CipherInit_ex(ctx, cipher, nullptr, key, iv, 1); // 1表示加密
if (!re)
{
    ERR_print_errors_fp(stderr);
    getchar();
    return -1;
}
cout << "EVP_CipherInit success!" << endl;
  • EVP_CIPHER_CTX_new(): 创建一个新的加解密上下文,用于存储加解密的状态。
  • EVP_CipherInit_ex(ctx, cipher, nullptr, key, iv, 1): 初始化加解密上下文,传入所选择的加密算法、密钥、初始化向量和加密模式。这里的 1 表示加密模式(解密时应该传 0)。如果初始化失败,程序会打印错误信息并退出。

6. 设置填充方式:

cpp 复制代码
 // 设置填充方式(默认是 PKCS7)
    EVP_CIPHER_CTX_set_padding(ctx, EVP_PADDING_PKCS7);
  • EVP_CIPHER_CTX_set_padding(ctx, EVP_PADDING_PKCS7): 设置加密过程中的填充方式。默认使用 PKCS7 填充方式,即使加密数据不是块大小的整数倍,也会进行填充,使其对齐到块大小。

7. 执行加密操作:

cpp 复制代码
int out_size = 0;
EVP_CipherUpdate(ctx, out, &out_size, data, data_size);
cout << "EVP_CipherUpdate size: " << out_size << endl;
  • EVP_CipherUpdate(ctx, out, &out_size, data, data_size): 进行加密操作,将输入数据 data 加密后写入 out 中,out_size 存储实际加密后的字节数。

8. 处理最后的填充块:

cpp 复制代码
  int padding_size = 0;
    EVP_CipherFinal_ex(ctx, out + out_size, &padding_size);
    cout << "padding_size = " << padding_size << endl;
    out_size += padding_size;
  • EVP_CipherFinal_ex(ctx, out + out_size, &padding_size): 获取加密结果的最后一块数据(如果有填充)。填充是为了保证加密数据大小是块大小的整数倍。
  • padding_size: 返回填充数据的大小。将其加到 out_size 中,得到总的加密数据大小。

9. 打印加密后的数据:

cpp 复制代码
   cout << "Encrypted data: ";
    for (int i = 0; i < out_size; ++i)
    {
        printf("%02x", out[i]); // 以十六进制打印每个字节
    }
    cout << endl;
  • 打印加密后的数据。由于输出的是字节数据,直接打印可能显示为乱码,因此使用 printf("%02x", out[i]) 以十六进制格式打印每个字节。

10. 释放上下文并结束程序:

cpp 复制代码
   // 释放上下文
    EVP_CIPHER_CTX_free(ctx);
    getchar();
    return 0;
}
  • EVP_CIPHER_CTX_free(ctx): 释放加解密上下文,以避免内存泄漏。
  • getchar(): 用于暂停程序,等待用户输入,便于查看加密结果。

总结:

该程序使用 OpenSSL 库的 EVP API 对数据进行 3DES 加密,使用 CBC 模式。通过初始化密钥、初始化向量(IV)和加密上下文来执行加密,并处理填充。最后,程序以十六进制格式打印加密后的数据。

完整代码

cpp 复制代码
#include <iostream>
#include <openssl/evp.h>
#include <openssl/err.h>

// _CRT_SECURE_NO_WARNINGS
// #include <openssl/applink.c>
using namespace std;

int main(int argc, char *argv[])
{
    const unsigned char data[] = "1234567812345678"; // 输入
    int data_size = sizeof(data) - 1;                // 计算数据长度,不包括'\0'
    cout << "data_size = " << data_size << endl;

    unsigned char out[1024] = {0};                    // 输出
    unsigned char key[] = "123456789012345678901234"; // 24 字节的密钥(3DES)
    unsigned char iv[8] = {0};                        // 8 字节的初始化向量(IV)

    // 三重DES 3DES 算法
    auto cipher = EVP_des_ede3_cbc();

    // 获取算法的分组大小
    int block_size = EVP_CIPHER_block_size(cipher);
    int key_size = EVP_CIPHER_key_length(cipher);
    int iv_size = EVP_CIPHER_iv_length(cipher);
    cout << "block_size = " << block_size << endl;
    cout << "key_size = " << key_size << endl;
    cout << "iv_size = " << iv_size << endl;

    // 加解密上下文
    auto ctx = EVP_CIPHER_CTX_new();
    // 加密算法初始化
    int re = EVP_CipherInit_ex(ctx, cipher, nullptr, key, iv, 1); // 1表示加密
    if (!re)
    {
        ERR_print_errors_fp(stderr);
        getchar();
        return -1;
    }
    cout << "EVP_CipherInit success!" << endl;

    // 设置填充方式(默认是 PKCS7)
    EVP_CIPHER_CTX_set_padding(ctx, EVP_PADDING_PKCS7);
    int out_size = 0;

    // 只处理分组大小得到数据, 如果取消自动填充,多余数据丢弃
    EVP_CipherUpdate(ctx, out, &out_size, data, data_size);
    cout << "EVP_CipherUpdate size: " << out_size << endl;

    // 取出最后一块数据(需要填充的),或者是 padding 补充的数据
    int padding_size = 0;
    EVP_CipherFinal_ex(ctx, out + out_size, &padding_size);
    cout << "padding_size = " << padding_size << endl;
    out_size += padding_size;

    // 打印加密后的数据
    cout << "Encrypted data: ";
    for (int i = 0; i < out_size; ++i)
    {
        printf("%02x", out[i]); // 以十六进制打印每个字节
    }
    cout << endl;

    // 释放上下文
    EVP_CIPHER_CTX_free(ctx);

    getchar();
    return 0;
}
相关推荐
B612 little star king3 分钟前
力扣29. 两数相除题解
java·算法·leetcode
野犬寒鸦5 分钟前
力扣hot100:环形链表(快慢指针法)(141)
java·数据结构·算法·leetcode·面试·职场和发展
时光追逐者9 分钟前
C# 哈希查找算法实操
算法·c#·哈希算法
Jasmine_llq34 分钟前
《P3825 [NOI2017] 游戏》
算法·游戏·枚举法·2-sat 算法·tarjan 算法·邻接表存储
Miraitowa_cheems37 分钟前
LeetCode算法日记 - Day 38: 二叉树的锯齿形层序遍历、二叉树最大宽度
java·linux·运维·算法·leetcode·链表·职场和发展
wangzy198238 分钟前
图形基础算法:如何将点与带曲线边的多边形位置关系算法做稳定
算法
艾醒1 小时前
探索大语言模型(LLM):Ollama快速安装部署及使用(含Linux环境下离线安装)
人工智能·深度学习·算法
劲镝丶1 小时前
malloc概述
c语言·开发语言·c++
艾醒1 小时前
探索大语言模型(LLM):Open-WebUI的安装
人工智能·算法·全栈
sun03221 小时前
使用 javax.net.ssl.HttpsURLConnection 发送 HTTP 请求_以及为了JWT通信选用OSS的Jar的【坑】
http·.net·ssl