无法在C ++中获得与OpenSSL的Diffie Hellman共享秘密

问题描述 投票:0回答:1

我正在尝试使自己熟悉OpenSSL Diffie Hellman的功能,为此,我试图创建一个简单的程序,该程序将生成两组Diffie Hellman私钥和公钥,然后得出共享密钥。我已经遵循了OpenSSL Wiki上的Diffie Hellman教程,并且能够生成密钥,但是无法导出共享密钥。我的C ++(Linux)代码如下:

#include <iostream>
#include <openssl/dh.h>
#include <openssl/engine.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>

int main(int argc, char** argv)
{

    EVP_PKEY* params;

    EVP_PKEY_CTX *kctx1, *kctx2, *dctx1, *dctx2;

    unsigned char *skey1, *skey2;
    size_t skeylen1, skeylen2;
    EVP_PKEY *dh_1, *dh_2;
    BIO* bio_out = NULL;
    int result = 0;
    ENGINE* eng;

    BIO* fp = BIO_new_fp(stdout, BIO_NOCLOSE);

    // Initalise Diffie Hellman PKEY for client 1
    if(NULL == (dh_1 = EVP_PKEY_new())) {
        std::cout << "error 1" << std::endl;
    }

    // Initalise Diffie Hellman PKEY for client 2
    if(NULL == (dh_2 = EVP_PKEY_new())) {
        std::cout << "error 2" << std::endl;
    }

    // Initalise Diffie Hellman parameter PKEY
    if(NULL == (params = EVP_PKEY_new())) {
        std::cout << "error 3" << std::endl;
    }

    // Set Diffie Hellman paramerers
    if(1 != EVP_PKEY_set1_DH(params, DH_get_2048_256())) {
        std::cout << "error 4" << std::endl;
    }

    // Initalise client 1 PKEY Context
    if(!(kctx1 = EVP_PKEY_CTX_new(params, NULL))) {
        std::cout << "error 5" << std::endl;
    }

    // Initalise client 2 PKEY Context
    if(!(kctx2 = EVP_PKEY_CTX_new(params, NULL))) {
        std::cout << "error 6" << std::endl;
    }

    if(!kctx1) {
        std::cout << "error 7" << std::endl;
    }

    if(!kctx2) {
        std::cout << "error 8" << std::endl;
    }

    // Initalise both contexts key generators
    if(1 != EVP_PKEY_keygen_init(kctx1)) {
        std::cout << "error 9" << std::endl;
    }

    if(1 != EVP_PKEY_keygen_init(kctx2)) {
        std::cout << "error 10" << std::endl;
    }

    // Generate DH public and private keys for client 1
    if(1 != EVP_PKEY_keygen(kctx1, &dh_1)) {
        std::cout << "error 11" << std::endl;
    }

    // Generate DH public and private keys for client 2
    if(1 != EVP_PKEY_keygen(kctx2, &dh_2)) {
        std::cout << "error 12" << std::endl;
    }

    // EVP_PKEY_print_public(fp, dh_1, 3, NULL);

    // EVP_PKEY_print_public(fp, dh_2, 3, NULL);

    // Create key derivation context
    if(NULL == (dctx1 = EVP_PKEY_CTX_new(dh_1, NULL))) {
        std::cout << "error 13" << std::endl;
    }

    if(!dctx1) {
        std::cout << "error 14" << std::endl;
    }

    // Initalise first key derivation context
    if(1 != EVP_PKEY_derive_init(dctx1)) {
        std::cout << "error 15" << std::endl;
    }

    if(1 != EVP_PKEY_check(dctx1)) {
        std::cout << "error 16" << std::endl;
    }

    if(1 != EVP_PKEY_param_check(dctx1)) {
        std::cout << "error 17" << std::endl;
    }

    // Set first key derivation context peer key to the second DH PKEY
    if(1 != EVP_PKEY_derive_set_peer(dctx1, dh_2)) {
        std::cout << "error 18" << std::endl;
    }

    if(1 != EVP_PKEY_public_check(dctx1)) {
        std::cout << "error 19" << std::endl;
    }

    /* Determine buffer length */
    if(EVP_PKEY_derive(dctx1, NULL, &skeylen1) <= 0) {
    }

    // Assign memory for shared key variable
    skey1 = (unsigned char*)OPENSSL_malloc(skeylen1);

    if(result = EVP_PKEY_derive(dctx1, skey1, &skeylen1) <= 0) {
        std::cout << "Key: " << skey1 << std::endl;

        for(int i = 0; i < skeylen1; i++) {
            std::cout << std::hex << (unsigned int)skey1[i];
        }
    }

    ERR_print_errors_fp(stdout);

    std::cout << result << std::endl;
}

我主要关心的是:

  1. 我需要做些什么来导出共享密钥?
  2. 每个密钥对和密钥派生是否需要新的上下文?

谢谢!

编辑:

我收到以下错误,并且没有共享密钥:

140690271102784:error:05079079:Diffie-Hellman routines:DH_check_ex:unable to check generator:../crypto/dh/dh_check.c:92:

140690271102784:error:05079076:Diffie-Hellman routines:DH_check_ex:check p not safe prime:../crypto/dh/dh_check.c:96:

140690271102784:error:0507B07B:Diffie-Hellman routines:DH_check_pub_key_ex:check pubkey too large:../crypto/dh/dh_check.c:190:

140690271102784:error:0507B07A:Diffie-Hellman routines:DH_check_pub_key_ex:check pubkey invalid:../crypto/dh/dh_check.c:192:

当我使用时

    if(NULL == (dctx1 = EVP_PKEY_CTX_new(dh_1, NULL))) {
        std::cout << "error 13" << std::endl;
    }

并且出现以下错误

error 16
error 19

Key: �ȭ��U

c0c8add7c4550000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

139939742943040:error:060BA096:digital envelope routines:EVP_PKEY_check:operation not supported for this keytype:../crypto/evp/pmeth_gn.c:188:
139939742943040:error:0507C07D:Diffie-Hellman routines:dh_pkey_public_check:missing pubkey:../crypto/dh/dh_ameth.c:517:
139939742943040:error:05066064:Diffie-Hellman routines:compute_key:no private value:../crypto/dh/dh_key.c:183:
1

当我将“ EVP_PKEY_CTX_new(dh_1,NULL)”更改为“ EVP_PKEY_CTX_new(params,NULL)”时,像这样:

    if(NULL == (dctx1 = EVP_PKEY_CTX_new(params, NULL))) {
        std::cout << "error 13" << std::endl;
    }

这两个变量之间的区别在于,“ dh_1”存储DH密钥对,而“ params”包含DH参数。似乎派生上下文在某种程度上启发了后者,尽管它没有与之相关的私钥和公钥。

c++ openssl diffie-hellman
1个回答
0
投票

使用您发布的代码版本,我得到的错误略有不同。我从您的代码中获得了以下输出(与OpenSSL 1.1.1链接):

error 16
error 17
140673674348352:error:060BA096:digital envelope routines:EVP_PKEY_check:operation not supported for this keytype:crypto/evp/pmeth_gn.c:187:
140673674348352:error:05079076:Diffie-Hellman routines:DH_check_ex:check p not safe prime:crypto/dh/dh_check.c:93:
0

第一个“错误16”输出仅是因为OpenSSL当前不支持Diffie-Hellman密钥的EVP_PKEY_check()调用。因此可以放心地忽略它。

第二个“错误17”输出(与错误队列中的“ check p not safe prime”错误相关联)更成问题。这是因为Diffie-Hellman键有两种不同的类型。默认情况下,OpenSSL使用PKCS#3 Diffie-Hellman密钥。但是,它也支持X9.42 Diffie-Hellman键。函数DH_get_2048_256()为X9.42键提供了一组内置参数。但是,函数EVP_PKEY_set1_DH()期望提供的DH对象是PKCS#3密钥。

这实际上对我来说似乎是OpenSSL中的一个错误(EVP_PKEY_set1_DH()应该真正检测出它是哪种类型的密钥并做正确的事情),因此我为此提出了以下OpenSSL问题:https://github.com/openssl/openssl/issues/10592

您可以通过将EVP_PKEY_set1_DH()调用替换为EVP_PKEY_assign()并将其指定为EVP_PKEY_DHX的类型来解决此问题,如下所示:

    if(1 != EVP_PKEY_assign(params, EVP_PKEY_DHX, DH_get_2048_256())) {
        std::cout << "error 4" << std::endl;
    }

或者,您可能只使用PKCS#3参数。

最后,没有得到任何共享机密的原因是,仅当EVP_PKEY_derive()调用失败时才打印它!它实际上是成功的!

我对您的代码进行了以下更改,它对我有用:

--- derive.cpp  2019-12-09 11:11:15.493349734 +0000
+++ derive-new.cpp  2019-12-09 11:14:59.348715074 +0000
@@ -37,7 +37,7 @@
     }

     // Set Diffie Hellman paramerers
-    if(1 != EVP_PKEY_set1_DH(params, DH_get_2048_256())) {
+    if(1 != EVP_PKEY_assign(params, EVP_PKEY_DHX, DH_get_2048_256())) {
         std::cout << "error 4" << std::endl;
     }

@@ -96,9 +96,11 @@
         std::cout << "error 15" << std::endl;
     }

+#if 0
     if(1 != EVP_PKEY_check(dctx1)) {
         std::cout << "error 16" << std::endl;
     }
+#endif

     if(1 != EVP_PKEY_param_check(dctx1)) {
         std::cout << "error 17" << std::endl;
@@ -120,7 +122,7 @@
     // Assign memory for shared key variable
     skey1 = (unsigned char*)OPENSSL_malloc(skeylen1);

-    if(result = EVP_PKEY_derive(dctx1, skey1, &skeylen1) <= 0) {
+    if((result = EVP_PKEY_derive(dctx1, skey1, &skeylen1)) > 0) {
         std::cout << "Key: " << skey1 << std::endl;

         for(int i = 0; i < skeylen1; i++) {
© www.soinside.com 2019 - 2024. All rights reserved.