#include <iostream>
#include <fstream>
#include <openssl/des.h>
#include <openssl/applink.c>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
typedef unsigned char uchar;
typedef unsigned int uint;
/*
调用OpenSSL接口进行DES ECB模式加解密
*/
int DES_set_key(const_DES_cblock* key,DES_key_schedule* schedule)
void DES_ecb_encrypt(const_DES_cblock* input,DES_cblock* output,DES_key_schedule* ke,int enc)
void DES_cbc_encrypt(const unsigned char* input,unsigned char* output,long length,DES_key_schedule* schedule,DES_cblock* ivec,int enc)
DES_ncbc_encrypt
//例1
int main(int argc, char* argv[])
{

unsigned char data[] = "1234567";
unsigned char out[1024]{};
unsigned char out2[1024]{};
unsigned char out3[1024]{};
unsigned char out4[1024]{};
const_DES_cblock key = "1239527";//密钥
DES_key_schedule key_sch;
//1设置密钥
DES_set_key(&key, &key_sch);
//数据加密
DES_ecb_encrypt((const_DES_cblock*)data, (DES_cblock*)out, &key_sch, DES_ENCRYPT);
cout << out << endl;
//数据二次加密,一次只能加密8字节加密数据过大需要根据加密内容大小对内容进行切割运算
DES_ecb_encrypt((const_DES_cblock*)out, (DES_cblock*)out2, &key_sch, DES_ENCRYPT);
cout << out2 << endl;
//解密
DES_ecb_encrypt((const_DES_cblock*)out2, (DES_cblock*)out3, &key_sch, DES_DECRYPT);
cout << out3 << endl;
//解密
DES_ecb_encrypt((const_DES_cblock*)out3, (DES_cblock*)out4, &key_sch, DES_DECRYPT);
cout << out4 << endl;
getchar();
return 0;
}



//命令行运行,运行指令 可执行文件名 输入源文件 输入结果文件 密钥 缺省表示加密,有参数表示解密
//
//PKCS7填充约定,当数据大小是8的倍数时添加额外8个值为8的字节;
// 否则添加的[8-(数据大小%8)]个值为{8-(数据大小%8)}的字节

//例2
int main(int argc, char* argv[])
{
string cmd = "加密文件: crypt_file 输入文件名 输入文件名 密码 (6) \n";
cmd += "机密文件: crypt_file 输入文件名 输入文件名 密码 (6)-d\n";
cout << cmd << endl;
if (argc < 4) {
cerr << "para error" << endl;
return -1;
}
//输入文件
string in_file = argv[1]; //输入文件
string out_file = argv[2]; //输出文件
string password = argv[3]; //密钥
int is_encrypt = DES_ENCRYPT;//加密
if (argc > 4)
is_encrypt = DES_DECRYPT;//解密

//二进制打开输入文件
ifstream ifs(in_file, ios::binary);
if (!ifs) {
cerr << "in_file:" << in_file << "open failed!" << endl;
return -1;
}

//二进制创建输出文件
ofstream ofs(out_file, ios::binary);
if (!ofs) {
cerr << "out_file:" << out_file << "open failed!" << endl;
return -1;
}
//处理密钥 多出丢掉.少的补0 //另一个思路通过哈希单向散列,把密钥生成一个单向散列的值,固定大小,再进行加密
int key_size = password.size();//获取密钥大小
const_DES_cblock key{};
if (key_size > sizeof(key))
key_size = sizeof(key); //多出丢掉
memcpy(key, password.c_str(), key_size);//初始化时清零了所以不必再次补零
DES_key_schedule key_sch;
DES_set_key(&key, &key_sch);//色织密钥
long long read_size = 0;
long long write_size = 0;

const_DES_cblock in;//输入数据
DES_cblock out; //输出数据

//获取文件大小
long long filesize = 0;
ifs.seekg(0, ios::end);
filesize = ifs.tellg();//获取文件大小
ifs.seekg(0, ios::beg);
cout << "filesize = " << filesize << endl;

//1读文件 => 2加解密文件 => 3写入文件
while (!ifs.eof()) {
//每次写入字节大小
int out_len = sizeof(out);
//1读文件
ifs.read((char*)in, sizeof(in));
int count = ifs.gcount();//获取读到的数据
if (count <= 0)break;
read_size += count;

//PKCS7 Padding 填充
//加密到结尾处 填充
if (read_size == filesize && is_encrypt == 1)//最后一行加密文件的逻辑
{
if (filesize % 8 == 0)//填充8字节值为8
{
DES_ecb_encrypt(&in, &out, &key_sch, is_encrypt);
ofs.write((char*)out, out_len);

//填充数据 8
memset(in, 8, sizeof(in));
ofs.write((char*)out, out_len);
}
else
{
int padding = 8 - filesize % 8;//要填充的字节
//移到位置填充数据
memset(in + (filesize % 8), padding, padding);
}
//填充后的数据是密文的,要进行解密再去掉
}
//2加解密文件
DES_ecb_encrypt(&in, &out, &key_sch, is_encrypt);


//解密padding处理
if (read_size == filesize && is_encrypt == DES_DECRYPT)
{
out_len = 8 - out[7];//计算填充了多少字节
}
if (out_len <= 0)break;//文件是字节数是8的倍数,最后一行不写入

//3写入文件
ofs.write((char*)out, out_len);
write_size += out_len;
}


ifs.close();
ofs.close();
cout << "write :" << write_size << endl;
getchar();
return 0;
}










