当前位置: 首页 > news >正文

填坑:VC++ 采用OpenSSL 3.0接口方式生成RSA密钥

文章目录

    • 填坑:VC++ 采用OpenSSL 3.0接口方式生成RSA密钥
      • 一些变化
      • 关键修改点和解释:
      • 编译和运行:
      • 小结

填坑:VC++ 采用OpenSSL 3.0接口方式生成RSA密钥

上一篇博客VC++ 使用OpenSSL创建RSA密钥PEM文件埋了点雷,还是要填掉的,借助现在强大的AI工具,也帮了不少忙,于是把修改的内容记录下来。

一些变化

首先,OpenSSL 3.0引入了一些重要的API变更,主要是为了更好的模块化和安全性,比如:

  1. Provider (提供者) 机制:这是最大的变化之一。算法实现现在通过"提供者"加载,而不是全局加载。
  2. RSA_generate_key_ex 的替代:在某些情况下,EVP_PKEY_keygen_initEVP_PKEY_keygen 及其相关函数是更现代和推荐的密钥生成方式。虽然 RSA_generate_key_ex 仍然可用,但使用 EVP 接口更符合 OpenSSL 3.0 的设计哲学。
  3. PEM 文件写入函数PEM_write_bio_RSAPrivateKeyPEM_write_bio_RSA_PUBKEY 仍然可用,但在 EVP 框架下,更推荐使用 PEM_write_bio_PKCS8PrivateKeyPEM_write_bio_PUBKEYPKCS8 是更现代的私钥存储格式,可以包含更多元数据并支持多种加密算法。
  4. 初始化函数OpenSSL_add_all_algorithms()ERR_load_crypto_strings() 等函数在 OpenSSL 3.0 中仍然存在,但更推荐使用 OPENSSL_init_crypto() 来进行更精细的控制。
  5. 错误处理ERR_print_errors_fp 依然有效。

为适配 OpenSSL 3.0,我主要使用了 EVP 接口进行密钥生成和 PKCS8 格式存储私钥:

