You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用EVP_PKEY_fromdata将EC私钥存入EVP_PKEY失败求助

问题分析与修复方案

核心问题点

  1. 参数构建的条件判断逻辑错误
    原代码中判断param_bld创建和group参数入栈的逻辑用了&&,这会导致只有当param_bld为NULL且入栈失败时才报错,实际只要其中任一操作失败就应该终止流程,需要改为||。

  2. EVP_PKEY_fromdata的flags参数误用
    你传入的EVP_PKEY_KEY_PARAMETERS | OSSL_KEYMGMT_SELECT_PRIVATE_KEY不符合函数预期:EVP_PKEY_KEY_PARAMETERS用于设置密钥参数(如曲线类型),而非构建完整私钥。正确的flags应该直接使用OSSL_KEYMGMT_SELECT_PRIVATE_KEY,或者更简洁的EVP_PKEY_PRIVATE_KEY(两者等价)。

  3. 缺少OpenSSL错误信息输出
    原代码只打印自定义错误,没有输出OpenSSL底层的错误详情,这会导致无法定位具体失败原因。

修正后的完整代码

#include <openssl/evp.h>
#include <openssl/param_build.h>
#include <openssl/ec.h>
#include <openssl/err.h>
#include <iostream>

using namespace std;

/*
 * Fixed data to represent the private key.
 */
const unsigned char priv_data[] = {
    0xb9, 0x2f, 0x3c, 0xe6, 0x2f, 0xfb, 0x45, 0x68,
    0x39, 0x96, 0xf0, 0x2a, 0xaf, 0x6c, 0xda, 0xf2,
    0x89, 0x8a, 0x27, 0xbf, 0x39, 0x9b, 0x7e, 0x54,
    0x21, 0xc2, 0xa1, 0xe5, 0x36, 0x12, 0x48, 0x5d};

void errMsg(string msg)
{
    cout << msg << endl;
    // 打印OpenSSL底层错误信息
    ERR_print_errors_fp(stderr);
    exit(1);
}

int main()
{
    EVP_PKEY_CTX *ctx;
    EVP_PKEY *key = NULL;
    OSSL_PARAM_BLD *param_bld;
    OSSL_PARAM *params = NULL;

    // 初始化OpenSSL错误处理
    ERR_load_crypto_strings();
    OpenSSL_add_all_algorithms();

    param_bld = OSSL_PARAM_BLD_new();
    // 修改逻辑判断为||,任一失败则报错
    if (param_bld == NULL || OSSL_PARAM_BLD_push_utf8_string(param_bld, "group", "prime256v1", 0) != 1)
    {
        errMsg("Setup params failed");
    }

    ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
    if (ctx == NULL || EVP_PKEY_fromdata_init(ctx) <= 0)
    {
        errMsg("Setup ctx failed");
    }

    // store private key
    BIGNUM *priv = BN_bin2bn(priv_data, sizeof(priv_data), NULL);
    if (priv == NULL)
    {
        errMsg("Conversion to BIGNUM failed");
    }

    if (OSSL_PARAM_BLD_push_BN(param_bld, "priv", priv) != 1)
    {
        errMsg("Loading private key data to params failed");
    }

    params = OSSL_PARAM_BLD_to_param(param_bld);

    // 修正flags参数,使用正确的私钥选择标识
    if (EVP_PKEY_fromdata(ctx, &key, OSSL_KEYMGMT_SELECT_PRIVATE_KEY, params) <= 0)
    {
        errMsg("Setting private key failed");
    }
    else
    {
        cout << "Private key is stored inside the EVP_PKEY" << endl;
    }

    // 资源释放
    BN_free(priv);
    EVP_PKEY_free(key); // 新增:释放创建的EVP_PKEY
    EVP_PKEY_CTX_free(ctx);
    OSSL_PARAM_free(params);
    OSSL_PARAM_BLD_free(param_bld);

    // 清理OpenSSL错误栈
    ERR_free_strings();
    return 0;
}

额外说明

  • 新增了OpenSSL错误处理的初始化和清理,确保能打印底层错误信息,方便后续调试。
  • 补充了EVP_PKEY_free(key)的资源释放,避免内存泄漏。
  • 修正后的代码会正确将给定的EC私钥加载到EVP_PKEY结构中。

内容的提问来源于stack exchange,提问作者James

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 22:17:48