OpenSSL 1.1.0 中的 EVP_get_cipherbyname 和“未定义的结构/联合 evp_cipher_st”

Posted

技术标签:

【中文标题】OpenSSL 1.1.0 中的 EVP_get_cipherbyname 和“未定义的结构/联合 evp_cipher_st”【英文标题】:EVP_get_cipherbyname and "undefined struct/union evp_cipher_st" in OpenSSL 1.1.0 【发布时间】:2017-01-28 11:04:50 【问题描述】:

我正在尝试将 openssl 与 Visual Studio C 项目一起使用。

我使用 Visual Studio nmake 命令编译了 openssl,然后使用以下命令将所有内容安装到预定义文件夹 (C:\openssl):

nmake install

文件夹结构如下:

bin

include/openssl

lib

在include/openssl里面有.h头文件。

在我的 Visual Studio 2012 中,我创建了一个空的通用 c++ 项目并包含 C:\openssl\include

[Project properties -> C/C++ -> General -> Additional Include Directories]

我还添加了 lib 目录和 .lib 文件。

但是当我编译代码时,我得到了

left of 'key_len' specifies undefined struct/union 'evp_cipher_st'

在我的代码中我有这些行

const EVP_CIPHER *cipher = EVP_get_cipherbyname("aes-256-cbc");
//some other code
return cipher->key_len;

查看 ossl_typ.h 文件中的 evp_cipher_st 定义,它被声明为

typedef struct evp_cipher_st EVP_CIPHER;

结构体没有定义!

深入挖掘源代码树,evp_cipher_st 定义在 crypto\include\internal\evp_int.h 中,它不包含在 openssl 安装文件夹的 include 文件夹中。

我还尝试将 crypto\include\internal\evp_int.h 包含在内,但它会导致更多问题。

知道如何解决这个问题吗?

更新:

这是完整的功能和我的主要功能,包括所有包括:

#include <winsock2.h>
#include <Ws2tcpip.h>
#include <mswsock.h>
#include <windows.h>
#include <minwindef.h>
#include <malloc.h>
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef int socklen_t;
#include "wingetopt.h"
#include <Wincrypt.h>
#include <iphlpapi.h>
#include "Shlwapi.h"
#include <Bcrypt.h>

#define inline __inline
#define STATUS_SUCCESS 0

#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "Shlwapi.lib")

#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <fcntl.h>
#include <time.h>

int generate_aes_key(const unsigned char *input_key, uint16_t input_key_size,
            unsigned char *output_key, uint16_t *outputkey_size) 

        const EVP_MD *dgst = NULL;
        unsigned char iv[EVP_MAX_IV_LENGTH];
        const EVP_CIPHER *cipher = EVP_get_cipherbyname("aes-256-cbc");

        if(!cipher) 

            return -1;
        

        dgst = EVP_get_digestbyname("sha256");

        if(!dgst) 

            fprintf(stderr, "no such digest\n");
            return -2;
        

        if(!EVP_BytesToKey(cipher, dgst, NULL, input_key, input_key_size, 1, output_key, iv)) 

            return -3;
        

        *outputkey_size = (uint16_t)cipher->key_len;

        return 0;


int main(int argc, char *argv[]) 

    char secret[] = "MIIFBTCCAu2gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwTjELMAkGA1UEBhMCR0Ix";

    unsigned char shared_secret[500];
    uint16_t aes_keylen = 0;

    //bunch of codes 

    if(generate_aes_key((unsigned char *)secret, strlen(secret), shared_secret, &aes_keylen) < 0) 

        fprintf(stderr, "Could not get initial shared secret\n");
        return 0;
    

    //other codes

Openssl 版本是:

OpenSSL_1_1_0-pre6-1266-g487d3a726

以上版本是来自 git 的最新标签名称,我认为它是迄今为止最新鲜的。最新的提交版本和日期如下:

487d3a726a1970e84853434561d88cb4ac212d15

作者:EasySec 日期:2017 年 1 月 17 日星期二 17:21:55 +0100

最后是 Visual Studio 2012 的编译输出:

Build started 1/28/2017 8:23:02 PM.
 1>Project "C:\CODE\mycode.vcxproj" on node 2 (Build target(s)).
 1>ClCompile:
     C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\CL.exe /c /I"c:\openssl\include" /ZI /nologo /W3 /WX- /Od /Oy- /D _MBCS /Gm /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Fo"Debug\\" /Fd"Debug\vc110.pdb" /Gd /TC /analyze- /errorReport:prompt src\main.c ... 

     wingetopt.c
 1>c:\openssl\include\openssl\lhash.h(198): warning C4090: 'function' : different 'const' qualifiers
     client.c
 1>c:\openssl\include\openssl\lhash.h(198): warning C4090: 'function' : different 'const' qualifiers
     client.c
 1>c:\openssl\include\openssl\lhash.h(198): warning C4090: 'function' : different 'const' qualifiers
     client.c
 1>c:\openssl\include\openssl\lhash.h(198): warning C4090: 'function' : different 'const' qualifiers
     client.c
 1>c:\openssl\include\openssl\lhash.h(198): warning C4090: 'function' : different 'const' qualifiers
     client.c
 1>c:\openssl\include\openssl\lhash.h(198): warning C4090: 'function' : different 'const' qualifiers
     client.c
 1>c:\openssl\include\openssl\lhash.h(198): warning C4090: 'function' : different 'const' qualifiers
     client.c
 1>c:\openssl\include\openssl\lhash.h(198): warning C4090: 'function' : different 'const' qualifiers
     client.c
 1>c:\openssl\include\openssl\lhash.h(198): warning C4090: 'function' : different 'const' qualifiers
     client.c
 1>c:\openssl\include\openssl\lhash.h(198): warning C4090: 'function' : different 'const' qualifiers
     client.c
 1>c:\openssl\include\openssl\lhash.h(198): warning C4090: 'function' : different 'const' qualifiers
     client.c
 1>c:\openssl\include\openssl\lhash.h(198): warning C4090: 'function' : different 'const' qualifiers
     client.c
 1>c:\openssl\include\openssl\lhash.h(198): warning C4090: 'function' : different 'const' qualifiers
     client.c
 1>c:\openssl\include\openssl\lhash.h(198): warning C4090: 'function' : different 'const' qualifiers
     crypto.c
 1>c:\openssl\include\openssl\lhash.h(198): warning C4090: 'function' : different 'const' qualifiers
 1>c:\CODE\src\crypto.c(517): error C2037: left of 'key_len' specifies undefined struct/union 'evp_cipher_st'
     client.c
 1>c:\openssl\include\openssl\lhash.h(198): warning C4090: 'function' : different 'const' qualifiers
     client.c
 1>c:\openssl\include\openssl\lhash.h(198): warning C4090: 'function' : different 'const' qualifiers
     Generating Code...
 1>Done Building Project "C:\CODE\mycode.vcxproj" (Build target(s)) -- FAILED.

Build FAILED.

Time Elapsed 00:00:08.55

【问题讨论】:

您应该包含evp.h。你这样做吗?否则,请提供Minimal, Complete, and Verifiable Example。实际上,我们需要查看完整的 main 以及您正在调用的函数。我们可能需要查看编译命令,因此您也应该提供它。最后,说明您使用的 OpenSSL 版本。 我也包含了 evp.h,但它没有做任何事情。好的,我会用其他信息更新问题,谢谢 从您的编译命令来看,这看起来不错:I"c:\openssl\include"。您的程序中没有evp.h。你应该包括&lt;openssl/evp.h&gt; @jww 听起来,对于较新版本的 openssl,不需要为 evp_cipher_st 结构包含 evp.h 文件。它变成了不透明的类型。无论如何感谢您的跟进 【参考方案1】:

您可以使用以下方法获取密钥长度

*outputkey_size = EVP_CIPHER_key_length(cipher);

将下一行放在代码的末尾:

printf("Key-size: %d\n", aes_keylen);
printf("Key: "); for (int i = 0; i<aes_keylen; ++i)  printf("%02x", shared_secret[i]);  printf("\n");

它打印正确的输出,接下来是:

Key-size: 32
Key: 51ae3ac4721439302cc5f90313f440bd9ca714c9a80b2213d034c87c00a700a0

我不确定 key_len 在以前的版本中是否可用,但您可以在 openssl-1.10 release notes 中阅读:

大多数 libcrypto 和 libssl 公共结构是不透明的,包括:BIGNUM 和相关类型、EC_KEY 和 EC_KEY_METHOD、DH 和 DH_METHOD、DSA 和 DSA_METHOD、RSA 和 RSA_METHOD、BIO 和 BIO_METHOD、EVP_MD_CTX、EVP_MD、EVP_CIPHER_CTX、EVP_CIPHER、EVP_PKEY 和相关的类型,HMAC_CTX,X509,X509_CRL,X509_OBJECT, X509_STORE_CTX、X509_STORE、X509_LOOKUP、X509_LOOKUP_METHOD libssl 内部结构变得不透明

这意味着不再允许应用程序查看结构的变量内部。这就是 _key_len(和其他)显示未定义的原因。

【讨论】:

谢谢@jgorosdev 该解决方案运行良好。听起来这个结构已成为较新的 openssl 版本的不透明类型 @pendrive - 看起来你遇到了Error: “invalid use of incomplete type ‘RSA aka struct rsa_st” in OpenSSL 1.1.0 和Visual Studio and error C2027: use of undefined type 'rsa_st'

以上是关于OpenSSL 1.1.0 中的 EVP_get_cipherbyname 和“未定义的结构/联合 evp_cipher_st”的主要内容,如果未能解决你的问题,请参考以下文章

Linux笔记-Centos7编译安装GmSSL

君正X2000交叉编译openssl

OpenSSL 1.1.0 中的 EVP_get_cipherbyname 和“未定义的结构/联合 evp_cipher_st”

arm-xm-linux交叉编译openssl

Openssl:错误“证书链中的自签名证书”

centos6-openssl1.1.0e安装