#include <iostream>
#include <string>
#include <fstream>
#include <vector>// OpenSSL 头文件
#include <openssl/rsa.h> // 仍然需要,因为 RSA 结构可能在内部被使用
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/evp.h> // EVP 接口// 辅助函数:显示OpenSSL错误
void printOpenSSLError(const std::string& msg) {std::cerr << msg << std::endl;ERR_print_errors_fp(stderr);
}// 生成RSA密钥对并保存到PEM文件 (适配 OpenSSL 3.0)
bool generateRSAKeyPair(const std::string& privateKeyFile, const std::string& publicKeyFile, int bits = 2048) {EVP_PKEY_CTX* pctx = NULL; // EVP_PKEY context for key generationEVP_PKEY* pkey = NULL;     // EVP_PKEY for the generated key pairBIO* bp_public = NULL;BIO* bp_private = NULL;int ret = 0; // 返回值// 写入加密的私钥,需要密码const char* password = "mypassword"; // 替换为你的密码,或者在实际应用中动态获取// 1. 创建 EVP_PKEY_CTX 用于 RSA 密钥生成// 使用 EVP_PKEY_RSA 来指定生成 RSA 密钥pctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); // 或者 EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);if (!pctx) {printOpenSSLError("Error creating EVP_PKEY_CTX");goto err;}if (EVP_PKEY_keygen_init(pctx) <= 0) {printOpenSSLError("Error initializing EVP_PKEY_keygen");goto err;}// 设置密钥位数if (EVP_PKEY_CTX_set_rsa_keygen_bits(pctx, bits) <= 0) {printOpenSSLError("Error setting RSA keygen bits");goto err;}// 可以选择设置公钥指数,例如 RSA_F4 (65537)// BIGNUM* e = BN_new();// BN_set_word(e, RSA_F4);// EVP_PKEY_CTX_set_rsa_keygen_pubexp(pctx, e);// BN_free(e); // 如果设置了,记得释放// 2. 生成 RSA 密钥对if (EVP_PKEY_keygen(pctx, &pkey) <= 0) {printOpenSSLError("Error generating RSA key pair");goto err;}std::cout << "RSA key pair generated successfully (bits: " << bits << ")." << std::endl;// 3. 保存私钥到 PEM 文件 (PKCS#8 格式,带加密)bp_private = BIO_new_file(privateKeyFile.c_str(), "w+");if (bp_private == NULL) {printOpenSSLError("Error creating private key file BIO");goto err;}// 使用 PEM_write_bio_PKCS8PrivateKey,它更通用且推荐// EVP_des_ede3_cbc() 是一个旧的加密算法,OpenSSL 3.0 推荐使用更强的算法,例如 EVP_aes_256_cbc()if (!PEM_write_bio_PKCS8PrivateKey(bp_private, pkey, EVP_aes_256_cbc(), (char*)password, strlen(password), NULL, NULL)) {printOpenSSLError("Error writing PKCS#8 private key to file");goto err;}std::cout << "Private key saved to " << privateKeyFile << " (PKCS#8 encrypted with AES-256-CBC)." << std::endl;// 4. 保存公钥到 PEM 文件bp_public = BIO_new_file(publicKeyFile.c_str(), "w+");if (bp_public == NULL) {printOpenSSLError("Error creating public key file BIO");goto err;}// 使用 PEM_write_bio_PUBKEYif (!PEM_write_bio_PUBKEY(bp_public, pkey)) {printOpenSSLError("Error writing public key to file");goto err;}std::cout << "Public key saved to " << publicKeyFile << std::endl;ret = 1; // 成功
err:// 清理资源if (bp_private != NULL) BIO_free_all(bp_private);if (bp_public != NULL) BIO_free_all(bp_public);if (pctx != NULL) EVP_PKEY_CTX_free(pctx);if (pkey != NULL) EVP_PKEY_free(pkey);return (ret == 1);
}int main() {// 1. 初始化 OpenSSL 库OpenSSL_add_all_algorithms();// 加载错误字符串,以便 ERR_print_errors_fp 可以打印有意义的信息ERR_load_crypto_strings();std::string privateKeyPath = "private_key.pem";std::string publicKeyPath = "public_key.pem";if (generateRSAKeyPair(privateKeyPath, publicKeyPath)) {std::cout << "\nRSA key pair generation and saving completed successfully." << std::endl;}else {std::cerr << "\nFailed to generate RSA key pair." << std::endl;}// 2. 清理 OpenSSL 库// 释放错误字符串ERR_free_strings();EVP_cleanup(); // 清理所有算法return 0;
}

