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

调用d2i_ECPrivateKey加载私钥返回空,如何实现ECDSA签名?

问题根因

你调用d2i_ECPrivateKey返回空的核心原因是输入参数格式不符合API要求:

  • d2i_ECPrivateKey的输入要求是符合OpenSSL定义的DER编码格式的EC私钥结构(包含版本号、曲线参数、私钥值、可选公钥等字段),不是你传入的原始十六进制私钥字符串。
  • 你当前存储的私钥是64字节的十六进制ASCII字符串,实际对应的256位私钥裸值只有32字节,既没有做十六进制转二进制,也没有封装成要求的DER结构,自然无法被识别。
排查思路
  1. 先调用OpenSSL错误栈接口打印具体错误信息,快速定位问题:在d2i_ECPrivateKey返回空后,加如下代码打印错误原因:
unsigned long err = ERR_get_error();
char err_buf[256];
ERR_error_string(err, err_buf);
LOG(ERROR) << "OpenSSL error: " << err_buf;
  1. 核对输入参数的格式和长度:确认你传入的缓冲区是否是DER编码数据,长度是否和DER数据长度匹配。
  2. 确认使用的椭圆曲线是否和私钥对应:如果DER数据中没有携带曲线参数,需要提前给d2i_ECPrivateKey传入已经设置好曲线的EC_KEY对象作为第一个参数,不能传NULL。
解决方案

针对你当前持有原始十六进制私钥的场景,最简便的方案是直接用原始私钥构造EC_KEY对象,无需使用d2i_ECPrivateKey,代码如下:
首先写一个十六进制转二进制的辅助函数,再完成EC_KEY构造:

// 十六进制字符串转二进制缓冲区
std::string hex_to_bin(const std::string& hex_str) {
    std::string bin_str;
    bin_str.reserve(hex_str.size() / 2);
    for (size_t i = 0; i < hex_str.size(); i += 2) {
        char byte = static_cast<char>(strtoul(hex_str.substr(i, 2).c_str(), nullptr, 16));
        bin_str.push_back(byte);
    }
    return bin_str;
}

// 修改后的签名函数逻辑
void sign() {
    // random data
    std::string data = "....";

    // 256-bit key in hex
    std::string private_key_hex =
        "ee52189da48a2aeda40e488ce3c711f852ebdd12a21d1c7fd8a5b78a0902fad1";
    // 1. 十六进制私钥转32字节二进制裸值
    std::string private_key_bin = hex_to_bin(private_key_hex);

    // 2. 创建对应曲线的EC_KEY对象,256位ECDSA常用曲线为secp256k1(加密货币场景)或prime256v1/secp256r1(通用场景),请根据实际使用替换NID
    EC_KEY* ec_key = EC_KEY_new_by_curve_name(NID_secp256k1);
    if (!ec_key) {
        LOG(ERROR) << "EC_KEY创建失败,请确认曲线NID是否正确";
        return {};
    }

    // 3. 私钥裸值转BIGNUM结构
    BIGNUM* priv_bn = BN_bin2bn(reinterpret_cast<const unsigned char*>(private_key_bin.data()), private_key_bin.size(), nullptr);
    if (!priv_bn) {
        LOG(ERROR) << "私钥转BIGNUM失败";
        EC_KEY_free(ec_key);
        return {};
    }

    // 4. 给EC_KEY设置私钥
    if (EC_KEY_set_private_key(ec_key, priv_bn) != 1) {
        LOG(ERROR) << "设置EC_KEY私钥失败";
        BN_free(priv_bn);
        EC_KEY_free(ec_key);
        return {};
    }
    BN_free(priv_bn);

    // 后续可正常执行ECDSA签名逻辑,使用完成后记得调用EC_KEY_free(ec_key)释放内存
}

如果你确实需要使用d2i_ECPrivateKey,需要先将原始私钥封装成符合规范的DER格式EC私钥结构,或者直接读取已生成的DER格式私钥文件内容作为输入即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 23:57:01