6

I am providing this sample application to show my problem

#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;
}

What I am trying to do, is to display the Public key from a private key(should an elliptic private key). I did not know how to do it until I encountered a similar problem

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

Which is from where I pointed myself how to get the public key and to use EC_POINT_bn2point instead of hex2point which internally does BN_hex2bn according to the OpenSSL source.

So, why is EC_POINT_bn2point returning NULL? I am seriously considering recompiling OpenSSL and putting some debug routines to figure out why it fails.

Stefan Falk
  • 23,898
  • 50
  • 191
  • 378
farmdve
  • 786
  • 3
  • 13
  • 26
  • Well, if you could extract a public key from a private key, that would beak the essence of RSA... –  Sep 18 '12 at 16:03
  • I've found some articles that saying the private key has leave some clue which to generate the pub key, but it is not written in English. So may you find the format of the private key and it may help. – Marcus Sep 18 '12 at 16:33
  • 3
    An ECDSA private key `d` (an integer) and public key `Q` (a point) is computed by `Q = dG`, where G is a non-secret domain parameter. See also: http://www.nsa.gov/ia/_files/ecdsa.pdf – indiv Sep 18 '12 at 17:02
  • Yes, I obtained it. I needed to do EC multiplication with base generator G. – farmdve Sep 18 '12 at 17:47

2 Answers2

14

An ECDSA private key d (an integer) and public key Q (a point) is computed by Q = dG, where G is a non-secret domain parameter. Suite B Implementer’s Guide to FIPS 186-3 (ECDSA) describes ECDSA in detail.

OpenSSL uses ECDSA_generate_key to generate a key pair. What it does is generate a private key randomly, and then it does the Q = dG multiplication to compute the public key:

/* 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;

So you can do the same thing. If I had the private key, I'd set it as the private key in an EC_KEY or ECDSA struct. Then I'd configure the domain parameters on it. And finally I'd do the EC_POINT_mul to get the public key point.

indiv
  • 17,306
  • 6
  • 61
  • 82
4

Working example:

// 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;
}

See also http://wiki.openssl.org/index.php/Elliptic_Curve_Cryptography - for library

http://www.nsa.gov/ia/_files/ecdsa.pdf - for algorithm

http://cs.ucsb.edu/~koc/ccs130h/notes/ecdsa-cert.pdf - for math

Doru Georgescu
  • 309
  • 2
  • 12