openssl算法 (RSA\MD5\SHA1) 使用demo

编译环境

  • win10
  • vs2019
  • openssl1.1.1

CRsa.h

#pragma once

#include <cassert>
#include <string>
#include <fstream>
#include <iostream>
#include <openssl\pem.h>
#include <openssl\rsa.h>
#include <openssl\bio.h>

#pragma comment(lib, "libcrypto.lib")	//openssl1.1.1之后 libeay32.lib->libcrypto.lib
#pragma comment(lib, "libssl.lib")		//openssl1.1.1之后 ssleay32.lib->libssl.lib
#define DEBUG_TEST
#define KEY_LENGTH  2048	// 密钥长度

using std::string;

void GenerateRSAKey(string& out_pub_key, string& out_pri_key);
string RsaPriEncrypt(const string& text, const string& pri_key);
string RsaPubDecrypt(const string& data, const string& pub_key);
string RsaPubEncrypt(const string& text, const string& pub_key);
string RsaPriDecrypt(const string& data, const string& pri_key);
string GenerateRsaSignByString(const string& message, const string& pri_key);
bool VerifyRsaSignByString(const string& sign, const string& pubkey, const string& verify_str);

CRsa.cpp

#include "CRsa.h"

const char* pub_key_file = { "./key/pubkey.pem" };	//公钥路径
const char* pri_key_file = { "./key/prikey.pem" };	//私钥路径

using namespace std;

/****************************************************************************
 *  @function : GenerateRSAKey
 *  @input    : out_pub_key 公钥 , out_pri_key 秘钥
 *  @output   :
 *  @brief    : 生成RSA钥匙
****************************************************************************/
void GenerateRSAKey(string& out_pub_key, string& out_pri_key)
{
	/* 生成密钥对 */
	RSA* keypair = RSA_new();
	BIGNUM* bne = BN_new();
	BN_set_word(bne, (unsigned int)RSA_3);	//给大数赋值RSA_3
	RSA_generate_key_ex(keypair, KEY_LENGTH, bne, NULL); //RSA_generate_key被弃用
	//RSA* keypair = RSA_generate_key(KEY_LENGTH, RSA_3, NULL, NULL);

	/* 生成私钥 */
	BIO* pri = BIO_new(BIO_s_mem());
	PEM_write_bio_RSAPrivateKey(pri, keypair, NULL, NULL, 0, NULL, NULL);
	size_t pri_len = BIO_pending(pri);

	/* 生成公钥 */
	BIO* pub = BIO_new(BIO_s_mem());
	PEM_write_bio_RSAPublicKey(pub, keypair);
	//PEM_write_bio_RSA_PUBKEY(pub, keypair);
	size_t pub_len = BIO_pending(pub);

	/* 密钥对读取到字符串 */
	char* pri_key = (char*)malloc(pri_len + 1);
	char* pub_key = (char*)malloc(pub_len + 1);

#ifdef DEBUG_TEST
	assert(pri_key != NULL);
	assert(pub_key != NULL);
#endif 

	BIO_read(pri, pri_key, pri_len);
	BIO_read(pub, pub_key, pub_len);
	pri_key[pri_len] = '\0';
	pub_key[pub_len] = '\0';
	out_pub_key = pub_key;
	out_pri_key = pri_key;

	/* 将公钥写入文件 */
	ofstream pub_file(pub_key_file);
	if (!pub_file.is_open())
	{
		perror("pub key file open fail:");
		exit(0);
	}
	pub_file << pub_key;
	pub_file.close();

	/* 将私钥写入文件 */
	ofstream pri_file(pri_key_file);
	if (!pri_file.is_open())
	{
		perror("pri key file open fail:");
		exit(0);
	}
	pri_file << pri_key;
	pri_file.close();

	// 释放内存
	RSA_free(keypair);
	BIO_free_all(pub);
	BIO_free_all(pri);

	free(pri_key);
	free(pub_key);
}


/****************************************************************************
 *  @function : string2rsa
 *  @input    :
 *  @output   :
 *  @brief    : 获取钥匙
****************************************************************************/
inline RSA* string2rsa(const string& key, decltype(PEM_read_bio_RSAPublicKey)* callback) {
	BIO* keybio = BIO_new_mem_buf((unsigned char*)key.c_str(), -1);
	RSA* rsa = RSA_new();
	rsa = callback(keybio, &rsa, NULL, NULL);
	BIO_free(keybio);
	return rsa;
}


