【问题标题】:Separating public and private keys of ECDSA keypair分离 ECDSA 密钥对的公钥和私钥
【发布时间】:2018-07-19 00:08:02
【问题描述】:

我正在使用 c++ 尝试在 OpenSSL wiki 的 Elliptic_Curve_Cryptography 之后生成 ECDSA 密钥对。

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

生成的密钥对没有错误,但我不知道如何在两个不同的对象(EC_POINT 和 BIGNUM)中提取公钥和私钥,知道吗?

【问题讨论】:

标签: c++ openssl ecdsa key-pair


【解决方案1】:

我认为你想要的方法是:

EC_KEY_get0_private_keyEC_KEY_get0_public_key

这对我有用:

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);

注意:

当使用像这样的C 库时,我经常定义一个自定义的智能指针 来处理是否删除。这使得代码不易发生内存泄漏和“异常安全”。

例如我会这样定义:

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

并像这样使用它:

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

【讨论】:

    【解决方案2】:

    我认为你必须做到以下几点:

    BIGNUM *privateKey;
    EC_POINT *publicKey;
    
    privateKey = BN_new();
    EC_KEY_set_private_key(key, privateKey);
    EC_KEY_set_public_key(key, publicKey);
    

    编辑:

    这两个调用将分别设置privateKeypublicKeyOpen SSL Documentation 声称“destination 应该是通过调用获得的新分配的 BIGNUM BN_new()它不应该用于其他目的或以任何方式初始化。",因此我添加了BN_new() 调用。

    我没有看到任何类似于创建 EC_Point 对象的东西(除非您使用 EC_Group 以这种方式创建:EC_POINT *EC_POINT_new(const EC_GROUP *group);

    所以试试这个,如果你还是不明白,那么也许你应该看看如何根据你的用法正确创建一个 EC_Point 对象。

    【讨论】:

    • 我已经尝试过了,但这两种方法都会产生错误。我认为只有在您已经拥有公钥或私钥时才需要使用它们
    • 对不起,这不是错误,他们只是返回 0,即错误代码
    【解决方案3】:

    这会将私钥作为 BIGNUM 返回

    BIGNUM* bn = EC_KEY_get0_private_key(key);
    

    对于公钥,不确定如何获取 EC_POINT,但您可以通过以下方式获取原始字节:

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

    【讨论】:

      猜你喜欢
      • 2014-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-02
      相关资源
      最近更新 更多