如何使用C++基于RSA私有PEM密钥与SHA256算法实现签名
你目前使用的RSA_sign接口默认采用PKCS#1 v1.5填充,和你给出的openssl命令指定的RSASSA-PSS填充模式不匹配,这是签名结果不一致的核心原因。
正确实现代码
基于OpenSSL的EVP高阶接口实现,完全匹配你给出的openssl命令参数:
#include <openssl/evp.h> #include <openssl/pem.h> #include <openssl/err.h> int rsa_pss_sha256_sign(const char* signString, const char* pem_private_key_path, unsigned char** out_sig, size_t* out_sig_len) { // 初始化OpenSSL依赖 ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); // 1. 读取PEM格式私钥 FILE* privateKeyFile = fopen(pem_private_key_path, "rb"); if (!privateKeyFile) { return -1; } EVP_PKEY* pkey = PEM_read_PrivateKey(privateKeyFile, NULL, NULL, NULL); fclose(privateKeyFile); if (!pkey) { ERR_print_errors_fp(stderr); return -1; } size_t messageLength = strlen(signString); // 2. 创建签名上下文 EVP_MD_CTX* md_ctx = EVP_MD_CTX_new(); if (!md_ctx) { EVP_PKEY_free(pkey); return -1; } // 3. 初始化签名操作,指定摘要算法为SHA256 if (EVP_DigestSignInit(md_ctx, NULL, EVP_sha256(), NULL, pkey) != 1) { EVP_MD_CTX_free(md_ctx); EVP_PKEY_free(pkey); return -1; } // 4. 配置PSS填充参数,和openssl命令参数完全对应 EVP_PKEY_CTX* pkey_ctx = EVP_MD_CTX_get_pkey_ctx(md_ctx); if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) != 1 || EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, 20) != 1 || EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, EVP_sha256()) != 1) { EVP_MD_CTX_free(md_ctx); EVP_PKEY_free(pkey); return -1; } // 5. 传入待签名原始数据 if (EVP_DigestSignUpdate(md_ctx, signString, messageLength) != 1) { EVP_MD_CTX_free(md_ctx); EVP_PKEY_free(pkey); return -1; } // 6. 动态获取签名长度,分配缓冲区 size_t sigLen = 0; if (EVP_DigestSignFinal(md_ctx, NULL, &sigLen) != 1) { EVP_MD_CTX_free(md_ctx); EVP_PKEY_free(pkey); return -1; } *out_sig = (unsigned char*)malloc(sigLen); // 7. 生成最终签名 if (EVP_DigestSignFinal(md_ctx, *out_sig, &sigLen) != 1) { free(*out_sig); EVP_MD_CTX_free(md_ctx); EVP_PKEY_free(pkey); return -1; } *out_sig_len = sigLen; // 释放资源 EVP_MD_CTX_free(md_ctx); EVP_PKEY_free(pkey); CRYPTO_cleanup_all_ex_data(); ERR_free_strings(); return 0; }
参数对应说明
代码里的配置和你给出的openssl命令参数一一对应:
EVP_sha256()对应命令的-sha256,指定摘要算法为SHA256EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING)对应-sigopt rsa_padding_mode:pss,指定PSS填充模式EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, 20)对应-sigopt rsa_pss_saltlen:20,指定盐长度为20字节EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, EVP_sha256())对应openssl默认的PSS掩码生成算法配置,使用SHA256作为MGF1的摘要算法
注意事项
- 签名缓冲区长度通过
EVP_PKEY_size(pkey)动态获取,无需硬编码,可适配2048/4096等不同长度的RSA密钥 - 所有OpenSSL资源使用完成后会调用对应的释放接口,避免内存泄漏
- 如果签名失败,可以调用
ERR_print_errors_fp(stderr)打印错误信息快速排查问题
内容的提问来源于stack exchange,提问作者RongLee
相关产品推荐
相关产品推荐

