C++使用Openssl进行RSA签名(sha1)--完整版

研究了一天,网上的代码写着是签名,实际上是加密,最开始把我弄得迷糊了,后来慢慢理清楚了,就把代码记下来,所有的说明都在代码注释里面,已实际应用于HTTP请求中,从读取私钥文件、sha1加密、rsa签名、base64、urlencode转换、CURL进行HTTP请求完整流程。


先将OPENSSL库编译好,并引入头文件:


#include "openssl/sha.h"
#include "openssl/rsa.h"
#include "openssl/rand.h"
#include "openssl/objects.h"
#include "openssl/pem.h"



实现代码:



char Dec2HexChar(short int n)
{
	if (0 <= n && n <= 9) {
		return char(short('0') + n);
	}
	else if (10 <= n && n <= 15) {
		return char(short('A') + n - 10);
	}
	else {
		return char(0);
	}
}

short int HexChar2Dec(char c)
{
	if ('0' <= c && c <= '9') {
		return short(c - '0');
	}
	else if ('a' <= c && c <= 'f') {
		return (short(c - 'a') + 10);
	}
	else if ('A' <= c && c <= 'F') {
		return (short(c - 'A') + 10);
	}
	else {
		return -1;
	}
}

std::string EncodeURL(const std::string &URL)
{
	std::string strResult = "";
	for (unsigned int i = 0; i < URL.size(); i++)
	{
		char c = URL[i];
		if (
			('0' <= c && c <= '9') ||
			('a' <= c && c <= 'z') ||
			('A' <= c && c <= 'Z') ||
			c == '.'
			) {
			strResult += c;
		}
		else
		{
			int j = (short int)c;
			if (j < 0)
			{
				j += 256;
			}
			int i1, i0;
			i1 = j / 16;
			i0 = j - i1 * 16;
			strResult += '%';
			strResult += Dec2HexChar(i1);
			strResult += Dec2HexChar(i0);
		}
	}

	return strResult;
}

std::string DecodeURL(const std::string &URL)
{
	std::string result = "";
	for (unsigned int i = 0; i < URL.size(); i++)
	{
		char c = URL[i];
		if (c != '%')
		{
			result += c;
		}
		else
		{
			char c1 = URL[++i];
			char c0 = URL[++i];
			int num = 0;
			num += HexChar2Dec(c1) * 16 + HexChar2Dec(c0);
			result += char(num);
		}
	}

	return result;
}

//--生成GUID  
const char* newGUID()
{
	static char buf[64] = { 0 };
	GUID guid;
	if (S_OK == ::CoCreateGuid(&guid))
	{
		_snprintf(buf, sizeof(buf)
			, "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X"
			, guid.Data1
			, guid.Data2
			, guid.Data3
			, guid.Data4[0], guid.Data4[1]
			, guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5]
			, guid.Data4[6], guid.Data4[7]
			);
	}
	return (const char*)buf;
}  

//将二进制流转换成base64编码
const char * base64char = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
char * base64_encode(const unsigned char * bindata, char * base64, int binlength)
{
	int i, j;
	unsigned char current;

	for (i = 0, j = 0; i < binlength; i += 3)
	{
		current = (bindata[i] >> 2);
		current &= (unsigned char)0x3F;
		base64[j++] = base64char[(int)current];

		current = ((unsigned char)(bindata[i] << 4)) & ((unsigned char)0x30);
		if (i + 1 >= binlength)
		{
			base64[j++] = base64char[(int)current];
			base64[j++] = '=';
			base64[j++] = '=';
			break;
		}
		current |= ((unsigned char)(bindata[i + 1] >> 4)) & ((unsigned char)0x0F);
		base64[j++] = base64char[(int)current];

		current = ((unsigned char)(bindata[i + 1] << 2)) & ((unsigned char)0x3C);
		if (i + 2 >= binlength)
		{
			base64[j++] = base64char[(int)current];
			base64[j++] = '=';
			break;
		}
		current |= ((unsigned char)(bindata[i + 2] >> 6)) & ((unsigned char)0x03);
		base64[j++] = base64char[(int)current];

		current = ((unsigned char)bindata[i + 2]) & ((unsigned char)0x3F);
		base64[j++] = base64char[(int)current];
	}
	base64[j] = '\0';
	return base64;
}

