现有签名代码综合网上示例和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;
}
求助各位大神帮助,验签代码未贴出,但相信如果签名解决了,验签应问题不大。