C++使用openssl對數據進行加解密

1. openssl庫文件及頭文件的獲取

獲取openssl庫文件及頭文件有兩種方式:

1)下載OpenSSL源代碼並由自己編譯後使用

2)下載已編譯好的安裝包,安裝後直接可以得到openssl的庫文件及頭文件

使用第一種方法獲取,過程十分繁瑣,同時編譯過程中可能產生各種各種的問題,因此這裏使用第二種方法獲取openssl庫文件及頭文件。

下載安裝包(https://slproweb.com/products/Win32OpenSSL.html),並進行安裝,安裝後安裝目錄如下圖,其中bin文件夾內的爲動態庫文件、lib文件夾內的爲靜態庫文件、include文件夾內的爲頭文件

2. 使用openssl對數據進行加解密

1) 新建工程,引入openssl頭文件及庫文件

2) 示例代碼如下,示例代碼包含了:

a. 摘要(散列)算法md5、sha256;

b. 對稱加密算法des;

c. 非對稱加密算法rsa。

#include <iostream>
#include <cassert>
#include <string>
#include <vector>
#include "openssl/md5.h"
#include "openssl/sha.h"
#include "openssl/des.h"
#include "openssl/rsa.h"
#include "openssl/pem.h"

#pragma comment(lib,"libcrypto.lib")

// ---- md5摘要哈希 ---- //
void md5(const std::string &srcStr, std::string &encodedStr, std::string &encodedHexStr)
{
	unsigned char mdStr[33] = { 0 };
	MD5((const unsigned char *)srcStr.c_str(), srcStr.length(), mdStr);// 調用md5哈希
	encodedStr = std::string((const char *)mdStr);// 哈希後的字符串
	
	char buf[65] = { 0 };
	char tmp[3] = { 0 };
	for (int i = 0; i < 32; i++)// 哈希後的十六進制串 32字節  
	{
		sprintf(tmp, "%02x", mdStr[i]);
		strcat(buf, tmp);
	}
	buf[32] = '\0'; // 後面都是0,從32字節截斷  
	encodedHexStr = std::string(buf);
}

// ---- sha256摘要哈希 ---- //  
void sha256(const std::string &srcStr, std::string &encodedStr, std::string &encodedHexStr)
{
	
	unsigned char mdStr[33] = { 0 };
	SHA256((const unsigned char *)srcStr.c_str(), srcStr.length(), mdStr);// 調用sha256哈希
	encodedStr = std::string((const char *)mdStr);// 哈希後的字符串
	
	char buf[65] = { 0 };
	char tmp[3] = { 0 };
	for (int i = 0; i < 32; i++)// 哈希後的十六進制串 32字節  
	{
		sprintf(tmp, "%02x", mdStr[i]);
		strcat(buf, tmp);
	}
	buf[32] = '\0'; // 後面都是0,從32字節截斷  
	encodedHexStr = std::string(buf);
}

// ---- des對稱加解密 ---- //  
// 加密 ecb模式  
std::string des_encrypt(const std::string &clearText, const std::string &key)
{
	std::string cipherText; // 密文

	DES_cblock keyEncrypt;
	memset(keyEncrypt, 0, 8);

	// 構造補齊後的密鑰  
	if (key.length() <= 8)
		memcpy(keyEncrypt, key.c_str(), key.length());
	else
		memcpy(keyEncrypt, key.c_str(), 8);

	// 密鑰置換  
	DES_key_schedule keySchedule;
	DES_set_key_unchecked(&keyEncrypt, &keySchedule);

	// 循環加密,每8字節一次  
	const_DES_cblock inputText;
	DES_cblock outputText;
	std::vector<unsigned char> vecCiphertext;
	unsigned char tmp[8];

	for (int i = 0; i < clearText.length() / 8; i++)
	{
		memcpy(inputText, clearText.c_str() + i * 8, 8);
		DES_ecb_encrypt(&inputText, &outputText, &keySchedule, DES_ENCRYPT);
		memcpy(tmp, outputText, 8);

		for (int j = 0; j < 8; j++)
			vecCiphertext.push_back(tmp[j]);
	}

	if (clearText.length() % 8 != 0)
	{
		int tmp1 = clearText.length() / 8 * 8;
		int tmp2 = clearText.length() - tmp1;
		memset(inputText, 0, 8);
		memcpy(inputText, clearText.c_str() + tmp1, tmp2);
		DES_ecb_encrypt(&inputText, &outputText, &keySchedule, DES_ENCRYPT);// 加密函數
		memcpy(tmp, outputText, 8);

		for (int j = 0; j < 8; j++)
			vecCiphertext.push_back(tmp[j]);
	}

	cipherText.clear();
	cipherText.assign(vecCiphertext.begin(), vecCiphertext.end());
	return cipherText;
}