//签名
bool EncryptWithPrivateKey(const unsigned char * pData, char *pSignOut)
{
	RSA * rsa_pri_key = NULL;
	FILE * pFile = NULL;

	//获取路径
	TCHAR szWorkDir[MAX_PATH] = TEXT("");
	CWHService::GetWorkDirectory(szWorkDir, CountArray(szWorkDir));

	//构造路径
	TCHAR szrsa_private_keyFile[MAX_PATH] = TEXT("");
	_sntprintf(szrsa_private_keyFile, CountArray(szrsa_private_keyFile), 
		TEXT("%s\\IniConfig\\rsa_private_key.pem"), szWorkDir);

	if (NULL != (pFile = _wfopen(szrsa_private_keyFile, TEXT("r"))))
	{
		//读取私钥文件
		rsa_pri_key = PEM_read_RSAPrivateKey(pFile, NULL, NULL, NULL);
		fclose(pFile);
		if (rsa_pri_key == NULL)
		{
			LOGException("读取私钥文件内容失败!");
			return false;
		}

		//先将源串SHA1算法加密, 后面+1是给结束符留的位置
		unsigned char szSha1Data[SHA_DIGEST_LENGTH+1] = { 0 };
		ZeroMemory(szSha1Data, sizeof(szSha1Data)); 
		SHA_CTX c; 
		if (!SHA1_Init(&c))
		{
			LOGException("初始化sha1算法失败!");
			return false;
		}
		SHA1_Update(&c, pData, strlen((char*)pData));
		SHA1_Final(szSha1Data, &c);
		OPENSSL_cleanse(&c, sizeof(c));
		 
		//RSA签名
		unsigned char szTBSign[512] = { 0 };
		ZeroMemory(szTBSign, sizeof(szTBSign));
		unsigned int nLen = 0;
		int r = RSA_sign(NID_sha1, szSha1Data, SHA_DIGEST_LENGTH, szTBSign, &nLen, rsa_pri_key);
		RSA_free(rsa_pri_key); 

		if (1 == r)
		{
			//签名成功,转换成base64编码
			base64_encode(szTBSign, pSignOut, nLen);
			return true;
		}
		return false; 
	}
	else
	{
		LOGException("读取私钥文件失败!");
	}
	return false;
}


借用前辈CURL的HTTP请求代码:

.h头文件

	/**
	* @brief HTTP POST请求
	* @param strUrl 输入参数,请求的Url地址,如:http://www.baidu.com
	* @param strPost 输入参数,使用如下格式para1=val1¶2=val2&…
	* @param strResponse 输出参数,返回的内容
	* @return 返回是否Post成功
	*/
	int Post(const std::string & strUrl, const std::string & strPost, std::string & strResponse);

	/**
	* @brief HTTP GET请求
	* @param strUrl 输入参数,请求的Url地址,如:http://www.baidu.com
	* @param strResponse 输出参数,返回的内容
	* @return 返回是否Post成功
	*/
	int Get(const std::string & strUrl, std::string & strResponse);

	/**
	* @brief HTTPS POST请求,无证书版本
	* @param strUrl 输入参数,请求的Url地址,如:https://www.alipay.com
	* @param strPost 输入参数,使用如下格式para1=val1¶2=val2&…
	* @param strResponse 输出参数,返回的内容
	* @param pCaPath 输入参数,为CA证书的路径.如果输入为NULL,则不验证服务器端证书的有效性.
	* @return 返回是否Post成功
	*/
	int Posts(const std::string & strUrl, const std::string & strPost, std::string & strResponse, const char * pCaPath = NULL);

	/**
	* @brief HTTPS GET请求,无证书版本
	* @param strUrl 输入参数,请求的Url地址,如:https://www.alipay.com
	* @param strResponse 输出参数,返回的内容
	* @param pCaPath 输入参数,为CA证书的路径.如果输入为NULL,则不验证服务器端证书的有效性.
	* @return 返回是否Post成功
	*/
	int Gets(const std::string & strUrl, std::string & strResponse, const char * pCaPath = NULL);

.cpp文件

int CAsyncEngineHttpSink::Post(const std::string & strUrl, const std::string & strPost, std::string & strResponse)
{
	CURLcode res;
	CURL* curl = curl_easy_init();
	if (NULL == curl)
	{
		return CURLE_FAILED_INIT;
	} 
	curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
	curl_easy_setopt(curl, CURLOPT_POST, 1);
	curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost.c_str());
	curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);
	curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
	curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);
	curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);
	res = curl_easy_perform(curl);
	curl_easy_cleanup(curl);
	return res;
}

