在OpenSSL3之前,这很简单.

DH* dh = DH_new();

/* Parameters */
dh->p = BN_bin2bn(bin_p, bin_p_size, NULL);
dh->g = BN_bin2bn(bin_g, bin_g_size, NULL);

/* Private key generation */
BN_hex2bn(&dh->priv_key, hex_priv_key);

/* Public key generation */
DH_generate_key(dh);

/* Derive */
int shared_key_size = DH_compute_key(shared_key, peer_pub_key, dh);

我正在try 在新版本的OpenSSL中制作密钥,但它没有工作,因为EVP_PKEY_generate在

OSSL_PARAM_BLD* param_build = OSSL_PARAM_BLD_new();
OSSL_PARAM_BLD_push_BN(param_build, OSSL_PKEY_PARAM_FFC_P, p);
OSSL_PARAM_BLD_push_BN(param_build, OSSL_PKEY_PARAM_FFC_G, g);

OSSL_PARAM* params = OSSL_PARAM_BLD_to_param(param_build};

/* DH_new() */
EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_from_name(nullptr, "DH", nullptr);
EVP_PKEY_keygen_init(ctx);

/* DH_generate_key */
EVP_PKEY* dh_key_pair = NULL;
EVP_PKEY_generate(ctx, &dh_key_pair, EVP_PKEY_KEY_PARAMETERS, params);

互联网上缺乏信息.我不知道该怎么办.

推荐答案

如果使用自定义素数和生成器,则必须创建域参数为first的EVP_PKEY.

// Create the OSSL_PARAM_BLD.
OSSL_PARAM_BLD* paramBuild = OSSL_PARAM_BLD_new();
if (!paramBuild) {
  // report the error
}
// Set the prime and generator.
if (!OSSL_PARAM_BLD_push_BN(paramBuild, OSSL_PKEY_PARAM_FFC_P, prime) ||
    !OSSL_PARAM_BLD_push_BN(paramBuild, OSSL_PKEY_PARAM_FFC_G, generator)) {
  // report the error
}
// Convert to OSSL_PARAM.
OSSL_PARAM* param = OSSL_PARAM_BLD_to_param(paramBuild);
if (!param) {
  // report the error
}
// Create the context. The name is DHX not DH!!!
EVP_PKEY_CTX* domainParamKeyCtx = EVP_PKEY_CTX_new_from_name(nullptr, "DHX", nullptr);
if (!domainParamKeyCtx) {
  // report the error
}
// Initialize the context.
if (EVP_PKEY_fromdata_init(domainParamKeyCtx) <= 0) {
  // report the error
}
// Create the domain parameter key.
EVP_PKEY* domainParamKey = nullptr;
if (EVP_PKEY_fromdata(domainParamKeyCtx, &domainParamKey,
    EVP_PKEY_KEY_PARAMETERS, param) <= 0) {
  // report the error
}

域参数domainParamKey准备好了!现在,使用它来创建密钥对.

EVP_PKEY_CTX* keyGenerationCtx = EVP_PKEY_CTX_new_from_pkey(nullptr, domainParamKey, nullptr);
if (!keyGenCtx) {
  // report the error
}
if (EVP_PKEY_keygen_init(keyGenerationCtx) <= 0) {
  // report the error
}
EVP_PKEY* keyPair = nullptr;
if (EVP_PKEY_generate(keyGenerationCtx, &keyPair) <= 0) {
  // report the error
}

keys 对keyPair准备好了!

在GitHub上查看这个项目:https://github.com/eugen15/diffie-hellman-cpp.它展示了如何生成密钥对,设置和获取Diffie-Hellman参数.此外,它还有一些定制的Diffie-Hellman实现.

有关OpenSSL 3示例,请参见以下文件:

  • diffie-hellman-openssl.h
  • diffie-hellman-openssl.cpp

以下文件是一个LibreSSL示例,基本上是版本3之前的OpenSSL.这是为了确保您具有向后兼容性.

  • diffie-hellman-libressl-dh.h
  • diffie-hellman-libressl-dh.cpp

More things to consider

FIRST

如果在OpenSSL 3之前使用自定义素数,那么最好使用预定义的安全素数.你可以在这里看到一个例子:https://www.openssl.org/docs/manmaster/man7/EVP_PKEY-DH.html

int priv_len = 2 * 112;
OSSL_PARAM params[3];
EVP_PKEY *pkey = NULL;
EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL);

params[0] = OSSL_PARAM_construct_utf8_string("group", "ffdhe2048", 0);
/* "priv_len" is optional */
params[1] = OSSL_PARAM_construct_int("priv_len", &priv_len);
params[2] = OSSL_PARAM_construct_end();

EVP_PKEY_keygen_init(pctx);
EVP_PKEY_CTX_set_params(pctx, params);
EVP_PKEY_generate(pctx, &pkey);
...
EVP_PKEY_free(pkey);
EVP_PKEY_CTX_free(pctx);

Alice执行上述代码(摘自OpenSSL手册).然后得到素数和生成器:

EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_P, &prime);
EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_G, &generator);

然后将其发送到Bob,并使用上面的代码创建密钥对.

SECOND

在新项目中使用椭圆曲线Diffie-Hellman(ECDH)密钥交换.速度要快得多.把你的DH作为备用方案.我将很快为github项目添加一些示例代码.

C++相关问答推荐

在C中使用动态内存分配找到最小的负数

使用NameSurname扫描到两个单独的字符串

我编译了一个新的c程序,并收到以下错误

ATmega328P EEPROM未写入

为什么STM32G474RE上没有启用RCC PLL

C在声明带有值的数组时,声明大小有用吗?

为什么此共享库没有预期的依赖项?

RawMotion的XInput2错误(具有较高值的XISelectEvents上的BadValue)

C语言中的外部关键字

类型定义 struct 与简单的类型定义 struct

如何将大写/小写土耳其字母相互转换?

程序如何解释变量中的值

C中的空指针是什么(_N)?

未为同一文件中的函数执行DirectFunctionCall

x86-64平台上的int_fast8_t大小与int_fast16_t大小

如何不断地用C读取文件?

将十六进制值或十进制值分配给 uint16_t 有什么区别?

在 printf() 格式说明符中使用字段宽度变量

获取指向 struct 的指针而不显式传递它

为什么CMake构建的程序比命令构建的程序运行得慢