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

转自 : http://blog.csdn.net/lzyuan1006/article/details/53905575


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


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


[cpp]  view plain  copy
  1. #include "openssl/sha.h"  
  2. #include "openssl/rsa.h"  
  3. #include "openssl/rand.h"  
  4. #include "openssl/objects.h"  
  5. #include "openssl/pem.h"  


实现代码:


[cpp]  view plain  copy
  1. char Dec2HexChar(short int n)  
  2. {  
  3.     if (0 <= n && n <= 9) {  
  4.         return char(short('0') + n);  
  5.     }  
  6.     else if (10 <= n && n <= 15) {  
  7.         return char(short('A') + n - 10);  
  8.     }  
  9.     else {  
  10.         return char(0);  
  11.     }  
  12. }  
  13.   
  14. short int HexChar2Dec(char c)  
  15. {  
  16.     if ('0' <= c && c <= '9') {  
  17.         return short(c - '0');  
  18.     }  
  19.     else if ('a' <= c && c <= 'f') {  
  20.         return (short(c - 'a') + 10);  
  21.     }  
  22.     else if ('A' <= c && c <= 'F') {  
  23.         return (short(c - 'A') + 10);  
  24.     }  
  25.     else {  
  26.         return -1;  
  27.     }  
  28. }  
  29.   
  30. std::string EncodeURL(const std::string &URL)  
  31. {  
  32.     std::string strResult = "";  
  33.     for (unsigned int i = 0; i < URL.size(); i++)  
  34.     {  
  35.         char c = URL[i];  
  36.         if (  
  37.             ('0' <= c && c <= '9') ||  
  38.             ('a' <= c && c <= 'z') ||  
  39.             ('A' <= c && c <= 'Z') ||  
  40.             c == '.'  
  41.             ) {  
  42.             strResult += c;  
  43.         }  
  44.         else  
  45.         {  
  46.             int j = (short int)c;  
  47.             if (j < 0)  
  48.             {  
  49.                 j += 256;  
  50.             }  
  51.             int i1, i0;  
  52.             i1 = j / 16;  
  53.             i0 = j - i1 * 16;  
  54.             strResult += '%';  
  55.             strResult += Dec2HexChar(i1);  
  56.             strResult += Dec2HexChar(i0);  
  57.         }  
  58.     }  
  59.   
  60.     return strResult;  
  61. }  
  62.   
  63. std::string DecodeURL(const std::string &URL)  
  64. {  
  65.     std::string result = "";  
  66.     for (unsigned int i = 0; i < URL.size(); i++)  
  67.     {  
  68.         char c = URL[i];  
  69.         if (c != '%')  
  70.         {  
  71.             result += c;  
  72.         }  
  73.         else  
  74.         {  
  75.             char c1 = URL[++i];  
  76.             char c0 = URL[++i];  
  77.             int num = 0;  
  78.             num += HexChar2Dec(c1) * 16 + HexChar2Dec(c0);  
  79.             result += char(num);  
  80.         }  
  81.     }  
  82.   
  83.     return result;  
  84. }  
  85.   
  86. //--生成GUID    
  87. const char* newGUID()  
  88. {  
  89.     static char buf[64] = { 0 };  
  90.     GUID guid;  
  91.     if (S_OK == ::CoCreateGuid(&guid))  
  92.     {  
  93.         _snprintf(buf, sizeof(buf)  
  94.             , "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X"  
  95.             , guid.Data1  
  96.             , guid.Data2  
  97.             , guid.Data3  
  98.             , guid.Data4[0], guid.Data4[1]  
  99.             , guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5]  
  100.             , guid.Data4[6], guid.Data4[7]  
  101.             );  
  102.     }  
  103.     return (const char*)buf;  
  104. }    
  105.   
  106. //将二进制流转换成base64编码  
  107. const char * base64char = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";  
  108. char * base64_encode(const unsigned char * bindata, char * base64, int binlength)  
  109. {  
  110.     int i, j;  
  111.     unsigned char current;  
  112.   
  113.     for (i = 0, j = 0; i < binlength; i += 3)  
  114.     {  
  115.         current = (bindata[i] >> 2);  
  116.         current &= (unsigned char)0x3F;  
  117.         base64[j++] = base64char[(int)current];  
  118.   
  119.         current = ((unsigned char)(bindata[i] << 4)) & ((unsigned char)0x30);  
  120.         if (i + 1 >= binlength)  
  121.         {  
  122.             base64[j++] = base64char[(int)current];  
  123.             base64[j++] = '=';  
  124.             base64[j++] = '=';  
  125.             break;  
  126.         }  
  127.         current |= ((unsigned char)(bindata[i + 1] >> 4)) & ((unsigned char)0x0F);  
  128.         base64[j++] = base64char[(int)current];  
  129.   
  130.         current = ((unsigned char)(bindata[i + 1] << 2)) & ((unsigned char)0x3C);  
  131.         if (i + 2 >= binlength)  
  132.         {  
  133.             base64[j++] = base64char[(int)current];  
  134.             base64[j++] = '=';  
  135.             break;  
  136.         }  
  137.         current |= ((unsigned char)(bindata[i + 2] >> 6)) & ((unsigned char)0x03);  
  138.         base64[j++] = base64char[(int)current];  
  139.   
  140.         current = ((unsigned char)bindata[i + 2]) & ((unsigned char)0x3F);  
  141.         base64[j++] = base64char[(int)current];  
  142.     }  
  143.     base64[j] = '\0';  
  144.     return base64;  
  145. }  
  146.   
  147. //签名  
  148. bool EncryptWithPrivateKey(const unsigned char * pData, char *pSignOut)  
  149. {  
  150.     RSA * rsa_pri_key = NULL;  
  151.     FILE * pFile = NULL;  
  152.   
  153.     //获取路径  
  154.     TCHAR szWorkDir[MAX_PATH] = TEXT("");  
  155.     CWHService::GetWorkDirectory(szWorkDir, CountArray(szWorkDir));  
  156.   
  157.     //构造路径  
  158.     TCHAR szrsa_private_keyFile[MAX_PATH] = TEXT("");  
  159.     _sntprintf(szrsa_private_keyFile, CountArray(szrsa_private_keyFile),   
  160.         TEXT("%s\\IniConfig\\rsa_private_key.pem"), szWorkDir);  
  161.   
  162.     if (NULL != (pFile = _wfopen(szrsa_private_keyFile, TEXT("r"))))  
  163.     {  
  164.         //读取私钥文件  
  165.         rsa_pri_key = PEM_read_RSAPrivateKey(pFile, NULL, NULL, NULL);  
  166.         fclose(pFile);  
  167.         if (rsa_pri_key == NULL)  
  168.         {  
  169.             LOGException("读取私钥文件内容失败!");  
  170.             return false;  
  171.         }  
  172.   
  173.         //先将源串SHA1算法加密, 后面+1是给结束符留的位置  
  174.         unsigned char szSha1Data[SHA_DIGEST_LENGTH+1] = { 0 };  
  175.         ZeroMemory(szSha1Data, sizeof(szSha1Data));   
  176.         SHA_CTX c;   
  177.         if (!SHA1_Init(&c))  
  178.         {  
  179.             LOGException("初始化sha1算法失败!");  
  180.             return false;  
  181.         }  
  182.         SHA1_Update(&c, pData, strlen((char*)pData));  
  183.         SHA1_Final(szSha1Data, &c);  
  184.         OPENSSL_cleanse(&c, sizeof(c));  
  185.            
  186.         //RSA签名  
  187.         unsigned char szTBSign[512] = { 0 };  
  188.         ZeroMemory(szTBSign, sizeof(szTBSign));  
  189.         unsigned int nLen = 0;  
  190.         int r = RSA_sign(NID_sha1, szSha1Data, SHA_DIGEST_LENGTH, szTBSign, &nLen, rsa_pri_key);  
  191.         RSA_free(rsa_pri_key);   
  192.   
  193.         if (1 == r)  
  194.         {  
  195.             //签名成功,转换成base64编码  
  196.             base64_encode(szTBSign, pSignOut, nLen);  
  197.             return true;  
  198.         }  
  199.         return false;   
  200.     }  
  201.     else  
  202.     {  
  203.         LOGException("读取私钥文件失败!");  
  204.     }  
  205.     return false;  
  206. }  


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

