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.
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.
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