本教程为openssl-1.1.1j.tar.gz为例子

第一步:下载OpenSSL源码


下载地址: https://www.openssl.org/source/
个人网盘: https://pan.ltools.vip/#/s/o8TJ

kv6h007q.png

选择 openssl-x.x.x?.tar.gz 其中 x.x.x? 为目前最新版本号
解压到任意目录下,后续的目录均用 PATH 代替

第二步:下载安装ActivePerl


下载地址:https://www.activestate.com/activeperl/downloads/
个人网盘: https://pan.ltools.vip/#/s/m4sP
如果这个网址打不开的话,可以直接百度搜索ActivePerl下载。
运行安装程序,一直下一步操作安装完成。这里默认安装在C:\Perl64。

kv6h158k.png

打开 C:\Perl64\site\lib\ActivePerl\Config.pm 文件,将400行左右的代码注释掉,如下图。

kv6h27u6.png

第三步:编译64位版本


1、打开VS2019的 x86_x64 Cross Tools Command Prompt for VS 2019 软件

kv6h3i09.png

kv6h3szh.png

2、使用 cd /d PATH 到我们的解压目录

3、使用 perl Configure VC-WIN64A no-asm no-shared --prefix="C:\Program Files\openssl_bin" 进行生成编译脚本

4、如果编译不过,出现LNK2019等错误的时候,你可能还需要添加ws2_32.lib,crypt32.lib库。打开我们的 PATH 目录下 makefile 文件,将如下位置 EX_LIBS 后添加 Crypt32.lib Ws2_32.lib

kv6h5enb.png

5、使用 nmake 进行编译

6、使用 nmake test 进行测试,出现 Result: PASS 则为成功

7、使用 nmake install 将编译好的文件拷贝到我们设定的目录下 C:\Program Files\openssl_bin

8、使用 nmake clean 清除上次静态库的编译,以便重新编译

第四步:编译32位版本

1、打开VS2019的 x64_x86 Cross Tools Command Prompt for VS 2019 软件

kv6h6vs7.png

kv6h70i4.png

2、使用 cd /d PATH 到我们的解压目录

3、使用 perl Configure VC-WIN32 no-asm no-shared --prefix="C:\Program Files (x86)\openssl_bin" 进行生成编译脚本

4、如果编译不过,出现LNK2019等错误的时候,你可能还需要添加ws2_32.lib,crypt32.lib库。打开我们的 PATH 目录下 makefile 文件,将如下位置 EX_LIBS 后添加 Crypt32.lib Ws2_32.lib

5、使用 nmake 进行编译

6、使用 nmake test 进行测试,出现 Result: PASS 则为成功

7、使用 nmake install 将编译好的文件拷贝到我们设定的目录下 C:\Program Files (x86)\openssl_bin

8、使用 nmake clean 清除上次静态库的编译,以便重新编译

第五步:使用openssl库

1、给项目包含目录添加我们编译好的openssl库文件中的 include 目录

2、在使用openssl库函数时,添加如下头文件(按需添加)即可,一下使用RSA为例:

1
2
3
4
#include <openssl/rsa.h>
#include <openssl/engine.h>
#include <openssl/pem.h>
#include <openssl/err.h>

3、将我们编译好的静态文件 libcrypto.lib 和 libssl.lib 添加至我们的项目中

1
2
#pragma comment(lib, "libssl.lib")
#pragma comment(lib, "libcrypto.lib")

