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

VC++ 使用OpenSSL创建RSA密钥PEM文件

文章目录

    • VC++ 使用OpenSSL创建RSA密钥PEM文件
      • 准备工作
      • C++ 源代码 (`main.cpp`)
      • 编译和运行
      • 预期输出
      • PEM 文件内容示例
      • 密钥长度 (`bits` 参数)
      • 加密的私钥
      • 存在的坑

VC++ 使用OpenSSL创建RSA密钥PEM文件

某个桌面应用需要对一些文件进行签名处理,上一篇写了C#相关的一些签名与验签,因原来的历史代码是VC++开发的,也许考虑在上面做类似的工作。
目前是Vibe Coding的时代了,AI这样的助手显然也派上了用场,在AI配合下,我把开发的内容给大家分享一下。
生成的私钥截图

准备工作

1. 安装 OpenSSL

  • Windows: 可以从 OpenSSL 的官方网站或第三方网站(如 https://slproweb.com/products/Win32OpenSSL.html)下载预编译的二进制文件。安装后,记下安装路径。
  • Linux/macOS: 通常通过包管理器安装:
    • Debian/Ubuntu: sudo apt-get install libssl-dev
    • CentOS/Fedora: sudo yum install openssl-devel
    • macOS (Homebrew): brew install openssl

我的这个项目因为是用了vcpkg进行包管理(之前我的博文:VCPKG配合NuGet在项目中使用包也有过简单的描述),直接用vcpkg安装并按照开源项目的方式给MSBUILD使用就行了。参考命令如下:

vcpkg install openssl:x64-windows
vcpkg integrate install

2. Visual Studio 项目配置 (Windows)

如果你在Windows上使用Visual Studio,你需要配置项目的 “附加包含目录” 和 “附加库目录” 以及 “附加依赖项”。

  • C/C++ -> 附加包含目录:
    • C:\OpenSSL-Win64\include (替换为你的OpenSSL安装路径)
  • 链接器 -> 附加库目录:
    • C:\OpenSSL-Win64\lib (替换为你的OpenSSL安装路径)
  • 链接器 -> 输入 -> 附加依赖项:
    • libssl.lib (或 ssleay32.lib)
    • libcrypto.lib (或 libeay32.lib)
    • ws2_32.lib (用于网络功能,但在这里可能不需要,最好加上以防万一)
    • gdi32.lib (可能需要,具体取决于你的OpenSSL版本和配置)

3. CMake 项目配置

如果你使用CMake,它会自动处理这些。

cmake_minimum_required(VERSION 3.10)
project(OpenSSLRSAExample CXX)# 查找OpenSSL库
find_package(OpenSSL REQUIRED)add_executable(generate_rsa_keys main.cpp)target_link_libraries(generate_rsa_keys PRIVATE OpenSSL::SSL OpenSSL::Crypto)

C++ 源代码 (main.cpp)

#include <iostream>
#include <string>
#include <fstream>
#include <vector>// OpenSSL 头文件
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h> // 用于错误处理#pragma warning(disable: 4996)// 辅助函数:显示OpenSSL错误
void printOpenSSLError(const std::string& msg) {std::cerr << msg << std::endl;ERR_print_errors_fp(stderr);
}// 生成RSA密钥对并保存到PEM文件
bool generateRSAKeyPair(const std::string& privateKeyFile, const std::string& publicKeyFile, int bits = 2048) {RSA* rsa = NULL;BIGNUM* bne = NULL; // RSA 公钥指数BIO* bp_public = NULL;BIO* bp_private = NULL;int ret = 0; // 返回值// 写入加密的私钥,需要密码const char* password = "mypassword"; // 替换为你的密码,或者在实际应用中动态获取// 1. 生成 RSA 密钥对// 设置公钥指数,通常是 65537bne = BN_new();if (bne == NULL) {printOpenSSLError("Error creating BIGNUM");goto err;}ret = BN_set_word(bne, RSA_F4); // RSA_F4 is 65537if (ret != 1) {printOpenSSLError("Error setting BIGNUM word");goto err;}// 生成RSA密钥rsa = RSA_new();if (rsa == NULL) {printOpenSSLError("Error creating RSA object");goto err;}ret = RSA_generate_key_ex(rsa, bits, bne, NULL);if (ret != 1) {printOpenSSLError("Error generating RSA key");goto err;}std::cout << "RSA key pair generated successfully (bits: " << bits << ")." << std::endl;// 2. 保存私钥到 PEM 文件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_RSAPrivateKey(bp_private, rsa, NULL, NULL, 0, NULL, NULL); // 未加密的私钥if (!PEM_write_bio_RSAPrivateKey(bp_private, rsa, EVP_des_ede3_cbc(), (unsigned char*)password, strlen(password), NULL, NULL)) {printOpenSSLError("Error writing private key to file");goto err;}std::cout << "Private key saved to " << privateKeyFile << std::endl;// 3. 保存公钥到 PEM 文件bp_public = BIO_new_file(publicKeyFile.c_str(), "w+");if (bp_public == NULL) {printOpenSSLError("Error creating public key file BIO");goto err;}if (!PEM_write_bio_RSA_PUBKEY(bp_public, rsa)) { // RSA_PUBKEY writes in PKCS#8 formatprintOpenSSLError("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 (bne != NULL) BN_free(bne);if (rsa != NULL) RSA_free(rsa);return (ret == 1);
}int main() {// 1. 初始化 OpenSSL 库// 可以调用 OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS | OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS, NULL);// 或者更简单的,使用 ERR_load_crypto_strings();ERR_load_crypto_strings(); // 加载错误字符串,以便 ERR_print_errors_fp 可以打印有意义的信息OpenSSL_add_all_algorithms(); // 加载所有加密算法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 库EVP_cleanup(); // 清理所有算法ERR_free_strings(); // 释放错误字符串return 0;
}

编译和运行

使用 CMake (推荐):

  1. 创建 main.cppCMakeLists.txt 在同一个目录。
  2. 在终端中导航到该目录。
  3. 创建 build 目录并进入:
    mkdir build
    cd build
    
  4. 运行 CMake 生成项目文件 (例如,Visual Studio 项目文件):
    cmake .. -G "Visual Studio 17 2022" # 根据你的VS版本调整
    
    或在 Linux/macOS 上:
    cmake ..
    
  5. 构建项目:
    cmake --build . --config Release # 或 Debug
    
  6. 运行可执行文件 (generate_rsa_keys.exebuild/Releasebuild/Debug 目录下)。

手动编译 (Windows, GCC/MinGW):

g++ main.cpp -o generate_rsa_keys -I C:\OpenSSL-Win64\include -L C:\OpenSSL-Win64\lib -lssl -lcrypto -lws2_32 -lgdi32

(请替换 C:\OpenSSL-Win64 为你的 OpenSSL 安装路径)

手动编译 (Linux/macOS, GCC/Clang):

g++ main.cpp -o generate_rsa_keys -lssl -lcrypto

预期输出

成功运行后,你会在程序所在的目录看到两个新文件:

  • private_key.pem (包含加密的RSA私钥)
  • public_key.pem (包含RSA公钥)

控制台输出会是这样:

RSA key pair generated successfully (bits: 2048).
Private key saved to private_key.pem
Public key saved to public_key.pemRSA key pair generation and saving completed successfully.

PEM 文件内容示例

private_key.pem (部分内容,由于加密,格式会有点不同):

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,BA0A9F1C02EB1D53MIIGsAYJKoZIhvcNAQEE... (大量base64编码的数据) ...
-----END RSA PRIVATE KEY-----

public_key.pem (部分内容):

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA... (大量base64编码的数据) ...
-----END PUBLIC KEY-----

密钥长度 (bits 参数)

generateRSAKeyPair 函数中,bits 参数控制生成RSA密钥的长度。

  • 1024: 曾经常用,但现在被认为安全性不足。
  • 2048: 当前推荐的标准,提供良好的安全性。
  • 30724096: 提供更高的安全性,但生成和使用速度较慢。

加密的私钥

示例中私钥是加密保存的,密码是 “mypassword”。这意味着当你以后需要加载这个私钥时,需要提供相同的密码。如果你想保存未加密的私钥,可以注释掉 PEM_write_bio_RSAPrivateKey 调用中 EVP_des_ede3_cbc() 和密码相关的参数,只留下 NULL但请注意,未加密的私钥非常不安全,应避免在生产环境中使用。

// 保存未加密的私钥 (不推荐用于生产环境)
// if (!PEM_write_bio_RSAPrivateKey(bp_private, rsa, NULL, NULL, 0, NULL, NULL)) {
//     printOpenSSLError("Error writing unencrypted private key to file");
//     goto err;
// }

存在的坑

由于我安装的OpenSSL版本是3.0以上,本文出现的主体代码有一个特点,就是 禁止了4996警告(#pragma warning(disable: 4996)),虽然仅用了这个警告,但毕竟只是临时的一个解决办法,事实上OpenSSL 3.0以上版本代码接口发生了变化,是需要进行修改调整的。
再者,EVP_des_ede3_cbc() 是一个旧的加密算法,OpenSSL 3.0 推荐使用更强的算法,例如 EVP_aes_256_cbc(),这些我将在下一篇博客里填坑。

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

相关文章:

  • 测试覆盖率:从度量到优化的完整工程实践指南
  • 贵阳网站设计哪家好无锡手机网站开发
  • SpringBoot中StringUtils工具类的使用
  • 阿里云网站方案建设书模板wordpress评论编辑器
  • SpringBoot核心注解、自动配置原理和配置文件
  • 46.NAT、代理服务、内网穿透
  • 网站平台建设规划西安最好的设计院排名
  • 基于Spring Boot与SSM的中药实验管理系统架构设计
  • 【Spring】Spring Boot 自动配置原理分析
  • git 的常用命令
  • 现在ui做的比较好的网站免费云手机无限时间版
  • 整体设计 逻辑系统程序 之2 Target 之1 靶点根治的逻辑体系深化与落地设计:从规则双轨到语言 - 知识桥梁
  • 网站php源码长沙设计公司都有哪些
  • 第一版代码
  • 2025年AI费控系统避坑指南:智能风控+预算管控能力对比
  • Windows的多路复用IOCP
  • 做网站的规范暴雪公司现状
  • 前端提效工具清单,常用前端效率工具推荐与开发提效实战经验
  • 做的网站怎么把技术支持去掉个人社保缴费年限怎么查询
  • 李宏毅机器学习笔记15
  • 数字化转型:开发者思维破局之道
  • 网站会员功能介绍营销背景包括哪些内容
  • 【NCS随笔】peripheral_hids_mouse例程修改为不使用PIN码绑定
  • 第三方软件验收测试:【AutoIt与Selenium结合测试文件上传/下载等Windows对话框】
  • 网站的二级目录是什么10个不愁销路的小型加工厂
  • K8S中关于容器对外提供服务网络类型
  • 建设网站需要虚拟空间嘛专业网站制作公司采用哪些技术制作网站?
  • 超声波水表:原理、实现与核心技术解析
  • 怎样 建设电子商务网站直播网站app开发
  • Nginx 核心功能配置:访问控制、用户认证、HTTPS 与 URL 重写等