700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > C++使用openssl建立证书 进行签名 验签 加密 解密(基于RSA)

C++使用openssl建立证书 进行签名 验签 加密 解密(基于RSA)

时间:2018-10-21 14:45:37

相关推荐

C++使用openssl建立证书 进行签名 验签 加密 解密(基于RSA)

话不多说,步骤详细,总结坑点

巨坑 RSA_verify()验证签名总是无法成功

官网的介绍

int RSA_verify(int type, const unsigned char *m, unsigned int m_len,unsigned char *sigbuf, unsigned int siglen, RSA *rsa);/*RSA_verify() verifies that the signature sigbuf of size siglen matches a given message digest m of size m_len. type denotes the message digest algorithm that was used to generate the signature. rsa is the signer's public key.*/

意思就是type需要为NID_sha1,NID_md5,等等哈希类型,然后m是信息摘要(坑点),m_len是该摘要的长度,sigbuf是签名的内容,siglen是签名长度(坑点),rsa是读取的RSA私钥信息。

听起来很简单的样子,实际上对信息做签名很容易,但是私钥验证总是会报错,各种各样都有。下面总结坑点:

1:以前以为签名和验证签名就只要把message塞进签名函数,然后和签名后的信息放进验证函数里就行了,后来发现不是这样的,RSA的签名是对信息摘要(hash)来做的签名,以为着我们需要先把原先的信息做哈希,才能签名。同理,验签的时候也需要该哈希,和签名后的数据。(PS:其实真正的通信在签名过后还需要进行base64编码处理,对应接收时也需要base64解码,因为签名后的数据是二进制的,无法正常阅读)

2:明明做了哈希,却一直验签不成功?

官网告诉了我们一个很好用的函数接口,会给出具体的错误提示:

unsigned long ulErr = ERR_get_error();

这个函数会给出错误代码,配合其余的代码会告诉我们哪里出错,比如他告诉了我,我的签名数据的长度错误,siglen error,因为这里的签名是二进制,不能通过使用strlen()等方式获取,所以我在签名后打印了签名的长度(自动绑定在outlen中),才发现长度是128.(不管我做的sha1还是sha256或者md5)

RSA_sign(NID_sha1, (const unsigned char*)strData.c_str(), strData.length() , (unsigned char*)pEncode, &outlen, pRSAPriKey);//签名数据存储在pEncode,对应长度存储在outlen

3:为什么???我做了哈希,然后按照官网的参数说明,总是报错:错误的私钥(公钥)

rsa routines:RSA_padding_check_PKCS1_type_1:invalid padding

可以明确的是,我的公私钥没有问题,因此开始定位,也没啥好说的,问题肯定在哈希函数里,所以我试了网上的很多办法,SHA256,SHA1,MD5等等,都无法成功验证,最后回归官网rsa_verify

使用了官方给出的SHA1头文件中的函数进行哈希,才成功的

生成1024位rsa私钥,保存为pem格式:

openssl genpkey -out prikey.pem -algorithm rsa

生成对应的公钥:

openssl pkey -in prikey.pem -pubout -out pubkey.pem

