求助各位大神基于 WinCrypt 库的RSA2(Sha256WithRSA)的C++代码,包括读私钥签名和读证书验签.

代码描述了在使用WinCrypt库进行RSA2(SHA256WithRSA)签名时遇到的问题,尽管代码已调试正常运行,但生成的签名与基于OpenSSL库的已验证正确签名不匹配。文章提供了两个签名实现的详细代码,一个是WinCrypt库的实现,另一个是OpenSSL库的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

现有签名代码综合网上示例和ChatGPT,反复修改调试后可正常输出结果,但与已验证正确的基于 OpenSSL 库的代码签名结果不符。

现有基于 WinCrypt 库的签名代码如下(头文件略):

///<summary>基于 WinCrypt 库的 RSA2 (Sha256WithRSA) 签名,反复修改调试后仍与经验证正确的基于 OpenSSL 库的代码签名结果不符</summary>
///<param name="sSignContent">待签名报文</param>
///<returns>Base64 编码的签名</returns>
string RSA2Sign_WinCrypt(string sSignContent)
{
	// openssl rsa -in api_private_key.pem -out api_private_key.key
	string sRsaKey = ::GetResStrA(IDR_PRI_KEY, L"RSA"); // 从资源加载私钥,开头为:-----BEGIN RSA PRIVATE KEY-----

	HCRYPTPROV	hProv	= NULL;
	HCRYPTKEY	hRSAKey	= NULL;
	HCRYPTHASH	hHash	= NULL;

	string sResult;

	for (int omit_go_to = 0; omit_go_to == 0; omit_go_to++) // 只执行一次,出错时跳出
	{
		DWORD cbKeyEncoded = sRsaKey.size();
		vector<BYTE> sKeyEncoded(cbKeyEncoded, 0);

		if (!::CryptStringToBinaryA(sRsaKey.c_str(), NULL, CRYPT_STRING_ANY, sKeyEncoded.data(), &cbKeyEncoded, NULL, NULL))
		{
			ATLTRACE(::GetLastErrMsg().c_str());
			break;
		}

		DWORD cbKeyDecoded = cbKeyEncoded + 32; // 解码后长度有可能略大于解码前
		vector<BYTE> sKeyDecoded(cbKeyDecoded, 0);

		if (!::CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY,
			sKeyEncoded.data(), cbKeyEncoded, 0, NULL, sKeyDecoded.data(), &cbKeyDecoded))
		{
			ATLTRACE(::GetLastErrMsg().c_str());
			break;
		}

		if (!::CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
		{
			ATLTRACE(::GetLastErrMsg().c_str());
			break;
		}

		if (!::CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash))
		{
			ATLTRACE(::GetLastErrMsg().c_str());
			break;
		}

		if (!::CryptHashData(hHash, (BYTE*)sSignContent.c_str(), sSignContent.length(), 0)) // dwFlags=CRYPT_USERDATA 时签名无变化
		{
			ATLTRACE(::GetLastErrMsg().c_str());
			break;
		}

		if (!::CryptImportKey(hProv, sKeyDecoded.data(), cbKeyDecoded, NULL, 0, &hRSAKey))
		{
			ATLTRACE(::GetLastErrMsg().c_str());
			break;
		}
		
		BYTE sSignature[256] = { 0 };
		DWORD cbSignature = sizeof(sSignature);

		if (!::CryptSignHash(hHash, AT_KEYEXCHANGE, NULL, 0, sSignature, &cbSignature)) // dwFlags=CRYPT_NOHASHOID 时签名变化,也与 OpenSSL 不符
		{
			ATLTRACE(::GetLastErrMsg().c_str());
			break;
		}

		sResult = ::Base64Encode(sSignature, cbSignature); // Base64 编码(自定义函数)
	}

	if (hHash	!= NULL) ::CryptDestroyHash(hHash);
	if (hRSAKey != NULL) ::CryptDestroyKey(hRSAKey);
	if (hProv	!= NULL) ::CryptReleaseContext(hProv, 0);

	return sResult;
}

已验证正确的基于 OpenSSL 库的签名代码如下(头文件略):

///<summary>基于 OpenSSL 库的 RSA2 (Sha256WithRSA) 签名</summary>
///<param name="sSignContent">待签名内容</param>
///<returns>Base64 编码的签名</returns>
string RSA2Sign_OpenSSL(string sSignContent)
{
	string sRsaKey = ::GetResStrA(IDR_PRI_PEM, L"RSA"); // 从资源读取私钥,其开头为:-----BEGIN PRIVATE KEY-----

	EVP_MD_CTX* pEvpMdCtx = ::EVP_MD_CTX_new();
	::EVP_DigestInit(pEvpMdCtx, ::EVP_sha256());
	::EVP_DigestUpdate(pEvpMdCtx, sSignContent.c_str(), (int)sSignContent.length());

	BIO* bio = ::BIO_new(::BIO_s_mem());
	::BIO_puts(bio, sRsaKey.c_str());
	RSA* pRsa = ::PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL); // RSA 私钥
	EVP_PKEY* pEvpKey = ::EVP_PKEY_new();
	::EVP_PKEY_assign_RSA(pEvpKey, pRsa);
	::BIO_free(bio);

	unsigned int cbSignature = (unsigned int)::EVP_PKEY_size(pEvpKey);
	vector<BYTE> sSignature(cbSignature, 0); // 签名结果
	int nResult = ::EVP_SignFinal(pEvpMdCtx, (LPBYTE)sSignature.data(), &cbSignature, pEvpKey);

	::EVP_MD_CTX_free(pEvpMdCtx);
	::EVP_PKEY_free(pEvpKey); // 释放私钥

	ASSERT(nResult == 1 && cbSignature > 0);

	string sResult = ::Base64Encode(sSignature.data(), cbSignature); // Base64 编码
	return sResult;
}

求助各位大神帮助,验签代码未贴出,但相信如果签名解决了,验签应问题不大。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值