4、进行编译,若出现如下错误请添加 ws2_32.lib 依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
1>libcrypto.lib(b_sock.obj) : error LNK2019: 无法解析的外部符号 __imp_ioctlsocket,函数 BIO_socket_ioctl 中引用了该符号
1>libcrypto.lib(b_sock.obj) : error LNK2019: 无法解析的外部符号 __imp_getsockname,函数 BIO_sock_info 中引用了该符号
1>libcrypto.lib(b_sock.obj) : error LNK2019: 无法解析的外部符号 __imp_getsockopt,函数 BIO_sock_error 中引用了该符号
1>libcrypto.lib(b_sock2.obj) : error LNK2001: 无法解析的外部符号 __imp_getsockopt
1>libcrypto.lib(b_sock.obj) : error LNK2019: 无法解析的外部符号 __imp_ntohs,函数 BIO_get_port 中引用了该符号
1>libcrypto.lib(b_addr.obj) : error LNK2001: 无法解析的外部符号 __imp_ntohs
1>libcrypto.lib(b_sock.obj) : error LNK2019: 无法解析的外部符号 __imp_gethostbyname,函数 BIO_gethostbyname 中引用了该符号
1>libcrypto.lib(b_sock.obj) : error LNK2019: 无法解析的外部符号 __imp_WSAStartup,函数 BIO_sock_init 中引用了该符号
1>libcrypto.lib(b_sock.obj) : error LNK2019: 无法解析的外部符号 __imp_WSACleanup,函数 bio_sock_cleanup_int 中引用了该符号
1>libcrypto.lib(b_sock.obj) : error LNK2019: 无法解析的外部符号 __imp_WSAGetLastError,函数 BIO_accept 中引用了该符号
1>libcrypto.lib(bss_sock.obj) : error LNK2001: 无法解析的外部符号 __imp_WSAGetLastError
1>libcrypto.lib(b_sock2.obj) : error LNK2001: 无法解析的外部符号 __imp_WSAGetLastError
1>libcrypto.lib(b_addr.obj) : error LNK2019: 无法解析的外部符号 __imp_getaddrinfo,函数 BIO_lookup 中引用了该符号
1>libcrypto.lib(b_addr.obj) : error LNK2019: 无法解析的外部符号 __imp_freeaddrinfo,函数 BIO_ADDRINFO_free 中引用了该符号
1>libcrypto.lib(b_addr.obj) : error LNK2019: 无法解析的外部符号 __imp_getnameinfo,函数 addr_strings 中引用了该符号
1>libcrypto.lib(bss_sock.obj) : error LNK2019: 无法解析的外部符号 __imp_recv,函数 sock_read 中引用了该符号
1>libcrypto.lib(bss_sock.obj) : error LNK2019: 无法解析的外部符号 __imp_send,函数 sock_write 中引用了该符号
1>libcrypto.lib(bss_sock.obj) : error LNK2019: 无法解析的外部符号 __imp_WSASetLastError,函数 sock_write 中引用了该符号
1>libcrypto.lib(b_sock2.obj) : error LNK2019: 无法解析的外部符号 __imp_accept,函数 BIO_accept_ex 中引用了该符号
1>libcrypto.lib(b_sock2.obj) : error LNK2019: 无法解析的外部符号 __imp_bind,函数 BIO_bind 中引用了该符号
1>libcrypto.lib(b_sock2.obj) : error LNK2019: 无法解析的外部符号 __imp_closesocket,函数 BIO_accept_ex 中引用了该符号
1>libcrypto.lib(b_sock2.obj) : error LNK2019: 无法解析的外部符号 __imp_connect,函数 BIO_connect 中引用了该符号
1>libcrypto.lib(b_sock2.obj) : error LNK2019: 无法解析的外部符号 __imp_listen,函数 BIO_listen 中引用了该符号
1>libcrypto.lib(b_sock2.obj) : error LNK2019: 无法解析的外部符号 __imp_setsockopt,函数 BIO_connect 中引用了该符号
1>libcrypto.lib(b_sock2.obj) : error LNK2019: 无法解析的外部符号 __imp_socket,函数 BIO_socket 中引用了该符号
1
#pragma comment(lib, "ws2_32.lib")

5、若出现如下错误请添加 Crypt32.lib 依赖

1
2
3
4
5
6
7
1>libcrypto.lib(e_capi.obj) : error LNK2019: 无法解析的外部符号 __imp_CertOpenStore,函数 capi_list_certs 中引用了该符号
1>libcrypto.lib(e_capi.obj) : error LNK2019: 无法解析的外部符号 __imp_CertCloseStore,函数 capi_find_key 中引用了该符号
1>libcrypto.lib(e_capi.obj) : error LNK2019: 无法解析的外部符号 __imp_CertEnumCertificatesInStore,函数 capi_find_cert 中引用了该符号
1>libcrypto.lib(e_capi.obj) : error LNK2019: 无法解析的外部符号 __imp_CertFindCertificateInStore,函数 capi_find_cert 中引用了该符号
1>libcrypto.lib(e_capi.obj) : error LNK2019: 无法解析的外部符号 __imp_CertDuplicateCertificateContext,函数 capi_load_ssl_client_cert 中引用了该符号
1>libcrypto.lib(e_capi.obj) : error LNK2019: 无法解析的外部符号 __imp_CertFreeCertificateContext,函数 capi_dsa_free 中引用了该符号
1>libcrypto.lib(e_capi.obj) : error LNK2019: 无法解析的外部符号 __imp_CertGetCertificateContextProperty,函数 capi_cert_get_fname 中引用了该符号

最后为RSA的完整示例代码

RSA头文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#pragma once

#include <openssl/rsa.h>
#include <openssl/engine.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <string>

