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

C++ OpenSSL secp256k1 ECDSA问题:相同哈希副本验证失败

问题:ECDSA签名验证时相同内容哈希副本验证失败

我尝试使用OpenSSL的secp256k1曲线ECDSA对哈希进行签名,创建该哈希的副本(模拟客户端/服务器场景),但使用副本验证签名时失败,尽管两个哈希变量内容完全一致。此外,直接传入相同内容的字符串字面量验证也失败,复制signature变量无影响。

相关代码

int main()
{
    EC_KEY* myecc = NULL;
    EVP_PKEY* pkey_ = NULL;

    myecc = EC_KEY_new_by_curve_name(NID_secp256k1);
    EC_KEY_generate_key(myecc);
    pkey_ = EVP_PKEY_new();
    EVP_PKEY_assign_EC_KEY(pkey_, myecc);
    myecc = EVP_PKEY_get1_EC_KEY(pkey_);
    const EC_GROUP* ecgrp = EC_KEY_get0_group(myecc);

    std::string hash = "126420fb81d58bbb7d86c98e1818f4c9d44acf216471e196ed403a608954cf1d";
    std::string hashCopy = hash;

    std::vector<unsigned char> signature;
    unsigned char pchSig[10000];
    unsigned int nSize = 0;

    ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), pchSig, &nSize, myecc);
    signature.resize(nSize);
    memcpy(&signature[0], pchSig, nSize);

    if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &signature[0], signature.size(), myecc) == 1)
    {
        std::cout << "Original hash variable verify success\n\n";
    }
    else
    {
        std::cout << "Original hash variable verify fail\n\n";
    }
    if (ECDSA_verify(0, (unsigned char*)&hashCopy, sizeof(hashCopy), &signature[0], signature.size(), myecc) == 1)
    {
        std::cout << "Hash copy variable verify success\n\n";
    }
    else
    {
        std::cout << "Hash copy variable verify fail\n\n";
    }
} 

代码输出

Original hash variable verify success

Hash copy variable verify fail

问题原因与解决方法

核心问题

你传递给ECDSA_sign和ECDSA_verify的参数完全错误:

  • (unsigned char*)&hash取的是std::string对象本身的内存地址,而非字符串存储的哈希内容;sizeof(hash)获取的是std::string结构体的固定大小(通常24或32字节),不是哈希字符串的实际长度。
  • 原hash变量验证成功只是巧合:签名和验证时用的是同一个std::string对象的结构体内存,内部指针、长度值等内容刚好一致;而hashCopy是独立的std::string对象,结构体内存内容和原hash不同,因此验证失败。

修正方案

传递哈希字符串的实际内容和长度:

  • 用hash.data()(或hash.c_str())获取字符串内容的首地址,转成unsigned char*类型
  • 用hash.size()获取字符串的实际长度,替代sizeof(hash)

修正后的关键代码片段:

// 签名操作
ECDSA_sign(0, reinterpret_cast<unsigned char*>(hash.data()), hash.size(), pchSig, &nSize, myecc);

// 验证原哈希
if (ECDSA_verify(0, reinterpret_cast<unsigned char*>(hash.data()), hash.size(), &signature[0], signature.size(), myecc) == 1)
{
    std::cout << "Original hash variable verify success\n\n";
}

// 验证哈希副本
if (ECDSA_verify(0, reinterpret_cast<unsigned char*>(hashCopy.data()), hashCopy.size(), &signature[0], signature.size(), myecc) == 1)
{
    std::cout << "Hash copy variable verify success\n\n";
}

额外提示

你的hash变量是十六进制字符串形式的哈希值,而ECDSA签名通常是对原始二进制哈希值操作。如果你的真实需求是签名哈希值本身,需要先把十六进制字符串转换成二进制数组,否则你签名的是十六进制字符的ASCII码(比如"12"会被当作0x31和0x32,而非0x12)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 15:57:15