2

I'm using c++ to try to generate a ECDSA key-pair following Elliptic_Curve_Cryptography from the OpenSSL wiki.

#include <iostream>

#include <openssl/obj_mac.h>
#include <openssl/ec.h>

int main()
{
    EC_KEY *key;

    if(NULL == (key = EC_KEY_new_by_curve_name(NID_secp224r1)))
        std::cout << "error on new_curve_by_name" << std::endl;

    if(1 != EC_KEY_generate_key(key)) std::cout << "error in generating keys" << std::endl;
}

The key pair is generated without errors, but I don't know how to extract public and private key in two different objects (EC_POINT and BIGNUM), any idea?

jww
  • 97,681
  • 90
  • 411
  • 885
Todde
  • 160
  • 1
  • 10
  • C++ can make it easier to use OpenSSL. You can avoid explicit calls to functions like `EVP_CIPHER_CTX_free` by using `unique_ptr`. See [EVP Symmetric Encryption and Decryption | C++ Programs](http://wiki.openssl.org/index.php/EVP_Symmetric_Encryption_and_Decryption#C.2B.2B_Programs) on the OpenSSL wiki, [unique_ptr and OpenSSL's STACK_OF(X509)*](http://stackoverflow.com/q/38145761/608639), [How to get PKCS7_sign result into a char * or std::string](http://stackoverflow.com/a/38079093/608639), etc. – jww Feb 09 '18 at 01:55

3 Answers3

3

I think the methods you want are:

EC_KEY_get0_private_key and EC_KEY_get0_public_key

This works for me:

EC_KEY* key = EC_KEY_new_by_curve_name(NID_secp224r1);

if(!key)
{
    std::cerr << "Error creating curve key" << '\n';
    return EXIT_FAILURE;
}

if(!EC_KEY_generate_key(key))
{
    std::cerr << "Error generating curve key" << '\n';
    EC_KEY_free(key);
    return EXIT_FAILURE;
}

BIGNUM const* prv = EC_KEY_get0_private_key(key);
if(!prv)
{
    std::cerr << "Error getting private key" << '\n';
    EC_KEY_free(key);
    return EXIT_FAILURE;
}

std::cout << "Private key: " << prv << '\n';

EC_POINT const* pub = EC_KEY_get0_public_key(key);
if(!pub)
{
    std::cerr << "Error getting public key" << '\n';
    EC_KEY_free(key);
    return EXIT_FAILURE;
}

std::cout << "Public key: " << pub << '\n';

// Use keys here ...

EC_KEY_free(key);

NOTE:

When using C libraries like this I often define a custom smart pointer to take care if the deletions. This makes the code less prone to memory leaks and "exception safe".

For example I would define something like this:

struct ec_key_dter{void operator()(EC_KEY* k)const{if(k) EC_KEY_free(k);}};
using  ec_key_uptr = std::unique_ptr<EC_KEY, ec_key_dter>;

And use it like this:

auto key = ec_key_uptr(EC_KEY_new_by_curve_name(NID_secp224r1));

if(!key)
    throw std::runtime_error("Error creating curve key");

if(!EC_KEY_generate_key(key.get()))
    throw std::runtime_error("Error generating curve key");

if(!EC_KEY_check_key(key.get()))
    throw std::runtime_error("Error checking curve key");

// ... etc ...

// Do not delete the key manually!!
Galik
  • 47,303
  • 4
  • 80
  • 117
0

I think you must do the following :

BIGNUM *privateKey;
EC_POINT *publicKey;

privateKey = BN_new();
EC_KEY_set_private_key(key, privateKey);
EC_KEY_set_public_key(key, publicKey);

EDIT :

These two calls will set the privateKey and the publicKey respectively. Open SSL Documentation claims that "destination should be a newly allocated BIGNUM obtained via a call to BN_new(). It should not have been used for other purposes or initialised in any way.", hence i am adding the BN_new() call.

I don't see anything similar to create an EC_Point object( unless you use an EC_Group to create this way : EC_POINT *EC_POINT_new(const EC_GROUP *group);

So try this, if you still don't get it, then maybe you should look into how an EC_Point object is created correctly according to your usage.

Vishaal Shankar
  • 1,648
  • 14
  • 26
  • I already tried this, but both methods generate an error. I think you need to use them only if you already own the public or private key – Todde Feb 08 '18 at 12:28
  • sorry it's not an error, they simply return 0 which is the error code – Todde Feb 08 '18 at 12:33
0

This returns the private key as a BIGNUM

BIGNUM* bn = EC_KEY_get0_private_key(key);

For the public key not sure how to get an EC_POINT but you can get the raw bytes with something like:

  // first call returns length of key
  int len = i2o_ECPublicKey(key, 0);  
  std::vector<unsigned char> bytes b(len, 0);
  unsigned char* p = &b[0];
  // second call copies key into p (and returns length if successful)
  if (i2o_ECPublicKey(key, &p)) != len)
  {
    // handle error
  }
virgesmith
  • 762
  • 1
  • 7
  • 18