int CAsyncEngineHttpSink::Get(const std::string & strUrl, std::string & strResponse)
{
	CURLcode res;
	CURL* curl = curl_easy_init();
	if (NULL == curl)
	{
		return CURLE_FAILED_INIT;
	}
	curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
	curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);
	/**
	* 当多个线程都使用超时处理的时候,同时主线程中有sleep或是wait等操作。
	* 如果不设置这个选项,libcurl将会发信号打断这个wait从而导致程序退出。
	*/
	curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
	curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);
	curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);
	res = curl_easy_perform(curl);
	curl_easy_cleanup(curl);
	return res;
}

int CAsyncEngineHttpSink::Posts(const std::string & strUrl, const std::string & strPost, std::string & strResponse, const char * pCaPath)
{
	CURLcode res;
	CURL* curl = curl_easy_init();
	if (NULL == curl)
	{
		return CURLE_FAILED_INIT;
	} 
	curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
	curl_easy_setopt(curl, CURLOPT_POST, 1);
	curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost.c_str());
	curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);
	curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
	if (NULL == pCaPath)
	{
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
	}
	else
	{
		//缺省情况就是PEM,所以无需设置,另外支持DER 
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
		curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath);
	}
	curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);
	curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);
	res = curl_easy_perform(curl);
	curl_easy_cleanup(curl);
	return res;
}

int CAsyncEngineHttpSink::Gets(const std::string & strUrl, std::string & strResponse, const char * pCaPath)
{
	CURLcode res;
	CURL* curl = curl_easy_init();
	if (NULL == curl)
	{
		return CURLE_FAILED_INIT;
	} 
	curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
	curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);
	curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
	if (NULL == pCaPath)
	{
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
	}
	else
	{
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
		curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath);
	}
	curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);
	curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);
	res = curl_easy_perform(curl);
	curl_easy_cleanup(curl);
	return res;
}


OpenSSL是一个开源的加密库,它提供了一系列的密码学功能,包括RSA签名。在C++使用OpenSSL进行RSA签名,可以按照以下步骤进行: 1. 导入OpenSSL库:在C++代码中,需要包含OpenSSL的头文件,并链接OpenSSL的库文件。 2. 生成RSA密钥对:使用OpenSSL的函数生成RSA密钥对,包括公钥和私钥。 3. 加载私钥:将生成的私钥加载到内存中,以便后续进行签名操作。 4. 准备待签名数据:将待签名的数据准备好,可以是任意长度的字节流。 5. 进行签名使用OpenSSL提供的函数,将待签名数据和私钥作为输入,生成签名结果。 下面是一个简单的示例代码,演示了如何使用OpenSSL进行RSA签名: ```cpp #include <openssl/rsa.h> #include <openssl/pem.h> // 生成RSA密钥对 RSA* generateRSAKey() { RSA* rsa = RSA_new(); BIGNUM* bne = BN_new(); unsigned long e = RSA_F4; BN_set_word(bne, e); RSA_generate_key_ex(rsa, 2048, bne, NULL); return rsa; } // 加载私钥 EVP_PKEY* loadPrivateKey(RSA* rsa) { EVP_PKEY* pkey = EVP_PKEY_new(); EVP_PKEY_assign_RSA(pkey, rsa); return pkey; } // 进行RSA签名 std::string rsaSign(const std::string& data, EVP_PKEY* privateKey) { EVP_MD_CTX* mdctx = EVP_MD_CTX_new(); EVP_SignInit(mdctx, EVP_sha256()); EVP_SignUpdate(mdctx, data.c_str(), data.length()); size_t siglen = EVP_PKEY_size(privateKey); std::vector<unsigned char> signature(siglen); EVP_SignFinal(mdctx, signature.data(), &siglen, privateKey); EVP_MD_CTX_free(mdctx); return std::string(signature.begin(), signature.end()); } int main() { // 生成RSA密钥对 RSA* rsa = generateRSAKey(); // 加载私钥 EVP_PKEY* privateKey = loadPrivateKey(rsa); // 准备待签名数据 std::string data = "Hello, World!"; // 进行RSA签名 std::string signature = rsaSign(data, privateKey); // 打印签名结果 for (unsigned char c : signature) { printf("%02x", c); } printf("\n"); // 释放资源 RSA_free(rsa); EVP_PKEY_free(privateKey); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值