#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "Crypt32.lib")
#pragma comment(lib, "libssl.lib")
#pragma comment(lib, "libcrypto.lib")

/// <summary>
/// 生成私钥公钥
/// </summary>
/// <param name="nPrime">素数, 默认值65537是官方推荐的一个数字</param>
/// <param name="nKeySize">密钥的位数, 默认值2048, 可以是别的值, 但最好是4的倍数, 且至少为1024</param>
/// <param name="strSavePath">存储位置, 默认值当前路径</param>
void CreateRSAPrivateAndPublicKey(int nPrime = 65537, int nKeySize = 2048, std::string strSavePath = "");

/// <summary>
/// 私钥加密
/// </summary>
/// <param name="strPrivateKey">私钥</param>
/// <param name="strData">明文</param>
/// <returns>密文</returns>
std::string RSAPrivateEncrypt(const std::string& strPrivateKey, const std::string& strData);

/// <summary>
/// 私钥解密
/// </summary>
/// <param name="strPrivateKey">私钥</param>
/// <param name="strData">密文</param>
/// <returns>明文</returns>
std::string RSAPrivateDecrypt(const std::string& strPrivateKey, const std::string& strData);


/// <summary>
/// 公钥加密
/// </summary>
/// <param name="strPublicKey">公钥</param>
/// <param name="strData">明文</param>
/// <returns>密文</returns>
std::string RSAPublicEncrypt(const std::string& strPublicKey, const std::string& strData);

/// <summary>
/// 公钥解密
/// </summary>
/// <param name="strPublicKey">公钥</param>
/// <param name="strData">密文</param>
/// <returns>明文</returns>
std::string RSAPublicDecrypt(const std::string& strPublicKey, const std::string& strData);

RSA源文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#include "RSA.h"
#include <assert.h>

// 生成新的公钥和私钥
void CreateRSAPrivateAndPublicKey(int nPrime, int nKeySize, std::string strSavePath)
{
RSA* rsa = RSA_new();
BIGNUM* e = BN_new();
BN_set_word(e, nPrime); // 65537是官方推荐的一个数字, 其实任意素数都是可以的
RSA_generate_key_ex(rsa, nKeySize, e, 0); // 2048表示密钥的位数, 可以是别的值, 但最好是4的倍数, 且至少为1024

// 使用BIO打开密钥文件
std::string privatePath = strSavePath + "privateKey.pem";
BIO* _pri = BIO_new_file(privatePath.c_str(), "w");
// 写入密钥
PEM_write_bio_RSAPrivateKey(_pri, rsa, NULL, NULL, 0, NULL, NULL);
// 使用BIO打开公钥文件
std::string publicPath = strSavePath + "publicKey.pem";
BIO* _pub = BIO_new_file(publicPath.c_str(), "w");
// 写入公钥
PEM_write_bio_RSAPublicKey(_pub, rsa);

BIO_free(_pub);
BIO_free(_pri);
BN_free(e);
RSA_free(rsa);
CRYPTO_cleanup_all_ex_data();
}

// 私钥加密
std::string RSAPrivateEncrypt(const std::string& strPrivateKey, const std::string& strData)
{
// 判断是否为空
if (strPrivateKey.empty() strData.empty())
{
assert(false);
return "";
}

// 读取私钥
RSA* pRSAPrivateKey = RSA_new();
BIO* bio = BIO_new(BIO_s_mem());
BIO_write(bio, strPrivateKey.c_str(), strPrivateKey.size());
pRSAPrivateKey = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);
if (pRSAPrivateKey == nullptr)
{
assert(false);
return "";
}

// 获取密钥长度
int nLen = RSA_size(pRSAPrivateKey);

// 返回结果
std::string strRet;

// 加密
char* pEncode = new char[nLen + 1];
int ret = RSA_private_encrypt(strData.length(), (const unsigned char*)strData.c_str(), (unsigned char*)pEncode, pRSAPrivateKey, RSA_PKCS1_PADDING);
if (ret >= 0)
{
strRet = std::string(pEncode, ret);
}
// 释放资源
delete[] pEncode;
RSA_free(pRSAPrivateKey);
CRYPTO_cleanup_all_ex_data();
return strRet;
}

// 私钥解密
std::string RSAPrivateDecrypt(const std::string& strPrivateKey, const std::string& strData)
{
// 判断是否为空
if (strPrivateKey.empty() strData.empty())
{
assert(false);
return "";
}

// 读取私钥
RSA* pRSAPrivateKey = RSA_new();
BIO* bio = BIO_new(BIO_s_mem());
BIO_write(bio, strPrivateKey.c_str(), strPrivateKey.size());
pRSAPrivateKey = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);
if (pRSAPrivateKey == nullptr)
{
assert(false);
return "";
}

