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

voi*_*ter 1 c c++ openssl

In all of the examples I've seen of generating a key using elliptic curve via OpenSSL using the EVP high level functions, two EVP_PKEY_CTX and EVP_PKEY (total of 4) variables are needed:

  1. One key/context pair for the parameter generation
  2. One key/context pair for the actual key itself (initialized with the parameters).

Is it possible to consolidate this down to just one key/context pair for both? As I understand it, from the examples I've seen, the logic goes like this:

  1. Create an EVP_PKEY_CONTEXT using whatever curve algorithm ID you want.
  2. Initialize the context with EVP_PKEY_paramgen_init().
  3. Call whatever parameter-setting functions you want on the param context (e.g. EVP_PKEY_CTX_set_ec_paramgen_curve_nid).
  4. Generate/finalize the parameters with EVP_PKEY_paramgen which gives you an EVP_PKEY.
  5. Create an EVP_PKEY_CTX for the actual key, initialized with the param EVP_PKEY from the previous step.
  6. Init the key with EVP_PKEY_keygen_init().
  7. Generate/finalize the key with EVP_PKEY_keygen().

Is there any way to simplify this process? For example, can I just init a key, call the paramgen functions on the key, and then call EVP_PKEY_keygen()? This is sort of how it works with RSA key generation from my experience (you really only do the last 2 steps above, with step 3 happening in the middle).

The documentation states this, which seems to indicate the second context/key pair is unnecessary:

After the call to EVP_PKEY_keygen_init() or EVP_PKEY_paramgen_init() algorithm specific control operations can be performed to set any appropriate parameters for the operation.

The functions EVP_PKEY_keygen() and EVP_PKEY_paramgen() can be called more than once on the same context if several operations are performed using the same parameters.

Maybe I'm misunderstanding, but it seems like it's saying you can invoke the parameter-setting functions after calling EVP_PKEY_keygen_init(), instead of using the paramgen functions.

Mat*_*ell 5

单独的参数生成阶段实际上是为 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;
}
Run Code Online (Sandbox Code Playgroud)

这只需要一个EVP_PKEY和一个EVP_PKEY_CTX