一、环境准备
ActivePerl - ActivePerl-5.26.3.2603-MSWin32-x64-a95bce075.exe
nasm - nasm-2.14.02-installer-x64.exe
以上两个下载地址:【免费】windows、vs2017编译64位openssl-1.1.1v所需要用到的ActivePerl和nasm资源-CSDN文库
以上两个工具都全部默认安装即可;
如上,需确保两个工具的路径存在于环境变量中,如没有,请手动添加;
如上,管理员身份使用vs2017的命令行工具分别执行perl -v和nasm -v,得到版本信息则两个工具的环境已经正常;
二、编译
依然以管理员身份使用vs2017的命令行工具进入到openssl的源码目录:
配置编译:
编译动态库:
perl configure VC-WIN64A --prefix=D:\lib\OpenSSL\x64
编译静态库:
perl configure no-shared VC-WIN64A --prefix=D:\lib\OpenSSL\x64
此阶段可能会出现如下报错:Can't open perl script "configure": No such file or directory
这时候检查下你的目录是否正确,一般会是cd进入的目录有误导致
编译:nmake
安装到目录:nmake install
三、使用
测试源码如下:
#include <string>
/** 基于openssl对字符串进行base64编码:c_original-原始字符串,i_len-原始字符串长度 */
std::string string_encode_openssl_base64(const char *c_original, int i_len);
/** 基于openssl对字符串进行base64解码:ss_base64-base64字符串,c_original-原始字符串,s_len-原始字符串长度 */
void string_decode_openssl_base64(const std::string &ss_base64, char *c_original, size_t &s_len);
/** 基于openssl的des加密算法以cfb64模式对字符串进行加密(加密前后长度一致,不存在补'\0'情况):c_original-原始字符串,i_len-原始字符串长度,c_encrypt-加密字符串,ss_key_1-密匙1,ss_key_2-密匙2,ss_key_3-密匙3 */
void string_encrypt_openssl_des_cfb64(char *c_original, int i_len, char *c_encrypt, const std::string &ss_key_1 = "", const std::string &ss_key_2 = "", const std::string &ss_key_3 = "");
/** 基于openssl的des解密算法以cfb64模式对字符串进行解密(解密前后长度一致,不存在补'\0'情况):c_encrypt-加密字符串,i_len-加密字符串长度,c_encrypt-原始字符串,ss_key_1-密匙1,ss_key_2-密匙2,ss_key_3-密匙3 */
void string_decrypt_openssl_des_cfb64(char *c_encrypt, int i_len, char *c_original, const std::string &ss_key_1 = "", const std::string &ss_key_2 = "", const std::string &ss_key_3 = "");
/** 基于openssl的des加密算法以cbc模式对字符串进行加密:ss_original-原始字符串(必须使用确定不会出现'\0'的字符串,否则在解密阶段处理结尾恰好为'\0'的字符串会丢失内容),ss_key-密匙 */
std::string string_encrypt_openssl_des_cbc(const std::string &ss_original, const std::string &ss_key = "");
/** 基于openssl的des解密算法以cbc模式对字符串进行解密:ss_encrypt-加密字符串,ss_key-密匙 */
std::string string_decrypt_openssl_des_cbc(const std::string &ss_encrypt, const std::string &ss_key = "");
/** 基于openssl的des加密算法以ecb模式对字符串进行加密:ss_original-原始字符串(必须使用确定不会出现'\0'的字符串,否则在解密阶段处理结尾恰好为'\0'的字符串会丢失内容),ss_key-密匙 */
std::string string_encrypt_openssl_des_ecb(const std::string &ss_original, const std::string &ss_key = "");
/** 基于openssl的des解密算法以ecb模式对字符串进行解密:ss_encrypt-加密字符串,ss_key-密匙 */
std::string string_decrypt_openssl_des_ecb(const std::string &ss_encrypt, const std::string &ss_key = "");
#include "OpensslCommon.h"
#include "openssl/bio.h"
#include "openssl/evp.h"
#include "openssl/buffer.h"
#include "openssl/des.h"
#include <vector>
#pragma warning(disable:4996)
std::string string_encode_openssl_base64(const char *c_original, int i_len)
{
std::string ss_base64 = "";
if (c_original != nullptr && i_len > 0)
{
BIO *base64_bio = BIO_new(BIO_f_base64());//base64过滤器:编解码操作的bio接口
if (base64_bio != nullptr)
{
BIO_set_flags(base64_bio, BIO_FLAGS_BASE64_NO_NL);//去掉所有换行符
BIO *mem_bio = BIO_new(BIO_s_mem());//内存读写操作的bio接口
if (mem_bio != nullptr)
{
BIO_push(base64_bio, mem_bio);
if (BIO_write(base64_bio, c_original, i_len) > 0)
{
BIO_flush(base64_bio);
BUF_MEM *p_data = nullptr;
BIO_get_mem_ptr(base64_bio, &p_data);
if (p_data != nullptr)
{
ss_base64 = std::string(p_data->data, p_data->length);
}
}
}
BIO_free_all(base64_bio);
}
}
return ss_base64;
}
void string_decode_openssl_base64(const std::string &ss_base64, char *c_original, size_t &s_len)
{
s_len = 0;
if (c_original == nullptr)
{
return;
}
BIO *base64_bio = BIO_new(BIO_f_base64());
if (base64_bio == nullptr)
{
return;
}
BIO_set_flags(base64_bio, BIO_FLAGS_BASE64_NO_NL);
BIO *mem_bio = BIO_new_mem_buf(ss_base64.c_str(), ss_base64.length());
if (mem_bio == nullptr)
{
BIO_free_all(base64_bio);
return;
}
BIO_push(base64_bio, mem_bio);
BIO_read_ex(base64_bio, c_original, ss_base64.length() + 1, &s_len);
if (s_len <= 0)
{
BIO_free_all(base64_bio);
return;
}
BIO_free_all(base64_bio);
}
void string_encrypt_openssl_des_cfb64(char *c_original, int i_len, char *c_encrypt, const std::string &ss_key_1, const std::string &ss_key_2, const std::string &ss_key_3)
{
if (c_original == nullptr || i_len <= 0 || c_encrypt == nullptr)
{
return;
}
DES_cblock key;
memset(key, 0, sizeof(DES_cblock));
memcpy(key, ss_key_1.c_str(), ss_key_1.length() <= 8 ? ss_key_1.length() : 8);
DES_key_schedule key_schedule_1 = {};
DES_set_key_unchecked(&key, &key_schedule_1);
memset(key, 0, sizeof(DES_cblock));
memcpy(key, ss_key_2.c_str(), ss_key_2.length() <= 8 ? ss_key_2.length() : 8);
DES_key_schedule key_schedule_2 = {};
DES_set_key_unchecked(&key, &key_schedule_2);
memset(key, 0, sizeof(DES_cblock));
memcpy(key, ss_key_3.c_str(), ss_key_3.length() <= 8 ? ss_key_3.length() : 8);
DES_key_schedule key_schedule_3 = {};
DES_set_key_unchecked(&key, &key_schedule_3);
DES_cblock ivec = {};
int num = 0;
DES_ede3_cfb64_encrypt((const unsigned char *)c_original, (unsigned char *)c_encrypt, i_len, &key_schedule_1, &key_schedule_2, &key_schedule_3, &ivec, &num, DES_ENCRYPT);
}
void string_decrypt_openssl_des_cfb64(char *c_encrypt, int i_len, char *c_original, const std::string &ss_key_1, const std::string &ss_key_2, const std::string &ss_key_3)
{
if (c_encrypt == nullptr || i_len <= 0 || c_original == nullptr)
{
return;
}
DES_cblock key;
memset(key, 0, sizeof(DES_cblock));
memcpy(key, ss_key_1.c_str(), ss_key_1.length() <= 8 ? ss_key_1.length() : 8);
DES_key_schedule key_schedule_1 = {};
DES_set_key_unchecked(&key, &key_schedule_1);
memset(key, 0, sizeof(DES_cblock));
memcpy(key, ss_key_2.c_str(), ss_key_2.length() <= 8 ? ss_key_2.length() : 8);
DES_key_schedule key_schedule_2 = {};
DES_set_key_unchecked(&key, &key_schedule_2);
memset(key, 0, sizeof(DES_cblock));
memcpy(key, ss_key_3.c_str(), ss_key_3.length() <= 8 ? ss_key_3.length() : 8);
DES_key_schedule key_schedule_3 = {};
DES_set_key_unchecked(&key, &key_schedule_3);
DES_cblock ivec = {};
int num = 0;
DES_ede3_cfb64_encrypt((const unsigned char *)c_encrypt, (unsigned char *)c_original, i_len, &key_schedule_1, &key_schedule_2, &key_schedule_3, &ivec, &num, DES_DECRYPT);
}
std::string string_encrypt_openssl_des_cbc(const std::string &ss_original, const std::string &ss_key)
{
size_t s_len = (ss_original.length() + 7) / 8 * 8;
unsigned char *output = nullptr;
try
{
output = new unsigned char[s_len + 1];
}
catch (const std::exception &e)
{
return "";
}
DES_cblock key = {};
memcpy(key, ss_key.c_str(), ss_key.length() <= 8 ? ss_key.length() : 8);
DES_key_schedule key_schedule = {};
DES_set_key_unchecked(&key, &key_schedule);
DES_cblock ivec = {};
DES_ncbc_encrypt((const unsigned char *)ss_original.c_str(), output, ss_original.length(), &key_schedule, &ivec, DES_ENCRYPT);
std::string ss_encrypt = std::string((char *)output, s_len);
delete output;
output = nullptr;
return ss_encrypt;
}
std::string string_decrypt_openssl_des_cbc(const std::string &ss_encrypt, const std::string &ss_key)
{
size_t s_len = ss_encrypt.length();
unsigned char *output = nullptr;
try
{
output = new unsigned char[s_len + 1];
}
catch (const std::exception &e)
{
return "";
}
DES_cblock key = {};
memcpy(key, ss_key.c_str(), ss_key.length() <= 8 ? ss_key.length() : 8);
DES_key_schedule key_schedule = {};
DES_set_key_unchecked(&key, &key_schedule);
DES_cblock ivec = {};
DES_ncbc_encrypt((const unsigned char *)ss_encrypt.c_str(), output, s_len, &key_schedule, &ivec, DES_DECRYPT);
for (size_t i = s_len - 1; i >= 0; i--)
{
if(*(output+i) != '\0')
{
break;
}
s_len--;
}
std::string ss_decrypt = std::string((char *)output, s_len);
delete output;
output = nullptr;
return ss_decrypt;
}
std::string string_encrypt_openssl_des_ecb(const std::string &ss_original, const std::string &ss_key)
{
DES_cblock key = {};//密钥
memcpy(key, ss_key.c_str(), ss_key.length() <= 8 ? ss_key.length() : 8);
DES_key_schedule key_schedule = {};//存放密钥的结构体
DES_set_key_unchecked(&key, &key_schedule);
const_DES_cblock input = {};//需要加密的数据
DES_cblock output = {};//加密后的数据
unsigned char tmp[8] = {};
std::vector<unsigned char> svuc_encrypt = {};
for (int i = 0; i < ss_original.length() / 8; i++)//8字节循环加密
{
memcpy(input, ss_original.c_str() + i * 8, 8);
DES_ecb_encrypt(&input, &output, &key_schedule, DES_ENCRYPT);
memcpy(tmp, output, 8);
for (int j = 0; j < 8; j++)
{
svuc_encrypt.push_back(tmp[j]);
}
}
if (ss_original.length() % 8 != 0)//超过8的倍数的部分的字节依然8字节循环加密
{
int tmp1 = ss_original.length() / 8 * 8;
int tmp2 = ss_original.length() - tmp1;
memset(input, 0, 8);//全部置为'\0',这样因长度不足而被补充的字节在解密的阶段解析出来也是'\0',解密阶段去掉结尾的'\0'即可
memcpy(input, ss_original.c_str() + tmp1, tmp2);
DES_ecb_encrypt(&input, &output, &key_schedule, DES_ENCRYPT);
memcpy(tmp, output, 8);
for (int j = 0; j < 8; j++)
{
svuc_encrypt.push_back(tmp[j]);
}
}
std::string ss_encrypt = "";
ss_encrypt.assign(svuc_encrypt.begin(), svuc_encrypt.end());
return ss_encrypt;
}
std::string string_decrypt_openssl_des_ecb(const std::string &ss_encrypt, const std::string &ss_key)
{
DES_cblock key = {};
memcpy(key, ss_key.c_str(), ss_key.length() <= 8 ? ss_key.length() : 8);
DES_key_schedule key_schedule = {};
DES_set_key_unchecked(&key, &key_schedule);
const_DES_cblock input = {};
DES_cblock output = {};
unsigned char tmp[8] = {};
std::vector<unsigned char> svuc_decrypt = {};
for (int i = 0; i < ss_encrypt.length() / 8; i++)
{
memcpy(input, ss_encrypt.c_str() + i * 8, 8);
DES_ecb_encrypt(&input, &output, &key_schedule, DES_DECRYPT);
memcpy(tmp, output, 8);
for (int j = 0; j < 8; j++)
{
if (i == (ss_encrypt.length() / 8 - 1))//结尾的数据
{
if (tmp[j] != '\0')//不要多余的'\0'
{
svuc_decrypt.push_back(tmp[j]);
}
}
else
{
svuc_decrypt.push_back(tmp[j]);
}
}
}
std::string ss_decrypt = "";
ss_decrypt.assign(svuc_decrypt.begin(), svuc_decrypt.end());
return ss_decrypt;
}
#include "OpensslCommon.h"
//#define openssl_base64
#define openssl_cfb64
int main(int argc, char **argv)
{
#ifdef openssl_base64
char c_original[20] = {};
memcpy(c_original, "this is an", 10);
c_original[10] = '\0';
memcpy(c_original + 11, " example", 8);
printf("*****\n");
for (size_t i = 0; i < 19; i++)
{
if (*(c_original + i) == '\0')
{
printf("-");
}
else
{
printf("%c", *(c_original + i));
}
}
printf("\n");
std::string ss_base64 = string_encode_openssl_base64(c_original, 19);
printf("*****\n");
printf("%s - %llu\n", ss_base64.c_str(), ss_base64.length());
memset(c_original, 0, sizeof(c_original));
size_t s_len = 0;
string_decode_openssl_base64(ss_base64, c_original, s_len);
if (s_len > 0)
{
printf("*****\n");
for (size_t i = 0; i < s_len; i++)
{
if (*(c_original + i) == '\0')
{
printf("-");
}
else
{
printf("%c", *(c_original + i));
}
}
printf("\n");
}
#endif
#ifdef openssl_cfb64
char c_original[20] = {};
memcpy(c_original, "this is an", 10);
c_original[10] = '\0';
memcpy(c_original + 11, " example", 8);
printf("*****\n");
for (size_t i = 0; i < 19; i++)
{
if (*(c_original + i) == '\0')
{
printf("-");
}
else
{
printf("%c", *(c_original + i));
}
}
printf("\n");
char c_encrypt[20] = {};
std::string ss_key_1 = "11111111";
std::string ss_key_2 = "22222222";
std::string ss_key_3 = "33333333";
string_encrypt_openssl_des_cfb64(c_original, 19, c_encrypt, ss_key_1, ss_key_2, ss_key_3);
printf("*****\n");
printf("%s\n", c_encrypt);
memset(c_original, 0, sizeof(c_original));
string_decrypt_openssl_des_cfb64(c_encrypt, 19, c_original, ss_key_1, ss_key_2, ss_key_3);
printf("*****\n");
for (size_t i = 0; i < 19; i++)
{
if (*(c_original + i) == '\0')
{
printf("-");
}
else
{
printf("%c", *(c_original + i));
}
}
printf("\n");
#endif
system("pause");
return 0;
}
使用静态库的时候,会可能遇到如下报错(使用动态库不会有该报错):
LNK2019 无法解析的外部符号 __imp_CertOpenStore,该符号在函数 capi_open_store 中被引用
该报错原因:
OpenSSL库使用了windows的一个密码学库: Crypt32
该报错解决办法:
在 项目属性 - 链接器 - 输入 - 附加依赖项 中加入: Crypt32.lib
错误:
LNK2019: 无法解析的外部符号 __imp_DeregisterEventSource,该符号在函数 OPENSSL_showfatal 中被引用
解决:
advapi32.lib
错误:
LNK2019: 无法解析的外部符号 __imp_GetProcessWindowStation,该符号在函数 OPENSSL_isservice 中被引用
解决:
user32.lib