.h头文件

[cpp]  view plain  copy
  1. /** 
  2. * @brief HTTP POST请求 
  3. * @param strUrl 输入参数,请求的Url地址,如:http://www.baidu.com 
  4. * @param strPost 输入参数,使用如下格式para1=val1¶2=val2&… 
  5. * @param strResponse 输出参数,返回的内容 
  6. * @return 返回是否Post成功 
  7. */  
  8. int Post(const std::string & strUrl, const std::string & strPost, std::string & strResponse);  
  9.   
  10. /** 
  11. * @brief HTTP GET请求 
  12. * @param strUrl 输入参数,请求的Url地址,如:http://www.baidu.com 
  13. * @param strResponse 输出参数,返回的内容 
  14. * @return 返回是否Post成功 
  15. */  
  16. int Get(const std::string & strUrl, std::string & strResponse);  
  17.   
  18. /** 
  19. * @brief HTTPS POST请求,无证书版本 
  20. * @param strUrl 输入参数,请求的Url地址,如:https://www.alipay.com 
  21. * @param strPost 输入参数,使用如下格式para1=val1¶2=val2&… 
  22. * @param strResponse 输出参数,返回的内容 
  23. * @param pCaPath 输入参数,为CA证书的路径.如果输入为NULL,则不验证服务器端证书的有效性. 
  24. * @return 返回是否Post成功 
  25. */  
  26. int Posts(const std::string & strUrl, const std::string & strPost, std::string & strResponse, const char * pCaPath = NULL);  
  27.   
  28. /** 
  29. * @brief HTTPS GET请求,无证书版本 
  30. * @param strUrl 输入参数,请求的Url地址,如:https://www.alipay.com 
  31. * @param strResponse 输出参数,返回的内容 
  32. * @param pCaPath 输入参数,为CA证书的路径.如果输入为NULL,则不验证服务器端证书的有效性. 
  33. * @return 返回是否Post成功 
  34. */  
  35. int Gets(const std::string & strUrl, std::string & strResponse, const char * pCaPath = NULL);  

