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

news/2025/9/30 12:35:42/文章来源:https://www.cnblogs.com/ljbguanli/p/19120817

填坑: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.mzph.cn/news/922839.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JUC:AQS

AbstractQueuedSynchronizer AQS重要性: Java => JVM JUC => AQS 4.11.1 前置知识公平锁和非公平锁 可重入锁 自旋思想 LockSupport 双向链表数据结构 模板设计模式4.11.2 AQS入门级理论知识AQS定义抽象的队列同…

CF1980F2 Field Division (hard version) 题解

Sol 注意到如果允许走没有限制边境的点答案一定不变,所以只考虑修改在边境上的点即可。 然后再注意到一个点边境上的点如果变成可通信的,那么每个不在边境上的点只会变成了边境上的点至多 \(2\) 次。 所以暴力即可。…

JUC:ThreadLocal

4.8 ThreadLocal 线程局部变量。 4.8.1 常见面试题ThreadLocal中ThreadLocalMap的数据结构和关系? ThreadLocal的key是弱引用,为什么? ThreadLocal内存泄漏问题是什么? ThreadLocal中最后为什么要加remove方法?4.…

广义串并联图とP6790 [SNOI2020] 生成树

广义串并联图とP6790 [SNOI2020] 生成树 前置知识:广义串并联图 定义广义串并联图为不存在与 \(K_4\)(即 \(4\) 个点的完全图)同胚的子图的连通无向图(同胚是指可以通过边的放缩而互相转化的图,即 \((x\leftright…

Manim实现波浪形文字特效

本文将介绍如何使用Manim实现波浪形文字特效,通过自定义动画类让文字产生波浪般的动态效果。 1. 实现原理 波浪形文字特效的核心是通过自定义Animation类,对文本对象中的每个字符应用不同的位置偏移,从而形成波浪效…

网站开发电子书网站ip地址 转向域名

内容简要 1分析网站 2简单爬取 3进阶自定义爬取 4保存进数据库 学校基础设施太差&#xff0c;宿舍电量过低提醒虽然贴在楼下&#xff0c;但是作为低头一族&#xff0c;经常忘记看提醒导致宿舍酣战时突然黑屏&#xff0c;为了避免这种尴尬的场景以及强化PY学习&#xff0c;我决定…

JUC: synchronized与锁升级

4.10.1 面试题谈谈你对synchronized的理解 synchronized的锁升级机制是什么? 偏向锁和轻量锁有什么区别?高并发时,同步调用应该去考量锁的性能损耗。能用无锁的数据结构,就不要用锁。能用锁块,就不要锁整个方法体…

cron表达式,每月1号凌晨3点执行和每周4凌晨3点半执行

cron表达式,每月1号凌晨3点执行和每周4凌晨3点半执行cron表达式,每月1号凌晨3点执行和每周4凌晨3点半执行 1.每月1号凌晨3点执行的Cron表达式为:0 0 3 1 * ? 每个月1号 凌晨3点   0 0 3 1 * ? 和 0 0 3 1 …

学python的第8天

学python的第8天字符编码 水导链接——字符编码 水导链接——Python2和3字符编码的区别 文件基本操作 从硬盘中读取数据、写入数据 水导链接——文件基本操作 绝对路径和相对路径 水导链接——绝对路径和相对路径 文件…

2025.9.30

坐火车回家

lang / philipino / feilvbin / taglog / tajialu

s菲语 翻译magandang tanghali 下午好end

C#/.NET/.NET Core技术前沿周刊 | 第 56 期(2025年9.22-9.28)

前言 C#/.NET/.NET Core技术前沿周刊,你的每周技术指南针!记录、追踪C#/.NET/.NET Core领域、生态的每周最新、最实用、最有价值的技术文章、社区动态、优质项目和学习资源等。让你时刻站在技术前沿,助力技术成长与…

漳州做网站建设的公司做网站 赚广告费

作为当下大语言模型的典型代表&#xff0c;ChatGPT对人类学习方式和教育发展所产生的变革效应已然引起了广泛关注。技术的快速发展在某种程度上正在“倒逼”教育领域开启更深层次的变革。在此背景下&#xff0c;教育从业者势必要学会准确识变、科学应变、主动求变、以变应变&am…

US$249 Autek IKEY820 New License for GM, Grand Cheokee and Dodge Durango Key Programming

Autek IKEY820 New License for GM, Grand Cheokee and Dodge Durango Key ProgrammingWith this license, Autek IKEY820 can support new car models as below:1. Added 2018 Buick LaCrosse Pincode and Key Progra…

Estun机器人数据断电保持问题解决方案

Estun机器人数据断电保持问题解决方案要数据断电保持: 1.变量必须为全局变量 2.用等号做赋值运算

天津港口海鲜之旅全攻略(2025最新版)

🦀 天津港口海鲜之旅全攻略(2025最新版) 天津不仅是工业重镇,更是海鲜爱好者的天堂!每年9月开海后,正是吃海鲜、出海捕鱼的黄金时节。以下是为你整理的天津港口海鲜之旅全攻略,涵盖出海码头、海鲜购买、美食推…

tomcat创建bat启动,结合任务计划实现自动重启tomcat服务 - 详解

tomcat创建bat启动,结合任务计划实现自动重启tomcat服务 - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "C…

如何从安卓手机恢复手机照相机消失的相机照片?(6个高效办法)

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

实用指南:【论文精读】Few-Shot Object Detection with Attention-RPN and Multi-Relation Detector

实用指南:【论文精读】Few-Shot Object Detection with Attention-RPN and Multi-Relation Detectorpre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: bloc…

网站开发实战asp制作视频教程wordpress用户积分

类似问题答案我是自动化专业的学生&#xff0c;大一的时候有没有必要考计算机二级证书计算机二级 虽然不是很重要 但是考了也是有好处的 自动化的跟计算机联系非常大 二级证不怎么重要 但是C语言很重要 对于你们 希望你还是去考个二级作为学习建筑类专业的学生,如果考试计算机二…