#include <iostream>#include "Socket.hpp"#include <functional>#include <bits/stdc++.h>#include <openssl/sha.h>#include <openssl/rsa.h>#include <openssl/err.h>#include <openssl/pem.h>#include <iostream>#include <string>#include <cstring>#include <cassert>using namespace std;//加密std::string EncodeRSAKeyFile( const std::string& strPemFileName, const std::string& strData ){if (strPemFileName.empty() || strData.empty()){assert(false);return "";}FILE* hPubKeyFile = fopen(strPemFileName.c_str(), "rb");if( hPubKeyFile == NULL ){assert(false);return ""; }std::string strRet;RSA* pRSAPublicKey = RSA_new();if(PEM_read_RSA_PUBKEY(hPubKeyFile, &pRSAPublicKey, 0, 0) == NULL){assert(false);return "";}int nLen = RSA_size(pRSAPublicKey);char* pEncode = new char[nLen + 1];int ret = RSA_public_encrypt(strData.length(), (const unsigned char*)strData.c_str(), (unsigned char*)pEncode, pRSAPublicKey, RSA_PKCS1_PADDING);if (ret >= 0){strRet = std::string(pEncode, ret);}delete[] pEncode;RSA_free(pRSAPublicKey);fclose(hPubKeyFile);CRYPTO_cleanup_all_ex_data(); return strRet;}//签名 use private keystd::string SignRSAKeyFile( const std::string& strPemFileName, std::string& strData ){if (strPemFileName.empty() || strData.empty()){assert(false);return "";}FILE* hPriKeyFile = fopen(strPemFileName.c_str(), "rb");if( hPriKeyFile == NULL ){assert(false);return "";}std::string strRet;RSA* pRSAPriKey = RSA_new();if(PEM_read_RSAPrivateKey(hPriKeyFile, &pRSAPriKey, 0, 0) == NULL){assert(false);return "";}int nLen = RSA_size(pRSAPriKey);char* pEncode = new char[nLen + 1];unsigned int outlen;int ret = RSA_sign(NID_sha1, (const unsigned char*)strData.c_str(), strData.length() , (unsigned char*)pEncode, &outlen, pRSAPriKey);if (ret >= 0){strRet = std::string(pEncode);std::cout << "\n" << strRet << endl;//std::cout << "next \n" << pEncode << endl;std::cout << "critical length:\n" << outlen << endl;}if( ret != 1)std::cout << "sign failed\n";delete[] pEncode;RSA_free(pRSAPriKey);fclose(hPriKeyFile);CRYPTO_cleanup_all_ex_data();return strRet;}//解密std::string DecodeRSAKeyFile( const std::string& strPemFileName, const std::string& strData ){if (strPemFileName.empty() || strData.empty()){assert(false);return "";}FILE* hPriKeyFile = fopen(strPemFileName.c_str(),"rb");if( hPriKeyFile == NULL ){assert(false);return "";}std::string strRet;RSA* pRSAPriKey = RSA_new();if(PEM_read_RSAPrivateKey(hPriKeyFile, &pRSAPriKey, 0, 0) == NULL){assert(false);return "";}int nLen = RSA_size(pRSAPriKey);char* pDecode = new char[nLen+1];int ret = RSA_private_decrypt(strData.length(), (const unsigned char*)strData.c_str(), (unsigned char*)pDecode, pRSAPriKey, RSA_PKCS1_PADDING);if(ret >= 0){strRet = std::string((char*)pDecode, ret);}delete [] pDecode;RSA_free(pRSAPriKey);fclose(hPriKeyFile);CRYPTO_cleanup_all_ex_data(); return strRet;}//验证签名 use pubkeyint VerifyRSAKeyFile( const std::string& strPemFileName, const std::string& strData , const std::string& sign_data){if (strPemFileName.empty() || strData.empty()){assert(false);return 0;}FILE* hPubKeyFile = fopen(strPemFileName.c_str(), "rb");if( hPubKeyFile == NULL ){assert(false);return 0;}std::string strRet;RSA* pRSAPublicKey = RSA_new();if(PEM_read_RSA_PUBKEY(hPubKeyFile, &pRSAPublicKey, 0, 0) == NULL){assert(false);return 0;}int nLen = RSA_size(pRSAPublicKey);char* pEncode = new char[nLen + 1];unsigned int outlen;int ret = RSA_verify(NID_sha1, (const unsigned char*)strData.c_str(), strlen(strData.c_str()), (const unsigned char*)sign_data.c_str(), 128, pRSAPublicKey);if(ret != 1){std::cout << "verify error\n";unsigned long ulErr = ERR_get_error();char szErrMsg[1024] = {0}; cout << "error number:" << ulErr << endl; char *pTmp = NULL; pTmp = ERR_error_string(ulErr,szErrMsg); // 格式:error:errId:库:函数:原因 cout << szErrMsg << endl;return -1;}elsestd::cout << "verify success\n";delete[] pEncode;RSA_free(pRSAPublicKey);fclose(hPubKeyFile);CRYPTO_cleanup_all_ex_data();return 1;}int main(void){try{//Socket::UDP sock;//sock.bind(3000);string m = "test";//hash SHA1unsigned char digest[SHA_DIGEST_LENGTH];SHA_CTX ctx;SHA1_Init(&ctx);SHA1_Update(&ctx, m.c_str(), strlen(m.c_str()));SHA1_Final(digest, &ctx);char mdString[SHA_DIGEST_LENGTH*2+1];for (int i = 0; i < SHA_DIGEST_LENGTH; i++)sprintf(&mdString[i*2], "%02x", (unsigned int)digest[i]);cout << "digest:" << digest << endl;std::cout << "SHA1 digest translate:" << mdString << endl;string digest_s((char*)digest);string mdString1(mdString);auto sign_ = SignRSAKeyFile("prikey.pem",mdString1);std::cout << "data:" << sign_ << std::endl;std::cout << "verify:" << VerifyRSAKeyFile("pubkey.pem",(const string)mdString,sign_);//Socket::Datagram received = sock.receive();//cout << received.data << endl;//sock.send("127.0.0.1", 2000, "request1");//Socket::Datagram received1 = sock.receive();//cout << received1.data << endl;//sock.close();}catch (Socket::Exception &e){cout << e.what() << endl;}return 0;}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。