.cpp文件

[cpp]  view plain  copy
  1. int CAsyncEngineHttpSink::Post(const std::string & strUrl, const std::string & strPost, std::string & strResponse)  
  2. {  
  3.     CURLcode res;  
  4.     CURL* curl = curl_easy_init();  
  5.     if (NULL == curl)  
  6.     {  
  7.         return CURLE_FAILED_INIT;  
  8.     }   
  9.     curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());  
  10.     curl_easy_setopt(curl, CURLOPT_POST, 1);  
  11.     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost.c_str());  
  12.     curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);  
  13.     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);  
  14.     curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);  
  15.     curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);  
  16.     curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);  
  17.     curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);  
  18.     res = curl_easy_perform(curl);  
  19.     curl_easy_cleanup(curl);  
  20.     return res;  
  21. }  
  22.   
  23. int CAsyncEngineHttpSink::Get(const std::string & strUrl, std::string & strResponse)  
  24. {  
  25.     CURLcode res;  
  26.     CURL* curl = curl_easy_init();  
  27.     if (NULL == curl)  
  28.     {  
  29.         return CURLE_FAILED_INIT;  
  30.     }  
  31.     curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());  
  32.     curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);  
  33.     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);  
  34.     curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);  
  35.     /** 
  36.     * 当多个线程都使用超时处理的时候,同时主线程中有sleep或是wait等操作。 
  37.     * 如果不设置这个选项,libcurl将会发信号打断这个wait从而导致程序退出。 
  38.     */  
  39.     curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);  
  40.     curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);  
  41.     curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);  
  42.     res = curl_easy_perform(curl);  
  43.     curl_easy_cleanup(curl);  
  44.     return res;  
  45. }  
  46.   
  47. int CAsyncEngineHttpSink::Posts(const std::string & strUrl, const std::string & strPost, std::string & strResponse, const char * pCaPath)  
  48. {  
  49.     CURLcode res;  
  50.     CURL* curl = curl_easy_init();  
  51.     if (NULL == curl)  
  52.     {  
  53.         return CURLE_FAILED_INIT;  
  54.     }   
  55.     curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());  
  56.     curl_easy_setopt(curl, CURLOPT_POST, 1);  
  57.     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost.c_str());  
  58.     curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);  
  59.     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);  
  60.     curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);  
  61.     curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);  
  62.     if (NULL == pCaPath)  
  63.     {  
  64.         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);  
  65.         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);  
  66.     }  
  67.     else  
  68.     {  
  69.         //缺省情况就是PEM,所以无需设置,另外支持DER   
  70.         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);  
  71.         curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath);  
  72.     }  
  73.     curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);  
  74.     curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);  
  75.     res = curl_easy_perform(curl);  
  76.     curl_easy_cleanup(curl);  
  77.     return res;  
  78. }  
  79.   
  80. int CAsyncEngineHttpSink::Gets(const std::string & strUrl, std::string & strResponse, const char * pCaPath)  
  81. {  
  82.     CURLcode res;  
  83.     CURL* curl = curl_easy_init();  
  84.     if (NULL == curl)  
  85.     {  
  86.         return CURLE_FAILED_INIT;  
  87.     }   
  88.     curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());  
  89.     curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);  
  90.     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData);  
  91.     curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);  
  92.     curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);  
  93.     if (NULL == pCaPath)  
  94.     {  
  95.         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);  
  96.         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);  
  97.     }  
  98.     else  
  99.     {  
  100.         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);  
  101.         curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath);  
  102.     }  
  103.     curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);  
  104.     curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);  
  105.     res = curl_easy_perform(curl);  
  106.     curl_easy_cleanup(curl);  
  107.     return res;  
  108. }  

你可能感兴趣的:(c++基础,linux)