RSA

RSA实现原帖:​​https://www.52pojie.cn/forum.php?mod=viewthread&tid=1650877&extra=page%3D1%26filter%3Dtypeid%26typeid%3D28​

生成公私钥

void generateKeys(){
EVP_PKEY* pkey = EVP_RSA_gen(1024);
if(pkey == NULL){
fprintf(stderr,"error: rsa gen\n");
ERR_print_errors_fp(stderr);
return;
}
FILE* fp = fopen("public.pem","wt");
if(fp! = NULL){
PEM_write_PUBKEY(fp,pkey);
fclose(fp);
}else{
perror("file error");
}
fp = fopen("private.pem","wt");
if(fp != NULL){
PEM_write_PrivateKey(fp,pkey,NULL,NULL,0,NULL,NULL);
fclose(fp);
}else{
perror("file error");
}
EVP_PKEY_free(pkey);
}



公钥加密

uchar *encrypt_public(uchar *src, uint len, int *length)
{
FILE *fp;
fopen_s(&fp, "public.pem", "r");
if (fp == NULL)
{
perror("file error");
return NULL;
}
EVP_PKEY *pkey;
pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL);
fclose(fp);
if (pkey == NULL)
{
fprintf(stderr, "error: read publics key\n");
return NULL;
}
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
EVP_PKEY_encrypt_init(ctx);
uchar *dst = (uchar *)malloc(2048);
size_t outl = 2048;
if (!EVP_PKEY_encrypt(ctx, dst, &outl, src, (size_t)len))
{
fprintf(stderr, "error: encrypt\n");
EVP_PKEY_free(pkey);
free(dst);
return NULL;
}
int len2 = outl;
EVP_PKEY_free(pkey);
EVP_PKEY_CTX_free(ctx);
BIO_dump_fp(stdout, dst, len2);
printf("len: %d, len2: %d\n", len, len2);
if (length != NULL)
{
*length = len2;
}
return dst;
}




私钥解密

uchar *decrypt_private(uchar *src, int len)
{
FILE *fp;
fopen_s(&fp, "private.pem", "r");
if (fp == NULL)
{
perror("file error");
return NULL;
}
EVP_PKEY *pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL);
fclose(fp);
if (pkey == NULL)
{
fprintf(stderr, "error: read private key\n");
return NULL;
}
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
EVP_PKEY_decrypt_init(ctx);
uchar *dst = (uchar *)malloc(2048);
size_t outl;
size_t inl = len;
if (!EVP_PKEY_decrypt(ctx, dst, &outl, src, inl))
{
fprintf(stderr, "error: decrypt\n");
free(dst);
dst = NULL;
}
else
{
BIO_dump_fp(stdout, dst, (int)outl);
printf("len: %d, outl: %lld\n", len, outl);
}
EVP_PKEY_free(pkey);
EVP_PKEY_CTX_free(ctx);
return dst;
}


int main() {
int len = 0;
generateKeys();
uchar* encode = encrypt_public((uchar*)"hello world", strlen("hello world"), &len);
uchar* source = decrypt_private(encode, len);
delete encode;
delete source;
}



cmake 静态链接openssl

...
...
...
IF(CMAKE_CL_64)
include_directories("C:\\Program Files\\OpenSSL-Win64\\include")
link_directories("C:\\Program Files\\OpenSSL-Win64\\lib")
ELSE(CMAKE_CL_64)
include_directories("C:\\Program Files (x86)\\OpenSSL-Win32\\include")
link_directories("C:\\Program Files (x86)\\OpenSSL-Win32\\lib")
ENDIF(CMAKE_CL_64)
# STATIC编译 取消openssl依赖
set(OPENSSL_USE_STATIC_LIBS TRUE)
find_package(OpenSSL REQUIRED)
add_library(RSA SHARED library.c)
target_link_libraries(RSA OpenSSL::Crypto)

OPENSSL_Uplink(100F2010,05): no OPENSSL_Applink

在​​非动态链接库​​​当中可以通过添加头问题的方式添加文件​​applink.c​​:

#include <openssl/applink.c>

如果是在​动态链接库​当中的话, 主要检查​IO方式​的影响(读取文件和输出等地方), 比如可以将读取公钥私钥的方式换成​BIO​的形式:

BIO* in=NULL;
in = BIO_new(BIO_s_file());
BIO_read_filename(in,"private.pem");
if (in == NULL){
perror("private.pem");
return NULL;
}
EVP_PKEY *pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL);
BIO_free(in);
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
EVP_PKEY_decrypt_init(ctx);
uchar *dst = (uchar *) malloc(2048);
size_t outl;
size_t inl = len;
if (!EVP_PKEY_decrypt(ctx, dst, &outl, src, inl)) {
fprintf(stderr, "error: decrypt\n");
free(dst);
dst = NULL;
} else {
printf("len: %d, outl: %lld\n", len, outl);
}
EVP_PKEY_free(pkey);
EVP_PKEY_CTX_free(ctx);
return dst;