如何从 OpenSSL 中的 ECDSA 私钥获取公钥?

Posted

技术标签:

【中文标题】如何从 OpenSSL 中的 ECDSA 私钥获取公钥?【英文标题】:How do I obtain the public key from an ECDSA private key in OpenSSL? 【发布时间】:2012-09-10 22:32:45 【问题描述】:

我提供这个示例应用程序来显示我的问题

#include <stdio.h>
#include <stdlib.h>
#include <openssl/ec.h>
#include <openssl/bn.h>

int main()

     EC_KEY *pkey = NULL;
     EC_POINT *pub_key = NULL;
     const EC_GROUP *group = NULL;
     BIGNUM start;
     BIGNUM *res;
     BN_CTX *ctx;

     BN_init(&start);
     ctx = BN_CTX_new();

     res = &start;
     BN_hex2bn(&res,"3D79F601620A6D05DB7FED883AB8BCD08A9101B166BC60166869DA5FC08D936E");
     pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
     group = EC_KEY_get0_group(pkey);
     pub_key = EC_POINT_new(group);

     EC_KEY_set_private_key(pkey, res);

     assert(EC_POINT_bn2point(group,res, pub_key, ctx)); // Null here

     EC_KEY_set_public_key(pkey, pub_key);


    return 0;

我想要做的是从私钥显示公钥(应该是椭圆私钥)。 直到遇到类似的问题,我才知道该怎么做

How do I feed OpenSSL random data for use in ECDSA signing?

这是我指出自己如何获取公钥并使用 EC_POINT_bn2point 而不是 hex2point 的地方,后者根据 OpenSSL 源在内部执行 BN_hex2bn。

那么,为什么 EC_POINT_bn2point 返回 NULL?我正在认真考虑重新编译 OpenSSL 并放置一些调试程序来找出它失败的原因。

【问题讨论】:

好吧,如果您可以从私钥中提取公钥,那将破坏 RSA 的本质...... 我发现一些文章说私钥留下了一些线索来生成公钥,但不是用英文写的。所以你可以找到私钥的格式,它可能会有所帮助。 ECDSA 私钥d(整数)和公钥Q(一个点)由Q = dG 计算,其中G 是非秘密域参数。另见:nsa.gov/ia/_files/ecdsa.pdf 是的,我拿到了。我需要使用基本生成器 G 进行 EC 乘法。 【参考方案1】:

ECDSA 私钥 d(整数)和公钥 Q(点)由 Q = dG 计算,其中 G 是一个非秘密域参数。 Suite B Implementer’s Guide to FIPS 186-3 (ECDSA) 详细描述了 ECDSA。

OpenSSL 使用ECDSA_generate_key 生成密钥对。它的作用是随机生成一个私钥,然后通过 Q = dG 乘法计算公钥:

/* pub_key is a new uninitialized `EC_POINT*`.  priv_key is a `BIGNUM*`. */
if (!EC_POINT_mul(ecdsa->group, pub_key, priv_key, NULL, NULL, ctx)) goto err;

所以你可以做同样的事情。如果我有私钥,我会将其设置为 EC_KEYECDSA 结构中的私钥。然后我会在上面配置域参数。最后我会使用EC_POINT_mul 来获取公钥。

【讨论】:

【参考方案2】:

工作示例:

// using figures on: https://en.bitcoin.it/wiki/Technical_background_of_version_1_Bitcoin_addresses
// gcc -Wall ecdsapubkey.c -o ecdsapubkey -lcrypto
#include <stdio.h>
#include <stdlib.h>
#include <openssl/ec.h>
#include <openssl/obj_mac.h>
#include <openssl/bn.h>

int main()

     EC_KEY *eckey = NULL;
     EC_POINT *pub_key = NULL;
     const EC_GROUP *group = NULL;
     BIGNUM start;
     BIGNUM *res;
     BN_CTX *ctx;

     BN_init(&start);
     ctx = BN_CTX_new(); // ctx is an optional buffer to save time from allocating and deallocating memory whenever required

     res = &start;
//     BN_hex2bn(&res,"3D79F601620A6D05DB7FED883AB8BCD08A9101B166BC60166869DA5FC08D936E");
     BN_hex2bn(&res,"18E14A7B6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725");
     eckey = EC_KEY_new_by_curve_name(NID_secp256k1);
     group = EC_KEY_get0_group(eckey);
     pub_key = EC_POINT_new(group);

     EC_KEY_set_private_key(eckey, res);

     /* pub_key is a new uninitialized `EC_POINT*`.  priv_key res is a `BIGNUM*`. */
     if (!EC_POINT_mul(group, pub_key, res, NULL, NULL, ctx))
       printf("Error at EC_POINT_mul.\n");

//     assert(EC_POINT_bn2point(group, &res, pub_key, ctx)); // Null here

     EC_KEY_set_public_key(eckey, pub_key);

     char *cc = EC_POINT_point2hex(group, pub_key, 4, ctx);

     char *c=cc;

     int i;

     for (i=0; i<130; i++) // 1 byte 0x42, 32 bytes for X coordinate, 32 bytes for Y coordinate
     
       printf("%c", *c++);
     

     printf("\n");

     BN_CTX_free(ctx);

     free(cc);

     return 0;

另见http://wiki.openssl.org/index.php/Elliptic_Curve_Cryptography - 库

http://www.nsa.gov/ia/_files/ecdsa.pdf - 用于算法

http://cs.ucsb.edu/~koc/ccs130h/notes/ecdsa-cert.pdf - 用于数学

【讨论】:

以上是关于如何从 OpenSSL 中的 ECDSA 私钥获取公钥?的主要内容,如果未能解决你的问题,请参考以下文章

Openssl ECDSA:私钥密码

从 ECDSA 公钥生成比特币地址

生成 256 位 ECDSA 私钥

如何将 OpenSSL ECDSA 密钥加载到 C# 中?

如何使用 RustCrypto (ECDSA) 签署文件?

从私钥派生 ECDSA 公钥