// 获取密钥长度
int nLen = RSA_size(pRSAPrivateKey);

// 返回结果
std::string strRet;

// 解密
char* pEncode = new char[nLen + 1];
int ret = RSA_private_decrypt(strData.length(), (const unsigned char*)strData.c_str(), (unsigned char*)pEncode, pRSAPrivateKey, RSA_PKCS1_PADDING);
if (ret >= 0)
{
strRet = std::string(pEncode, ret);
}
// 释放资源
delete[] pEncode;
RSA_free(pRSAPrivateKey);
CRYPTO_cleanup_all_ex_data();
return strRet;
}

// 公钥加密
std::string RSAPublicEncrypt(const std::string& strPublicKey, const std::string& strData)
{
// 判断是否为空
if (strPublicKey.empty() strData.empty())
{
assert(false);
return "";
}

// 读取公钥
RSA* pRSAPublicKey = RSA_new();
BIO* bio = BIO_new(BIO_s_mem());
BIO_write(bio, strPublicKey.c_str(), strPublicKey.size());
pRSAPublicKey = PEM_read_bio_RSAPublicKey(bio, NULL, NULL, NULL);
if (pRSAPublicKey == nullptr)
{
assert(false);
return "";
}

// 获取密钥长度
int nLen = RSA_size(pRSAPublicKey);

// 返回结果
std::string strRet;

// 加密
char* pEncode = new char[nLen + 1];
int ret = RSA_public_encrypt(strData.length(), (const unsigned char*)strData.c_str(), (unsigned char*)pEncode, pRSAPublicKey, RSA_PKCS1_PADDING);
if (ret >= 0)
{
strRet = std::string(pEncode, ret);
}
// 释放资源
delete[] pEncode;
RSA_free(pRSAPublicKey);
CRYPTO_cleanup_all_ex_data();
return strRet;
}

// 公钥解密
std::string RSAPublicDecrypt(const std::string& strPublicKey, const std::string& strData)
{
// 判断是否为空
if (strPublicKey.empty() strData.empty())
{
assert(false);
return "";
}

// 读取公钥
RSA* pRSAPublicKey = RSA_new();
BIO* bio = BIO_new(BIO_s_mem());
BIO_write(bio, strPublicKey.c_str(), strPublicKey.size());
pRSAPublicKey = PEM_read_bio_RSAPublicKey(bio, NULL, NULL, NULL);
if (pRSAPublicKey == nullptr)
{
assert(false);
return "";
}

// 获取密钥长度
int nLen = RSA_size(pRSAPublicKey);

// 返回结果
std::string strRet;

// 解密
char* pEncode = new char[nLen + 1];
int ret = RSA_public_decrypt(strData.length(), (const unsigned char*)strData.c_str(), (unsigned char*)pEncode, pRSAPublicKey, RSA_PKCS1_PADDING);
if (ret >= 0)
{
strRet = std::string(pEncode, ret);
}
// 释放资源
delete[] pEncode;
RSA_free(pRSAPublicKey);
CRYPTO_cleanup_all_ex_data();
return strRet;
}

RSA使用实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <string>
#include "RSA.h"

using namespace std;