关键修改点和解释:

  1. EVP_PKEY_CTXEVP_PKEY

    • 在 OpenSSL 3.0 中,EVP 接口是推荐的通用加密操作接口。
    • EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL) 用于创建一个用于 RSA 操作的上下文。"RSA" 是算法名称。
    • EVP_PKEY_keygen_init(pctx) 初始化密钥生成过程。
    • EVP_PKEY_CTX_set_rsa_keygen_bits(pctx, bits) 设置密钥的位数,与 RSA_generate_key_ex 中的 bits 参数功能相同。
    • EVP_PKEY_keygen(pctx, &pkey) 执行密钥生成,并将结果存储在 EVP_PKEY* pkey 中。这个 pkey 对象包含了公钥和私钥信息。
  2. 私钥保存 (PKCS#8)

    • PEM_write_bio_PKCS8PrivateKey 用于将私钥以 PKCS#8 格式写入 PEM 文件。PKCS#8 是一个更现代、更灵活的私钥存储标准,它本身可以包含加密信息。
    • 我将加密算法从 EVP_des_ede3_cbc() 改为 EVP_aes_256_cbc(),因为 DES-EDE3-CBC (即 Triple DES) 在现代标准下已不推荐,AES-256-CBC 更安全。
    • PKCS#8 格式的私钥通常以 -----BEGIN ENCRYPTED PRIVATE KEY----- 开头,而不是 -----BEGIN RSA PRIVATE KEY-----
  3. 公钥保存

    • PEM_write_bio_PUBKEY 用于将公钥写入 PEM 文件。它会写入标准的 -----BEGIN PUBLIC KEY----- 格式,该格式是基于 EVP_PKEY 结构的。
  4. 错误处理

    • ERR_print_errors_fp 仍然是打印 OpenSSL 错误的标准方式。

编译和运行:

  1. 头文件和库文件:确保你的编译器能够找到 OpenSSL 3.0 的头文件 (-I 参数) 和库文件 (-L 参数,以及 -l 参数链接 libcryptolibssl)。
  2. Windows 用户:对于在 Windows 上使用 MSVC 编译,你可能需要包含 openssl/applink.c 或者在链接时处理一些特定的库。我的代码中已经添加了 #include <openssl/applink.c>,这通常能解决控制台应用程序的一些问题。
  3. 链接库
    • Linux/macOS: g++ your_code.cpp -o your_app -I/path/to/openssl/include -L/path/to/openssl/lib -lcrypto
    • Windows (MinGW/MSYS2): g++ your_code.cpp -o your_app -I<openssl_dir>/include -L<openssl_dir>/lib -lssl -lcrypto -Wl,--start-group -lws2_32 -lgdi32 -lcrypt32 -Wl,--end-group (具体依赖可能因你的 OpenSSL 安装方式而异)
    • Windows (MSVC): 需要在项目属性中配置包含目录、库目录,并链接 libcrypto.liblibssl.lib (或者 crypt32.lib, ws2_32.lib 等)。

这个修改后的版本遵循 OpenSSL 3.0 的现代实践,提供了更好的模块化和对新算法的支持。

小结

至此,我们填掉了之前warning: 4996的坑,从 EVP_des_ede3_cbc() 改为 EVP_aes_256_cbc()也体现到了私钥PEM文件里:

运行截图
在这里插入图片描述

http://www.dtcms.com/a/419309.html

相关文章:

  • 郑州做网站的网站再就业技能培训班
  • Vscode 连接服务时候一直出现setting ssh Host server
  • 全面解析数据库审批平台:主流工具对比与选型指南
  • 【Docker项目实战】使用Docker部署IT运维管理平台CAT
  • spring事务传播级别的实操案例2
  • 泰州专一做淘宝网站如何用html做网站头像
  • 电子商务网站设计与实现个人网站做捐赠发布违法吗
  • Java滑动窗口算法题目练习
  • 介绍一下HTTP和WebSocket的头部信息
  • Linux系统学习之---库的理解和加载(毛坯初版...)
  • 南山模板网站建设公司怎么看网站的外链
  • 企业网站策划大纲模板文山住房和城乡建设局网站
  • Linux 基础IO与系统IO
  • 【IEDA】已解决:IDEA中jdk的版本切换
  • idea推荐springboot+mybatis+分页查询插件之PageHelper
  • 南非网站域名做网站微信支付多少钱
  • 网站开发 图形验证码网站建设衤金手指下拉10
  • OPenssh6代码移植的依赖库 OpenSSL双库连接问题的解决方案
  • 商务网站建设组成包括网站优化wordpress 换行
  • tiktok scheme
  • Xrdp 远程桌面配置【笔记】
  • 【Linux】倒计时和进度条实现
  • 网站建设需要用到哪些软件有哪些系统安装wordpress
  • 梯度下降(Gradient Descent)
  • 东莞市建设规划局网站游戏类企业网站模板
  • C++---bind(绑定函数或函数对象的参数)
  • 网站和域名网站开发技术是什么
  • 个人如何开网站西安网络推广外包公司
  • 国产处理器飞腾CPU各系列综合性能对比
  • 南宁网站设计推广wordpress+授权登录