当前位置: 首页 > 知识库问答 >
问题:

ECDSA签名验证:Go vs OpenSSL

翟高明
2023-03-14

我正在尝试使用公钥验证散列的ECDSA签名。我写了一个小的围棋程序,成功地做到了这一点,但是我不能把它移植到C语言中。

这是我的输入数据

    < li >公钥:< code > mfkwewyhkozizj 0 caqyikozij0 dackcdqgaedd 9 vxm phjv 4 vofo 0 zofplr r5 iczxquxsr 9 eka ouo 9 b 7 wl 1 daggi 0 ekcm 1 bl 2 od 32 zfefug 07 otptmvocpa = = < li >哈希:< code > 562 D6 ddfb 3c EB 5 abb 12d 97 BC 35 c 4963d 249 f 55 b 7 c 75 EDA 618d 365492 ee 98d 469 < li >签名:< code > 304502204 d6d 070117d 445 f 4c 2 fc DBD 4 df 037 a1 c 8 cf ee2 a 166353 C2 e 562 CD 5 EFD 06 e 914d 022100 bb 06439 de d 1478 BD 19022519 DC 06 a 84 ba 18 ea 4 BF 30 ea 9 e 9 ea 90 f 8 b 66 dad 12 c 7

这是我的工作围棋程序:

package main

import (
    "crypto/ecdsa"
    "crypto/x509"
    "encoding/base64"
    "encoding/hex"
)

func main() {
    key_, _ := base64.StdEncoding.DecodeString("MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDd9VXmpHjV4voFO+0ZoFPlRr5icZXquxsr9EkaOUO9B7Wl1DAgGI0EKCm1++Bl2Od32xZFeFuG07OTpTMVOCPA==")
    key, _ := x509.ParsePKIXPublicKey(pkey_)
    msg, _ := hex.DecodeString("562d6ddfb3ceb5abb12d97bc35c4963d249f55b7c75eda618d365492ee98d469")
    sig, _ := hex.DecodeString("304502204d6d070117d445f4c2fcdbd4df037a1c8cfee2a166353c2e562cd5efd06e914d022100bb06439ded1478bd19022519dc06a84ba18ea4bf30ea9eb9ea90f8b66dad12c7")

    valid := ecdsa.VerifyASN1(key.(*ecdsa.PublicKey), msg[:], sig)

    if !valid {
      panic("key invalid")
    }
}

这是我损坏的C程序,它在最后一个断言中失败。我想知道为什么:

#include <cassert>
#include <cstdlib>
#include <string>
#include <stdexcept>

#include <openssl/bio.h>
#include <openssl/ec.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/pem.h>

std::string decode_hex_str(std::string const &hex) {
  std::string str;
  for (std::size_t i { 0 }; i < hex.size(); i += 2) {
    auto byte { hex.substr(i,2) };
    str.push_back(std::strtol(byte.c_str(), nullptr, 16));
  }

  return str;
}

