用 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;
}
相关推荐
GalaxyPokemon4 分钟前
LeetCode - 76. 最小覆盖子串
运维·服务器·数据结构·算法·leetcode
嵌入式@秋刀鱼7 分钟前
《 第三章-招式初成》 C++修炼生涯笔记(基础篇)程序流程结构
linux·开发语言·数据结构·c++·笔记·visual studio code
HaiQinyanAN18 分钟前
【学习笔记】重载和重写的注意事项
c++·笔记·学习
手握风云-19 分钟前
动态规划算法的欢乐密码(二):路径问题
算法·动态规划
西北大程序猿1 小时前
服务器代码知识点补充
服务器·开发语言·网络·c++·网络协议
Raven100861 小时前
L1G2-OpenCompass 评测书生大模型实践
算法
NAGNIP1 小时前
RAG信息检索-如何让模型找到‘对的知识’
算法
打不了嗝 ᥬ᭄2 小时前
进程控制
linux·运维·服务器·c++
yxc_inspire3 小时前
基于Qt的app开发第十四天
前端·c++·qt·app·面向对象·qss
电院工程师3 小时前
轻量级密码算法CHAM的python实现
python·嵌入式硬件·算法·安全·密码学