调用d2i_ECPrivateKey加载私钥返回空,如何实现ECDSA签名?
问题根因
你调用d2i_ECPrivateKey返回空的核心原因是输入参数格式不符合API要求:
d2i_ECPrivateKey的输入要求是符合OpenSSL定义的DER编码格式的EC私钥结构(包含版本号、曲线参数、私钥值、可选公钥等字段),不是你传入的原始十六进制私钥字符串。- 你当前存储的私钥是64字节的十六进制ASCII字符串,实际对应的256位私钥裸值只有32字节,既没有做十六进制转二进制,也没有封装成要求的DER结构,自然无法被识别。
排查思路
- 先调用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;
- 核对输入参数的格式和长度:确认你传入的缓冲区是否是DER编码数据,长度是否和DER数据长度匹配。
- 确认使用的椭圆曲线是否和私钥对应:如果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
相关产品推荐
相关产品推荐

