用 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;
}