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

VC++ 使用OpenSSL创建RSA密钥PEM档案

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

我的这个项目因为是用了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.pem
RSA key pair generation and saving completed successfully.

PEM 文件内容示例

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

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,BA0A9F1C02EB1D53
MIIGsAYJKoZIhvcNAQEE... (大量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.hskmm.com/?act=detail&tid=21315

相关文章:

  • CF1699D Almost Triple Deletions
  • QMT回测模式为什么要在副图进行
  • DSA:DeepSeek Sparse Attention
  • 荒野猎手出击!启明智显ZX7981PO:专治各种恶劣环境的5G插卡路由器
  • AWS CDK重构功能发布:安全重构基础设施即代码
  • 开发即时通社交软件APP首选系统,可定制开发,可提供源码
  • 死锁的处理策略-死锁的检测和解除
  • springboot3 mybatis 数据库操控入门与实战
  • 解决winform调用wpf窗体时原窗体缩小的问题
  • 重构 Java 系统服务!JBoltAI 框架以 AIGS 方案开启企业数智化转型
  • 本土化优势凸显:Gitee如何成为中国开发团队的效率引擎
  • Linux系统OOM终止Oracle进程
  • Filebeat写ElasticSearch故障排查思路(上) - 教程
  • 数字化转型浪潮下,CI/CD工具如何成为企业软件开发效率的加速器?
  • linux 删除服务
  • Verl实验
  • 适配 20 + 主流 AI 模型!JBoltAI 框架让 Java AI 应用兼容性拉满
  • 告别 “一刀切” 管理!MyEMS 为不同行业定制专属能源优化方案
  • Fourier Features Let Networks Learn High Frequency Functions in Low Dimensional Domains
  • 「突发奇想,灵光乍现」 - hello
  • jenkins 用户权限 管理配置
  • DirectX- DLL修复工具 免费下载!绿色单文件版!安装使用教程
  • 测试集成CI/CD的五大实践:构建高效质量保障体系
  • DirectX修复工具官方中文增强版下载!下载安装教程(附安装包),0xc000007b错误解决办法
  • 死锁的处理策略-避免死锁
  • 7、微服务中 DTO、VO、PO、BO 的设计规范 - 指南
  • Gitee崛起:中国代码托管平台的自主创新之路
  • 9-30
  • 探索 Nim 中的 sequtils 与箭头语法 —— 立即计算与惰性计算的那些事
  • 250930