// 解密 ecb模式  
std::string des_decrypt(const std::string &cipherText, const std::string &key)
{
	std::string clearText; // 明文  

	DES_cblock keyEncrypt;
	memset(keyEncrypt, 0, 8);

	if (key.length() <= 8)
		memcpy(keyEncrypt, key.c_str(), key.length());
	else
		memcpy(keyEncrypt, key.c_str(), 8);

	DES_key_schedule keySchedule;
	DES_set_key_unchecked(&keyEncrypt, &keySchedule);

	const_DES_cblock inputText;
	DES_cblock outputText;
	std::vector<unsigned char> vecCleartext;
	unsigned char tmp[8];

	for (int i = 0; i < cipherText.length() / 8; i++)
	{
		memcpy(inputText, cipherText.c_str() + i * 8, 8);
		DES_ecb_encrypt(&inputText, &outputText, &keySchedule, DES_DECRYPT);
		memcpy(tmp, outputText, 8);

		for (int j = 0; j < 8; j++)
			vecCleartext.push_back(tmp[j]);
	}

	if (cipherText.length() % 8 != 0)
	{
		int tmp1 = cipherText.length() / 8 * 8;
		int tmp2 = cipherText.length() - tmp1;
		memset(inputText, 0, 8);
		memcpy(inputText, cipherText.c_str() + tmp1, tmp2);
		DES_ecb_encrypt(&inputText, &outputText, &keySchedule, DES_DECRYPT);// 解密函數
		memcpy(tmp, outputText, 8);

		for (int j = 0; j < 8; j++)
			vecCleartext.push_back(tmp[j]);
	}

	clearText.clear();
	clearText.assign(vecCleartext.begin(), vecCleartext.end());

	return clearText;
}


// ---- rsa非對稱加解密 ---- //  
#define KEY_LENGTH  2048               // 密鑰長度
#define PUB_KEY_FILE "pubkey.pem"    // 公鑰路徑
#define PRI_KEY_FILE "prikey.pem"    // 私鑰路徑

// 函數方法生成密鑰對 
void generateRSAKey(std::string strKey[2])
{
	// 公私密鑰對  
	size_t pri_len;
	size_t pub_len;
	char *pri_key = NULL;
	char *pub_key = NULL;

	// 生成密鑰對  
	RSA *keypair = RSA_generate_key(KEY_LENGTH, RSA_3, NULL, NULL);

	BIO *pri = BIO_new(BIO_s_mem());
	BIO *pub = BIO_new(BIO_s_mem());

	PEM_write_bio_RSAPrivateKey(pri, keypair, NULL, NULL, 0, NULL, NULL);
	PEM_write_bio_RSAPublicKey(pub, keypair);

	// 獲取長度  
	pri_len = BIO_pending(pri);
	pub_len = BIO_pending(pub);

	// 密鑰對讀取到字符串  
	pri_key = (char *)malloc(pri_len + 1);
	pub_key = (char *)malloc(pub_len + 1);

	BIO_read(pri, pri_key, pri_len);
	BIO_read(pub, pub_key, pub_len);

	pri_key[pri_len] = '\0';
	pub_key[pub_len] = '\0';

	// 存儲密鑰對  
	strKey[0] = pub_key;
	strKey[1] = pri_key;

	// 存儲到磁盤(這種方式存儲的是begin rsa public key/ begin rsa private key開頭的)
	FILE *pubFile = fopen(PUB_KEY_FILE, "w");
	if (pubFile == NULL)
	{
		assert(false);
		return;
	}
	fputs(pub_key, pubFile);
	fclose(pubFile);

	FILE *priFile = fopen(PRI_KEY_FILE, "w");
	if (priFile == NULL)
	{
		assert(false);
		return;
	}
	fputs(pri_key, priFile);
	fclose(priFile);

	// 內存釋放
	RSA_free(keypair);
	BIO_free_all(pub);
	BIO_free_all(pri);

	free(pri_key);
	free(pub_key);
}

