Search code examples
c++opensslecdsakey-pair

Separating public and private keys of ECDSA keypair


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?


Solution

  • 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!!