string privateKey = "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEA9Bhk806dD+exe+rnBEInMhJ9zaE0Ok/3iscSiT9uI/mKdtj2\nQfQ4QH9yRHbIm+yFaPo+xOd2jVjJcJtDiHFk/4IjuE65OWaI7wryMa5/SP8GijNm\nDpPHNbNVfGrL+qL7+H6tZZ9ggFxgE2bqw97MBAW63DtAzeFeQyleHtxUpwRONazU\nYOhz2CZAqOUSoxwztx8CWtZSCNOV4cs67e7Q/uyuZPIxlS2z2MgI65/ez4vqZkj6\nbJHHb5c7gd4MMbnZ54xWI+S3mtcrOF8SV5ITTtt+tgGygm1kNeasKJRRqKqib2IE\nuRo1taKKr++Q9hSBk95saqcKkovyqinr6v1yCQIDAQABAoIBAQChfwJLd9eyjjh/\nJAt0ZdBI8LMLOXy0l/PPfaZl5/GXG6Lgvusu98W/5pJTecOAZhxeODMPU5S8L+IW\n/qLPwzZvVksLxgoGUDCI91UGSc0tHo3VIeyD+IH0pZIJnx8V1H+hCS7v7WKLipKG\nQ7FPpjiU8LWQwCNAE7up89Sx1lSrqoLMf5oyKbZ42Jld0oFBmljp/EW6Mo7tvQlv\nI5tAYccNHKvVwqYk1VMEU9LBqHDLpJXeRMxlxQTB2cfEr/CaAkCJE2mf5REFgsuB\nJ36AwRfKLcwFDPCv9r850l+AYh5NRlkp3FwIi+s5obpMGUfnCdcQMBmcerwwkTyf\ntoUl892BAoGBAPpkQcIGBiegPncUih9RXvEbNx/lmuqncWTd6DcjMuX2Of2ll32V\n1g4Nc8SzfHl3TZPe0qTN61NqH8ZIubNObz+5C8Fa9k+fSeQIbE5iYx2U+9ZLLmFg\nSq7QcAxprWIm5Bu7r6XWzPJtrIjoJ0JF0T3oxITKnaJiCIDhPoSTpPFrAoGBAPmQ\nCMnj1ccB+K7/ODFbx05MDWONpkjFonrQnBrRXThoRklLRA5DAYsxT5iLS7fJ2mKa\nk13eyJZdtJ1JD6DPuGcai/7ZeGn/l2E8fpNapCPyhQeG1CIbqwa6MGGqfPQjqTQ7\nmWWoEH/lEvwH5yx9hlh8ZKnFUyIHoBV8qvMrjiNbAoGBAKBa4q4SU5C/FCII+mgS\nIZ6Bkm0QC4Vp1LoHT3c4SJlzdjIWAY3BDsQTI2f+lqHnoLwpgHdhFOtn1I+U9bB6\nc864gGnFCmd1mMm8Bziv09AXIK1dmodsNof8HzYj25E3XPDR4yxvAvPi/xLysmnD\n8rwWPPzaEdfztoRrPDGFqKWfAoGBAIHh0HEiPlRAVmjdMyWdGnFJa35wbiZZlWJN\nx7C9XcLJoirrHRQ/E0KZ+07s0A9q4lmHEUM9ey+mvSVOrO+Iq/QdANc131FrUCGv\nFkEiX2LGCS4NocHOnIf3xs5NqJJ3LMyeaAtcGJo3YlYA1vN0sMLEmq8wnz+KsGn+\nZAoClQsZAoGAcsOZnAUfRpdu5H1femhlU83MzpdDNsIcgEp6m0on0i4q/e4n2VgJ\nBXi1/K1tbnU2cU6A4FmLlJ1i9Lf7JAdycylRm5BG9ynXeb3uligxh0kN5SvIiADY\n7MLCB6DyqyXaD7uf903lWJOOlBQpL+aypUAQ5jLyr9zaVDiDwuzPAYU=\n-----END RSA PRIVATE KEY-----";
string publicKey = "-----BEGIN RSA PUBLIC KEY-----\nMIIBCgKCAQEA9Bhk806dD+exe+rnBEInMhJ9zaE0Ok/3iscSiT9uI/mKdtj2QfQ4\nQH9yRHbIm+yFaPo+xOd2jVjJcJtDiHFk/4IjuE65OWaI7wryMa5/SP8GijNmDpPH\nNbNVfGrL+qL7+H6tZZ9ggFxgE2bqw97MBAW63DtAzeFeQyleHtxUpwRONazUYOhz\n2CZAqOUSoxwztx8CWtZSCNOV4cs67e7Q/uyuZPIxlS2z2MgI65/ez4vqZkj6bJHH\nb5c7gd4MMbnZ54xWI+S3mtcrOF8SV5ITTtt+tgGygm1kNeasKJRRqKqib2IEuRo1\ntaKKr++Q9hSBk95saqcKkovyqinr6v1yCQIDAQAB\n-----END RSA PUBLIC KEY-----";

int main()
{
std::string strTest = "测试文本";
std::string strRet;
// 测试私钥加密公钥解密
//strRet = RSAPrivateEncrypt(privateKey, strTest);
//cout << strRet << endl;
//strRet = RSAPublicDecrypt(publicKey, strRet);
//cout << strRet << endl;
// 测试公钥加密私钥解密
strRet = RSAPublicEncrypt(publicKey, strTest);
cout << strRet << endl;
strRet = RSAPrivateDecrypt(privateKey, strRet);
cout << strRet << endl;
return 0;
}

写在最后

上面的我想必你一定学会怎么配置openssl和使用他了,那么再说一个更简单的使用办法就是使用vcpkg可以非常简单的编译并使用openssl库,哈哈哈哈哈哈哈哈哈哈。