openssl rsa公钥验签名

场景:

只有公钥字符串(base64编码),需验证签名。

环境:

c++ + openssl

step1 从内存读取公钥

static RSA* GetPublicKeyRSA(string strPublicKey)
	{
		int nPublicKeyLen = strPublicKey.size();      //strPublicKey为base64编码的公钥字符串
		for(int i = 64; i < nPublicKeyLen; i+=64)
		{
			if(strPublicKey[i] != '\n')
			{
				strPublicKey.insert(i, "\n");
			}
			i++;
		}
		strPublicKey.insert(0, "-----BEGIN PUBLIC KEY-----\n");
		strPublicKey.append("\n-----END PUBLIC KEY-----\n");

		BIO *bio = NULL; 
		RSA *rsa = NULL; 
		char *chPublicKey = const_cast(strPublicKey.c_str());
		if ((bio = BIO_new_mem_buf(chPublicKey, -1)) == NULL)       //从字符串读取RSA公钥
		{     
			cout<<"BIO_new_mem_buf failed!"<

step2 开始验证啦

static bool verify( string sign, string content )
{
	// 公钥字符串,经过base64编码
 	string publicKey = "xxxxxxxxxxxxx";
 	// 得到公钥的RSA结构体
	RSA* rsa = GetPublicKeyRSA(publicKey);
	if (NULL == rsa)
 	{
 		return false;
 	}
	// 将原串经过sha256摘要(摘要算法根据实际使用来,此处以sha256为例)
	string hash = Sha256(content.c_str(),false); 
	// 将待验证签名用base64解码(一般给的签名是经过base64编码的)
	string sign = Base64Decode((char *)gameAuthSign.c_str(), strlen(gameAuthSign.c_str()));
	// 此处签名长度根据实际使用来,最好不要直接strlen(sign),可能发生截断
	int sign_len = 256; 
	int res = RSA_verify(NID_sha256, (const unsigned char*)hash.c_str(), strlen(hash.c_str()), (unsigned char*)sign.c_str(),sign_len, rsa);  
	if (res == 1)
	{
		gDebugStream("huawei verify ok");
	}
	else
	{// 此api打印了验证失败的原因(bad signature,sigature length error等)
		unsigned long ulErr = ERR_get_error(); // 获取错误号
		char szErrMsg[1024] = {0};
		char *pTmp = NULL;
		pTmp = ERR_error_string(ulErr,szErrMsg); // 格式:error:errId:库:函数:原因
		cout << szErrMsg;
		gDebugStream("verify error:" << szErrMsg);
	}
	return res == 1;  
}
ps base64解码,编码 sha256摘要 都能过openssl实现 

base64解码

static string Base64Decode(char * input, int length)  
	{  
		string result;
		static char decode[1024] = {0};
		if (NULL == input || length <= 0 || length >= 1024)
		{
			return result;
		}		
		int len = EVP_DecodeBlock((unsigned char*)decode, (const unsigned char*)input, length);  
		if (len >= 1024 || len <= 0)
		{
			return result;
		}
		decode[len] = '\0';
		
		result.resize(len);
		for(int i = 0; i < len; i++) 
		{
			result[i] = decode[i];
		}
		return result;
	}

base64编码

	static string Base64Encode(char * input, int length)
	{
		static char encoded[1024] = {0};
		string result;
		if (NULL == input || length <= 0 || length >= 1024)
		{
			return result;
		}
		
		int len = EVP_EncodeBlock((unsigned char*)encoded, (const unsigned char*)input, length);  	
		if (len >= 1024 || len <= 0)
		{
			return result;
		}
		encoded[len] = '\0';
		result = string(encoded);
		return result;
	}
sha256

static string Sha256(const char* data, bool bHex = true)
	{
		unsigned char md[SHA256_DIGEST_LENGTH] = {0};

		SHA256((const unsigned char *)data, strlen(data), md);  
		if (!bHex)
		{
			string s;
			s.resize(SHA256_DIGEST_LENGTH);
			for(int i = 0; i < SHA256_DIGEST_LENGTH; i++) 
			{
				s[i] = md[i];
			}
			return s;
		}
		else
		{
			string s;
			s.resize(SHA256_DIGEST_LENGTH * 2);
			int k = 0;
			for(unsigned int i = 0; i < SHA256_DIGEST_LENGTH ; i++) 
			{  
				sprintf(&s.at(k), "%02x", md[i]);
				k += 2;
			}  
			return s;
		}
	}

另外,尝试过php来验证

但是读取公钥时总用报错 $openssl_public_key = @openssl_get_publickey($pubKey);

error:0906D06C:PEM routines:PEM_read_bio:no start line

似乎是openssl_get_publickey这个api不支持只用公钥的字符串,应该读取的是证书,但是只有公钥字符串,我也不知道如何生成证书。。

最后~希望你顺利验证通过~~~~

你可能感兴趣的:(c++)