/****************************************************************************
 *  @function : RsaPriEncrypt
 *  @input    : text 明文 , pri_key 秘钥
 *  @output   : 密文
 *  @brief    : 秘钥加密
****************************************************************************/
string RsaPriEncrypt(const string& text, const string& pri_key)
{
	/* 获取秘钥 */
	RSA* rsa = string2rsa(pri_key, PEM_read_bio_RSAPrivateKey);
	if (rsa == nullptr) {
		cout << "PEM_read_bio_RSAPrivateKey fail" << endl;
		return string();
	}

	/* 获取长度 */
	int key_len = RSA_size(rsa); //RSA加密后出来的长度
	int block_len = key_len - 11; //RSA单次处理的最大长度,因为填充方式为RSA_PKCS1_PADDING, 所以要减去11
	string data; //总加密数据
	char* sub_data = new char[key_len + 1]; //分段加密数据
	string sub_text; //分段待加密数据

	/* 分段加密 */
	for (int ret = 0, pos = 0; pos < text.length(); pos += block_len) {
		sub_text = text.substr(pos, block_len); //获取数据
		memset(sub_data, 0, key_len + 1);
		ret = RSA_private_encrypt(sub_text.length(), (const unsigned char*)sub_text.c_str(), (unsigned char*)sub_data, rsa, RSA_PKCS1_PADDING);
		if (ret >= 0) {
			data.append(string(sub_data, ret)); //添加加密数据
		}
	}

	/* 释放内存 */
	delete[] sub_data;
	RSA_free(rsa);

	return data;
}


/****************************************************************************
 *  @function : RsaPubDecrypt
 *  @input    : data 密文 , pub_key 公钥
 *  @output   : 明文
 *  @brief    : 公钥解密
****************************************************************************/
string RsaPubDecrypt(const string& data, const string& pub_key)
{
	/* 获取公钥 */
	RSA* rsa = string2rsa(pub_key, PEM_read_bio_RSAPublicKey); //PEM_read_bio_RSA_PUBKEY
	if (rsa == nullptr) {
		cout << "PEM_read_bio_RSAPublicKey fail" << endl;
		return string();
	}

	/* 获取长度 */
	int len = RSA_size(rsa); //RSA单次处理的最大长度
	char* sub_text = new char[len + 1]; //分段解密数据
	string text; //总解密数据
	string sub_data; //分段加密数据

	/* 分段解密 */
	for (int ret = 0, pos = 0; pos < data.length(); pos += len) {
		sub_data = data.substr(pos, len);
		memset(sub_text, 0, len + 1);
		ret = RSA_public_decrypt(sub_data.length(), (const unsigned char*)sub_data.c_str(), (unsigned char*)sub_text, rsa, RSA_PKCS1_PADDING);
		if (ret >= 0) {
			text.append(string(sub_text, ret));
		}
	}

	/* 释放内存 */
	delete[] sub_text;
	RSA_free(rsa);

	return text;
}


/****************************************************************************
 *  @function : RsaPubEncrypt
 *  @input    : text 待加密的明文 , pri_key 私钥
 *  @output   : 加密后的数据
 *  @brief    : 公钥加密
****************************************************************************/
string RsaPubEncrypt(const string& text, const string& pub_key)
{
	/* 获取公钥 */
	RSA* rsa = string2rsa(pub_key, PEM_read_bio_RSAPublicKey); //PEM_read_bio_RSA_PUBKEY
	if (rsa == nullptr) {
		cout << "PEM_read_bio_RSAPublicKey fail" << endl;
		return string();
	}

	/* 获取长度 */
	int key_len = RSA_size(rsa); //RSA加密后出来的长度
	int block_len = key_len - 11; //RSA单次处理的最大长度,因为填充方式为RSA_PKCS1_PADDING, 所以要减去11
	char* sub_data = new char[key_len + 1]; 
	string sub_text;
	string data;
	
	/* 分段加密 */
	for (int ret = 0, pos = 0; pos < text.length(); pos += block_len) {
		sub_text = text.substr(pos, block_len); //获取数据
		memset(sub_data, 0, key_len + 1);
		ret = RSA_public_encrypt(sub_text.length(), (const unsigned char*)sub_text.c_str(), (unsigned char*)sub_data, rsa, RSA_PKCS1_PADDING);
		if (ret >= 0) {
			data.append(string(sub_data, ret)); //添加加密数据
		}
	}

	// 释放内存  
	RSA_free(rsa);
	delete[] sub_data;

	return data;
}


