使用OpenSSL 1.1生成EC密钥时仅使用1个EVP_PKEY

时间:2019-07-09 13:53:05

标签: c++ c openssl

在我看到的所有示例中,使用EVP高级函数通过OpenSSL使用椭圆曲线生成密钥,需要两个EVP_PKEY_CTXEVP_PKEY(总共4个)变量:< / p>

  1. 一对键/上下文对用于参数生成
  2. 用于实际密钥本身的一对密钥/上下文对(使用参数初始化)。

是否有可能将两者合并为一对密钥/上下文对?据我了解,从我所看到的示例中,逻辑是这样的:

  1. 使用所需的任何曲线算法ID创建一个EVP_PKEY_CONTEXT
  2. 使用EVP_PKEY_paramgen_init()初始化上下文。
  3. 在参数上下文中调用所需的任何参数设置函数(例如EVP_PKEY_CTX_set_ec_paramgen_curve_nid)。
  4. 使用EVP_PKEY_paramgen生成/完成参数,为您提供EVP_PKEY
  5. 为实际密钥创建一个EVP_PKEY_CTX,并使用上一步中的参数EVP_PKEY进行初始化。
  6. 使用EVP_PKEY_keygen_init()初始化密钥。
  7. 使用EVP_PKEY_keygen()生成/确定密钥。

有什么方法可以简化这个过程?例如,我可以只初始化一个键,调用该键上的paramgen函数,然后调用EVP_PKEY_keygen()吗?根据我的经验,这就是RSA密钥生成的工作方式(您实际上只完成了以上最后两个步骤,而中间发生了第三步)。

documentation指出了这一点,这似乎表明第二个上下文/密钥对是不必要的:

  

在调用EVP_PKEY_keygen_init()或EVP_PKEY_paramgen_init()算法之后,可以执行特定的控制操作来为该操作设置任何适当的参数。

     

如果使用相同参数执行多个操作,则可以在同一上下文中多次调用函数EVP_PKEY_keygen()和EVP_PKEY_paramgen()。

也许我误会了,但似乎是在说您可以在调用EVP_PKEY_keygen_init()之后调用参数设置函数,而不是使用paramgen函数。

1 个答案:

答案 0 :(得分:1)

单独的参数生成阶段实际上是针对Diffie-Hellman之类的算法的,这是必要的。对于EC,您几乎总是使用“标准”参数集(即众所周知的曲线)。因此,OpenSSL允许您对此进行快捷操作,并且仅在您已经知道要使用哪些参数的情况下才进行密钥生成。对于EVP_PKEY_CTX_set_ec_paramgen_curve_nid()宏,可以通过参数生成或键生成选项将其明确记录为可以使用:

https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_CTX_set_ec_paramgen_curve_nid.html

  

EVP_PKEY_CTX_set_ec_paramgen_curve_nid()设置EC参数的EC曲线   生成到B。对于EC参数生成,必须调用此宏   或由于没有默认曲线而发生错误。   在以下情况下,也可以调用此函数来显式设置曲线   生成EC密钥。

因此,使用P-256曲线(NID_X9_62_prime256v1)生成密钥的代码可能如下所示:

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

int main(void) {
    EVP_PKEY_CTX *ctx;
    EVP_PKEY *pkey = NULL;
    int ret = 1;

    ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
    if (ctx == NULL)
        goto err;
    if (EVP_PKEY_keygen_init(ctx) <= 0)
        goto err;
    if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, NID_X9_62_prime256v1) <= 0)
        goto err;

    /* Generate key */
    if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
        goto err;

    printf("Success!\n");

    ret = 0;
 err:
    EVP_PKEY_CTX_free(ctx);
    return ret;
}

这仅需要一个EVP_PKEY和一个EVP_PKEY_CTX