int main() {
  std::string key_ {
R"(
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDd9VXmpHjV4voFO+0ZoFPlRr5icZXquxsr9EkaOUO9B7Wl1DAgGI0EKCm1++Bl2Od32xZFeFuG07OTpTMVOCPA==
-----END PUBLIC KEY-----
)"
  };

  std::string msg { decode_hex_str("562d6ddfb3ceb5abb12d97bc35c4963d249f55b7c75eda618d365492ee98d469") };
  std::string sig { decode_hex_str("304502204d6d070117d445f4c2fcdbd4df037a1c8cfee2a166353c2e562cd5efd06e914d022100bb06439ded1478bd19022519dc06a84ba18ea4bf30ea9eb9ea90f8b66dad12c7") };

  auto bio { BIO_new_mem_buf(key_.data(), key_.length()) };
  assert(bio);

  auto key { PEM_read_bio_EC_PUBKEY(bio, nullptr, nullptr, nullptr) };

  EVP_MD_CTX *mdctx { nullptr };
  EVP_PKEY *pkey { nullptr };

  int status;
  bool verified;

  mdctx = EVP_MD_CTX_new();
  assert(mdctx);

  pkey = EVP_PKEY_new();
  assert(pkey);

  assert(EVP_PKEY_assign_EC_KEY(pkey, key) == 1);

  assert(EVP_DigestVerifyInit(mdctx, nullptr, EVP_sha256(), nullptr, pkey) == 1);

  assert(EVP_DigestVerifyUpdate(mdctx, msg.data(), msg.length()) == 1);

  status = EVP_DigestVerifyFinal(mdctx, reinterpret_cast<unsigned char const *>(sig.data()), sig.length());

  switch (status) {
    case 0:
      verified = false;
      break;
    case 1:
      verified = true;
      break;
    default:
      assert(false);
  }

  EVP_MD_CTX_free(mdctx);
  EVP_PKEY_free(pkey);

  assert(verified);
}

共有1个答案

聂炜
2023-03-14

EVP_DigestVerify{Init/Update/Final}做两件事:

  • 他们对输入数据进行散列
  • 然后他们根据签名验证计算的哈希

ecdsa。另一方面,VerifyASN1只执行上述第二步,已经将散列作为输入。

执行此操作的 OpenSSL 函数ECDSA_verify

所以你可以这样做:

BIO* bio = BIO_new_mem_buf(key_.data(), key_.length());

EC_KEY* key = PEM_read_bio_EC_PUBKEY(bio, nullptr, nullptr, nullptr);

int verified = ECDSA_verify(
    0,
    (unsigned char const*)msghash.data(), msghash.length(),
    (unsigned char const*)sig.data(), sig.length(),
    key
);

std::cout << verified << std::endl;

应该打印< code>1。

请注意,代码中的变量命名令人困惑——变量msg实际上包含报文摘译。所以msghashdigest是一个更好的名字。在进行加密时,变量命名的准确性很重要。

 类似资料:
  • 我想创建一个签名并使用openssl验证它。我想有我的签名的十六进制输出。 这是我的密码 我得到这个错误: 如果我在创建签名的过程中删除了-hex,它就可以工作了。

  • 我应该如何更改A方法?任何想法都是好的。提前谢谢。

  • 最近,我一直在尝试构建一个Java库来解释和验证NZ Covid传递。在签名验证之前(这个过程中稍微重要的一部分),我已经让代码变得更好或更坏。完整的代码可以在这里找到,但是仍然很粗糙。 验证器本身在这里可用,有一个配套测试。新冠通行证的技术规范在这里。至少有一个相关部分。 在与另一个开发人员合作后,我想我已经确定了解释提供的公钥。下面的代码(删除了调试输出)。公钥详细信息来自这里 该错误可能存在

  • 我正在尝试在python中使用ECDSA验证比特币签名,但发现它非常困难,许多尝试已经失败了。 参数: 注意:我已经根据ECDSA的要求将签名从base64转换为hexstring。每当我试图验证它时,它会说: 预期64字节签名(128十六进制字符串),提供了65字节签名(130十六进制字符串) 我查看了许多关于ECDSA的stackoverflow问题,但没有一个答案与我的qs 100%相关。感

  • 我有一个python程序,它使用PyKCS11,pkcs11接口的python包装器。我可以使用存储在HSM上并由PyKCS11访问的ECC私钥(机制CKM_ECDSA)对数据进行签名。 我现在想要的是用openssl通过相应的公钥验证ECDSA签名。该公钥包含在x509(NewCert.pem)中,该x509由HSM中的私钥创建。 我测试了许多正确验证签名的方法,但没有成功。 文件签名包含bas

  • 我试图使用javascript创建ECDSA算法的密钥对,签名消息,然后在服务器端验证它(使用Java)。 示例javascript代码: 例如: 我做错了什么?