C++ 无法使用C+;中的OpenSSL派生Diffie Hellman共享机密+;
我试图熟悉OpenSSL Diffie-Hellman的特性,在这样做的过程中,我试图创建一个简单的程序,它将生成两组Diffie-Hellman私钥和公钥,然后派生出共享密钥。我遵循了OpenSSL wiki上的Diffie Hellman教程,我能够生成密钥,但是我无法导出共享密钥。我的C++(Linux)代码如下:C++ 无法使用C+;中的OpenSSL派生Diffie Hellman共享机密+;,c++,openssl,diffie-hellman,C++,Openssl,Diffie Hellman,我试图熟悉OpenSSL Diffie-Hellman的特性,在这样做的过程中,我试图创建一个简单的程序,它将生成两组Diffie-Hellman私钥和公钥,然后派生出共享密钥。我遵循了OpenSSL wiki上的Diffie Hellman教程,我能够生成密钥,但是我无法导出共享密钥。我的C++(Linux)代码如下: #include <iostream> #include <openssl/dh.h> #include <openssl/engine.h>
#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;
}
if(1 != EVP_PKEY_assign(params, EVP_PKEY_DHX, DH_get_2048_256())) {
std::cout << "error 4" << std::endl;
}
当我使用
if(NULL == (dctx1 = EVP_PKEY_CTX_new(dh_1, NULL))) {
std::cout << "error 13" << std::endl;
}
当我将“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;
}
if(NULL==(dctx1=EVP\u PKEY\u CTX\u new(params,NULL))){
std::cout对于您发布的代码版本,我得到了与您略有不同的错误。我从您的代码中得到以下输出(与OpenSSL 1.1.1链接):
第一个“错误16”输出只是因为OpenSSL目前不支持对Diffie-Hellman密钥的EVP\u PKEY\u check()
调用。因此可以安全地忽略这一点
第二个“error 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中的一个bug(EVP_PKEY_set1_DH()
应该真正检测到它是什么类型的密钥并做正确的事情),因此我为此提出了以下OpenSSL问题:
您可以将EVP\u PKEY\u set1\u DH()
调用替换为一个toEVP\u PKEY\u assign()
,并将类型指定为EVP\u PKEY\u DHX
,如下所示:
#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;
}
if(1 != EVP_PKEY_assign(params, EVP_PKEY_DHX, DH_get_2048_256())) {
std::cout << "error 4" << std::endl;
}
上面是伊犁曲线Diffie和Hellman。OpenSSL 3的一个工作示例(无伊犁曲线)
你说你无法导出共享秘密。当你尝试时会发生什么?当你调用ERR\u print\u errors\u fp
时,你会收到某种错误消息吗?如果是这样,那是什么?在你遇到麻烦之前,这个过程能走多远?嗨@MattCaswell,我更新了我的帖子来回答你的问题。谢谢!令人惊讶的是,这解决了我的问题,谢谢您的帮助!顺便问一下,您是如何发现的:“但是函数EVP_PKEY_set1_DH()希望提供的DH对象是PKCS#3密钥。”我是OpenSSL开发人员;-)
if(1 != EVP_PKEY_assign(params, EVP_PKEY_DHX, DH_get_2048_256())) {
std::cout << "error 4" << std::endl;
}
--- 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++) {