// 命令行方法生成公私鑰對(begin public key/ begin private key)
// 找到openssl命令行工具,運行以下
// openssl genrsa -out prikey.pem 1024 
// openssl rsa - in privkey.pem - pubout - out pubkey.pem

// 公鑰加密  
std::string rsa_pub_encrypt(const std::string &clearText, const std::string &pubKey)
{
	std::string strRet;
	RSA *rsa = NULL;
	BIO *keybio = BIO_new_mem_buf((unsigned char *)pubKey.c_str(), -1);
	// 此處有三種方法
	// 1, 讀取內存裏生成的密鑰對,再從內存生成rsa
	// 2, 讀取磁盤裏生成的密鑰對文本文件,在從內存生成rsa
	// 3,直接從讀取文件指針生成rsa
	RSA* pRSAPublicKey = RSA_new();
	rsa = PEM_read_bio_RSAPublicKey(keybio, &rsa, NULL, NULL);

	int len = RSA_size(rsa);
	char *encryptedText = (char *)malloc(len + 1);
	memset(encryptedText, 0, len + 1);

	// 加密函數
	int ret = RSA_public_encrypt(clearText.length(), (const unsigned char*)clearText.c_str(), (unsigned char*)encryptedText, rsa, RSA_PKCS1_PADDING);
	if (ret >= 0)
		strRet = std::string(encryptedText, ret);

	// 釋放內存
	free(encryptedText);
	BIO_free_all(keybio);
	RSA_free(rsa);

	return strRet;
}

// 私鑰解密  
std::string rsa_pri_decrypt(const std::string &cipherText, const std::string &priKey)
{
	std::string strRet;
	RSA *rsa = RSA_new();
	BIO *keybio;
	keybio = BIO_new_mem_buf((unsigned char *)priKey.c_str(), -1);

	// 此處有三種方法
	// 1, 讀取內存裏生成的密鑰對,再從內存生成rsa
	// 2, 讀取磁盤裏生成的密鑰對文本文件,在從內存生成rsa
	// 3,直接從讀取文件指針生成rsa
	rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL);

	int len = RSA_size(rsa);
	char *decryptedText = (char *)malloc(len + 1);
	memset(decryptedText, 0, len + 1);

	// 解密函數
	int ret = RSA_private_decrypt(cipherText.length(), (const unsigned char*)cipherText.c_str(), (unsigned char*)decryptedText, rsa, RSA_PKCS1_PADDING);
	if (ret >= 0)
		strRet = std::string(decryptedText, ret);

	// 釋放內存
	free(decryptedText);
	BIO_free_all(keybio);
	RSA_free(rsa);

	return strRet;
}

int main(int argc, char **argv)
{
	// 原始明文  
	std::string srcText = "this is an example";

	std::string encryptText;
	std::string encryptHexText;
	std::string decryptText;

	std::cout << "=== 原始明文 ===" << std::endl;
	std::cout << srcText << std::endl;

	// md5  
	std::cout << "=== md5哈希 ===" << std::endl;
	md5(srcText, encryptText, encryptHexText);
	std::cout << "摘要字符: " << encryptText << std::endl;
	std::cout << "摘要串: " << encryptHexText << std::endl;

	// sha256  
	std::cout << "=== sha256哈希 ===" << std::endl;
	sha256(srcText, encryptText, encryptHexText);
	std::cout << "摘要字符: " << encryptText << std::endl;
	std::cout << "摘要串: " << encryptHexText << std::endl;

	// des  
	std::cout << "=== des加解密 ===" << std::endl;
	std::string desKey = "12345";
	encryptText = des_encrypt(srcText, desKey);
	std::cout << "加密字符: " << std::endl;
	std::cout << encryptText << std::endl;
	decryptText = des_decrypt(encryptText, desKey);
	std::cout << "解密字符: " << std::endl;
	std::cout << decryptText << std::endl;

	// rsa  
	std::cout << "=== rsa加解密 ===" << std::endl;
	std::string key[2];
	generateRSAKey(key);
	std::cout << "公鑰: " << std::endl;
	std::cout << key[0] << std::endl;
	std::cout << "私鑰: " << std::endl;
	std::cout << key[1] << std::endl;
	encryptText = rsa_pub_encrypt(srcText, key[0]);
	std::cout << "加密字符: " << std::endl;
	std::cout << encryptText << std::endl;
	decryptText = rsa_pri_decrypt(encryptText, key[1]);
	std::cout << "解密字符: " << std::endl;
	std::cout << decryptText << std::endl;

	system("pause");
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章