/****************************************************************************
 *  @function : RsaPriDecrypt
 *  @input    : data 密文 , pri_key 私钥
 *  @output   : 明文
 *  @brief    : 私钥解密
****************************************************************************/
string RsaPriDecrypt(const string& data, const string& pri_key)
{
	/* 获取秘钥 */
	RSA* rsa = string2rsa(pri_key, PEM_read_bio_RSAPrivateKey);
	if (rsa == nullptr) {
		cout << "PEM_read_bio_RSAPrivateKey fail" << endl;
		return string();
	}

	/* 获取长度 */
	int len = RSA_size(rsa); //获取RSA单次处理的最大长度
	char* sub_text = new char[len + 1]; //分段解密数据
	string sub_data; //分段加密数据
	string text; //总解密数据
	
	/* 分段解密 */
	for (int ret = 0, pos = 0; pos < data.length(); pos += len) {
		sub_data = data.substr(pos, len);
		memset(sub_text, 0, len + 1);
		ret = RSA_private_decrypt(sub_data.length(), (const unsigned char*)sub_data.c_str(), (unsigned char*)sub_text, rsa, RSA_PKCS1_PADDING);
		if (ret >= 0) {
			text.append(string(sub_text, ret));
		}
	}

	/* 释放内存 */
	delete[] sub_text;
	RSA_free(rsa);

	return text;
}


/****************************************************************************
 *  @function : GenerateRsaSignByString
 *  @input    : 
 *  @output   :
 *  @brief    : 通过私钥字符串生成签名
****************************************************************************/
string GenerateRsaSignByString(const string& message, const string& pri_key) {
	OpenSSL_add_all_algorithms();
	/* 获取秘钥 */
	RSA* rsa = string2rsa(pri_key, PEM_read_bio_RSAPrivateKey);
	if (rsa == nullptr) {
		cout << "PEM_read_bio_RSAPrivateKey fail" << endl;
		return string();
	}

	unsigned int size = RSA_size(rsa);
	string sign;
	sign.resize(size);
	
	int ret = RSA_sign(NID_md5, (const unsigned char*)message.c_str(), message.length(), (unsigned char*)sign.data(), &size, rsa);
	RSA_free(rsa);
	if (ret != 1) {
		cout << "RSA_sign failed" << endl;
		return string();
	}
	return sign;
}


/****************************************************************************
 *  @function : VerifyRsaSignByString
 *  @input    :
 *  @output   :
 *  @brief    : 通过公钥字符串验证签名
****************************************************************************/
bool VerifyRsaSignByString(const string &sign, const string& pub_key, const string& verify_str) {
	/* 获取公钥 */
	RSA* rsa = string2rsa(pub_key, PEM_read_bio_RSAPublicKey); //PEM_read_bio_RSA_PUBKEY
	if (rsa == nullptr) {
		cout << "PEM_read_bio_RSAPublicKey fail" << endl;
		return false;
	}

	int ret = RSA_verify(NID_md5, (const unsigned char*)verify_str.c_str(), verify_str.size(), (const unsigned char*)sign.c_str(), sign.size(), rsa);
	RSA_free(rsa);
	if (ret != 1) {
		cout << "RSA_verify failed" << endl;
		return false;
	}
	return true;
}

main.cpp

#include <iostream>
#include <openssl\md5.h>
#include <openssl\sha.h>
#include "CRsa.h"

using namespace std;

int main() {
	/* RSA */
	string prikey, pubkey;
	GenerateRSAKey(pubkey, prikey);

	string cipher1 = RsaPubEncrypt("hello\n", pubkey);
	cout << RsaPriDecrypt(cipher1, prikey);

	string cipher2 = RsaPriEncrypt("world\n", prikey);
	cout << RsaPubDecrypt(cipher2, pubkey);

	string sign = GenerateRsaSignByString("jifanlichou", prikey);
	string verify("jifanlichou");
	if (VerifyRsaSignByString(sign, pubkey, verify))
		cout << "verify success" << endl;

	/* MD5 & SHA1 */
	unsigned char md5bigest[16], shabigest[20];
	char message[] = { "jifanlichou is very cool" };

	MD5((const unsigned char*)message, strlen(message), md5bigest);
	cout << endl << "md5 : ";
	for (unsigned short ch : md5bigest) {
		cout <<hex << ch;
	}
	cout << endl;

	SHA1((const unsigned char*)message, strlen(message), shabigest);
	cout << "sha1 : ";
	for (unsigned short ch : shabigest) {
		cout << hex << ch;
	}
	cout << endl;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值