123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566 |
- #include "StdAfx.h"
- #include "PayApi.h"
- #include <algorithm>
- #include "EncodingConversion.h"
- // 支付宝公共参数;
- const string Alipay_default_charset = "utf-8";
- const string Alipay_default_url = "https://openapi.alipay.com/gateway.do";
- const string Alipay_default_sign_type = "RSA";
- const string Alipay_default_version = "1.0";
- const string Alipay_appid = "app_id";
- const string Alipay_method = "method";
- const string Alipay_charset = "charset";
- const string Alipay_signtype = "sign_type";
- const string Alipay_sign = "sign";
- const string Alipay_timestamp = "timestamp";
- const string Alipay_version = "version";
- const string Alipay_bizcontenr = "biz_content";
- PayApi::PayApi(void)
- {
- }
- PayApi::~PayApi(void)
- {
- }
- /************************************************************************/
- /* 函数:base64Encode[3/30/2017 Jeff];
- /* 描述:将字符串转成base64格式;
- /* 参数:;
- /* [IN] bytes:要转的字符串指针;
- /* [IN] len:字符串长度;
- /* 返回:void;
- /* 注意:;
- /* 示例:;
- /*
- /* 修改:;
- /* 日期:;
- /* 内容:;
- /************************************************************************/
- string PayApi::base64Encode(const unsigned char *bytes, int len)
- {
- BIO *bmem = NULL;
- BIO *b64 = NULL;
- BUF_MEM *bptr = NULL;
- b64 = BIO_new(BIO_f_base64());
- BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
- bmem = BIO_new(BIO_s_mem());
- b64 = BIO_push(b64, bmem);
- BIO_write(b64, bytes, len);
- BIO_flush(b64);
- BIO_get_mem_ptr(b64, &bptr);
- string str = string(bptr->data, bptr->length);
- BIO_free_all(b64);
- return str;
- }
- /************************************************************************/
- /* 函数:base64Decode[3/30/2017 Jeff];
- /* 描述:解码base64字符串;
- /* 参数:;
- /* [IN] str:要解码的base64字符串;
- /* [OUT] bytes:存储解码结果的字符串缓存指针;
- /* [OUT] len:解码后的字符串长度;
- /* 返回:void;
- /* 注意:;
- /* 示例:;
- /*
- /* 修改:;
- /* 日期:;
- /* 内容:;
- /************************************************************************/
- bool PayApi::base64Decode(const string &str, unsigned char *bytes, int &len)
- {
- const char *cstr = str.c_str();
- BIO *bmem = NULL;
- BIO *b64 = NULL;
- b64 = BIO_new(BIO_f_base64());
- BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
- bmem = BIO_new_mem_buf((void *)cstr, strlen(cstr));
- b64 = BIO_push(b64, bmem);
- len = BIO_read(b64, bytes, len);
- BIO_free_all(b64);
- return len > 0;
- }
- /************************************************************************/
- /* 函数:rsaSign[3/30/2017 Jeff];
- /* 描述:rsa签名;
- /* 参数:;
- /* [IN] content:要使用rsa签名的字符串;
- /* [IN] key:rsa签名的密钥;
- /* 返回:void;
- /* 注意:;
- /* 示例:;
- /*
- /* 修改:;
- /* 日期:;
- /* 内容:;
- /************************************************************************/
- string PayApi::rsaSign(const string &content, const string &key)
- {
- string signed_str;
- const char *key_cstr = key.c_str();
- int key_len = strlen(key_cstr);
- BIO *p_key_bio = BIO_new_mem_buf((void *)key_cstr, key_len);
- RSA *p_rsa = PEM_read_bio_RSAPrivateKey(p_key_bio, NULL, NULL, NULL);
- if (p_rsa != NULL) {
- const char *cstr = content.c_str();
- unsigned char hash[SHA_DIGEST_LENGTH] = { 0 };
- SHA1((unsigned char *)cstr, strlen(cstr), hash);
- unsigned char sign[XRSA_KEY_BITS / 8] = { 0 };
- unsigned int sign_len = sizeof(sign);
- int r = RSA_sign(NID_sha1, hash, SHA_DIGEST_LENGTH, sign, &sign_len, p_rsa);
- if (0 != r && sizeof(sign) == sign_len) {
- signed_str = base64Encode(sign, sign_len);
- }
- }
- RSA_free(p_rsa);
- BIO_free(p_key_bio);
- return signed_str;
- }
- /************************************************************************/
- /* 函数:rsaVerify[3/30/2017 Jeff];
- /* 描述:rsa签名验证;
- /* 参数:;
- /* [IN] content:要验证的字符串;
- /* [IN] sign:验证比较的rsa签名;
- /* [IN] key:rsa签名的密钥;
- /* 返回:void;
- /* 注意:;
- /* 示例:;
- /*
- /* 修改:;
- /* 日期:;
- /* 内容:;
- /************************************************************************/
- bool PayApi::rsaVerify(const string &content, const string &sign, const string &key)
- {
- bool result = false;
- const char *key_cstr = key.c_str();
- int key_len = strlen(key_cstr);
- BIO *p_key_bio = BIO_new_mem_buf((void *)key_cstr, key_len);
- RSA *p_rsa = PEM_read_bio_RSA_PUBKEY(p_key_bio, NULL, NULL, NULL);
- if (p_rsa != NULL) {
- const char *cstr = content.c_str();
- unsigned char hash[SHA_DIGEST_LENGTH] = { 0 };
- SHA1((unsigned char *)cstr, strlen(cstr), hash);
- unsigned char sign_cstr[XRSA_KEY_BITS / 8] = { 0 };
- int len = XRSA_KEY_BITS / 8;
- base64Decode(sign, sign_cstr, len);
- unsigned int sign_len = XRSA_KEY_BITS / 8;
- int r = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH, (unsigned char *)sign_cstr, sign_len, p_rsa);
- if (r > 0) {
- result = true;
- }
- }
- RSA_free(p_rsa);
- BIO_free(p_key_bio);
- return result;
- }
- /************************************************************************/
- /* 函数:alipay_setCommonParam[3/30/2017 Jeff];
- /* 描述:设置支付宝支付的公共参数;
- /* 参数:;
- /* [IN] appid:支付宝分配开发者的应用ID;
- /* [IN] privatekey:私钥;
- /* [IN] signtype:签名方式;
- /* [IN] charset:字符集;
- /* [IN] version:版本;
- /* [IN] url:主url;
- /* [IN] publickey:公钥;
- /* 返回:void;
- /* 注意:;
- /* 示例:;
- /*
- /* 修改:;
- /* 日期:;
- /* 内容:;
- /************************************************************************/
- void PayApi::alipay_setCommonParam( const string &appid, const string &privatekey, const string &signtype, const string &charset, const string &version, const string &url, const string &publickey )
- {
- alipay_appid = appid;
- alipay_privatekey = privatekey;
- alipay_signtype = signtype;
- alipay_charset = charset;
- alipay_version = version;
- alipay_url = url;
- alipay_PublicKey = publickey;
- }
- /************************************************************************/
- /* 函数:[3/30/2017 Jeff];
- /* 描述:;
- /* 参数:;
- /* [IN] :;
- /* [OUT] :;
- /* [IN/OUT] :;
- /* 返回:void;
- /* 注意:;
- /* 示例:;
- /*
- /* 修改:;
- /* 日期:;
- /* 内容:;
- /************************************************************************/
- string PayApi::buildContent(const StringMap &contentPairs)
- {
- string content;
- for (StringMap::const_iterator iter = contentPairs.begin();
- iter != contentPairs.end(); ++iter) {
- if (!content.empty()) {
- content.push_back('&');
- }
- content.append(iter->first);
- content.push_back('=');
- content.append(iter->second);
- }
- return content;
- }
- /************************************************************************/
- /* 函数:[3/30/2017 Jeff];
- /* 描述:;
- /* 参数:;
- /* [IN] :;
- /* [OUT] :;
- /* [IN/OUT] :;
- /* 返回:void;
- /* 注意:;
- /* 示例:;
- /*
- /* 修改:;
- /* 日期:;
- /* 内容:;
- /************************************************************************/
- string PayApi::alipay_invoke(const string & method, const JsonMap & contentMap, const StringMap & extendParamMap)
- {
- string content = JsonUtil::objectToString(JsonType(contentMap));
- return alipay_invoke(method, content, extendParamMap);
- }
- /************************************************************************/
- /* 函数:[3/30/2017 Jeff];
- /* 描述:;
- /* 参数:;
- /* [IN] :;
- /* [OUT] :;
- /* [IN/OUT] :;
- /* 返回:void;
- /* 注意:;
- /* 示例:;
- /*
- /* 修改:;
- /* 日期:;
- /* 内容:;
- /************************************************************************/
- JsonMap PayApi::alipay_Str2JsonMap(string strJson)
- {
- //获取返回报文中的alipay_xxx_xxx_response的内容;
- int beg = strJson.find("_response\"");
- int end = strJson.rfind("\"sign\"");
- if (beg < 0 || end < 0)
- {
- JsonType jsonObj = JsonUtil::stringToObject(strJson);
- return jsonObj.toMap();
- }
- beg = strJson.find('{', beg);
- end = strJson.rfind('}', end);
- strJson = strJson.substr(beg, end - beg + 1);
- JsonType jsonObj = JsonUtil::stringToObject(strJson);
- return jsonObj.toMap();
- }
- /************************************************************************/
- /* 函数:[3/31/2017 Jeff];
- /* 描述:;
- /* 参数:;
- /* [IN] :;
- /* [OUT] :;
- /* [IN/OUT] :;
- /* 返回:void;
- /* 注意:;
- /* 示例:;
- /*
- /* 修改:;
- /* 日期:;
- /* 内容:;
- /************************************************************************/
- string PayApi::alipay_invoke(const string & method, const string & content, const StringMap & extendParamMap)
- {
- // 生成时间缀;
- time_t t = time(0);
- char tmp[64];
- strftime(tmp, sizeof(tmp), "%Y-%m-%d %X", localtime(&t));
- // 补全公共参数;
- StringMap requestPairs;
- requestPairs.insert(StringMap::value_type(Alipay_appid, alipay_appid));
- requestPairs.insert(StringMap::value_type(Alipay_bizcontenr, content));
- requestPairs.insert(StringMap::value_type(Alipay_charset, alipay_charset));
- requestPairs.insert(StringMap::value_type(Alipay_method, method));
- requestPairs.insert(StringMap::value_type(Alipay_signtype, alipay_signtype));
- requestPairs.insert(StringMap::value_type(Alipay_timestamp, tmp));
- requestPairs.insert(StringMap::value_type(Alipay_version, alipay_version));
- /** 追加外部传入的网关的补充参数,如notify_url等 **/
- for (StringMap::const_iterator iter = extendParamMap.begin(); iter != extendParamMap.end(); ++iter) {
- requestPairs.insert(StringMap::value_type(iter->first, iter->second));
- }
- string wholeContent = buildContent(requestPairs);
- string sign = rsaSign(wholeContent, alipay_privatekey);
- requestPairs.insert(StringMap::value_type(Alipay_sign, sign));
- wholeContent = buildContent(requestPairs);
- #ifdef _DEBUG
- WriteTextLog("\r\nRequest:%s\r\n", wholeContent.c_str());
- #endif
- HttpClient httpClient;
- string responseStr = httpClient.sendSyncRequest(alipay_url, requestPairs);
- #ifdef _DEBUG
- WriteTextLog("\r\nResponse:%s\r\n", responseStr.c_str());
- #endif
- // 验签失败原因未找到,暂时不处理;
- //string responseContent = analyzeAliResponse(responseStr);
- //return responseContent;
- return responseStr;
- }
- string PayApi::analyzeAliResponse(const string & responseStr)
- {
- JsonType responseObj = JsonUtil::stringToObject(responseStr);
- JsonMap responseMap = responseObj.toMap();
- //获取返回报文中的alipay_xxx_xxx_response的内容;
- int beg = responseStr.find("_response\"");
- int end = responseStr.rfind("\"sign\"");
- if (beg < 0 || end < 0)
- {
- return string();
- }
- beg = responseStr.find('{', beg);
- end = responseStr.rfind('}', end);
- //注意此处将map转为json之后的结果需要与支付宝返回报文中原格式与排序一致;
- //排序规则是节点中的各个json节点key首字母做字典排序;
- //Response的Json值内容需要包含首尾的“{”和“}”两个尖括号,双引号也需要参与验签;
- //如果字符串中包含“http://”的正斜杠,需要先将正斜杠做转义,默认打印出来的字符串是已经做过转义的;
- //此处转换之后的json字符串默认为"Compact"模式,即紧凑模式,不要有空格与换行;
- string responseContent = responseStr.substr(beg, end - beg + 1);
- DebugLog("ResponseContent:%s", responseContent.c_str());
- //此处为校验支付宝返回报文中的签名;
- //如果支付宝公钥为空,则默认跳过该步骤,不校验签名;
- //如果支付宝公钥不为空,则认为需要校验签名;
- if (!alipay_PublicKey.empty())
- {
- DebugLog("AlipayPublicKey:%s", alipay_PublicKey.c_str());
- JsonMap::const_iterator iter = responseMap.find(Alipay_sign);
- if (iter == responseMap.end())
- {
- DebugLog("Cannot get Sign from response, Verify Failed");
- return string();
- }
- //获取返回报文中的sign;
- string responseSign = iter->second.toString();
- DebugLog("ResponseSign:%s", responseSign.c_str());
- //调用验签方法;
- bool verifyResult = rsaVerify(responseContent, responseSign, alipay_PublicKey);
- if (!verifyResult) {
- DebugLog("Verify Failed");
- return string();
- }
- DebugLog("Verify Success");
- }
- else
- {
- DebugLog("AlipayPublicKey is empty, Skip the Verify");
- }
- return responseContent;
- }
- /************************************************************************/
- /* 函数:[3/31/2017 Jeff];
- /* 描述:;
- /* 参数:;
- /* [IN] :;
- /* [OUT] :;
- /* [IN/OUT] :;
- /* 返回:void;
- /* 注意:;
- /* 示例:;
- /*
- /* 修改:;
- /* 日期:;
- /* 内容:;
- /************************************************************************/
- void PayApi::wxpay_setCommonParam(const string & appid, const string & mchid, const string & privatekey)
- {
- wxpay_appid = appid;
- wxpay_mchid = mchid;
- wxpay_privatekey = privatekey;
- }
- /************************************************************************/
- /* 函数:[3/30/2017 Jeff];
- /* 描述:;
- /* 参数:;
- /* [IN] :;
- /* [OUT] :;
- /* [IN/OUT] :;
- /* 返回:void;
- /* 注意:;
- /* 示例:;
- /*
- /* 修改:;
- /* 日期:;
- /* 内容:;
- /************************************************************************/
- string PayApi::wxapi_getSign(StringMap &strMap, string key)
- {
- string strtemp;
- vector<string> vtString;
- for (StringMap::const_iterator iter = strMap.begin(); iter != strMap.end(); iter++)
- {
- if ( _tcscmp(iter->first.c_str(), "sign") != 0 && iter->second.size() != 0 )
- {// 除去sign本身;
- strtemp = iter->first;
- strtemp.append("=");
- strtemp.append(iter->second);
- vtString.push_back(strtemp);
- }
- }
- strtemp.clear();
- std::sort(vtString.begin(), vtString.end());
- for (vector<string>::iterator it = vtString.begin(); it != vtString.end(); it++ )
- {
- strtemp.append(it->c_str());
- strtemp.append("&");
- }
- strtemp.append("key=");
- strtemp.append(key);
- #ifdef _DEBUG
- WriteTextLog("合并:%s\n", strtemp.c_str());
- #endif
- // 计算MD5,必须使用utf-8来计算;
- EncodingConverion::ASCII2UTF8(strtemp.c_str(), strtemp);
- // md5加密;
- MD5_CTX ctx;
- char sztmp[3] = {0};
- unsigned char szmd[16] = {0};
- MD5_Init(&ctx);
- MD5_Update(&ctx, strtemp.data(), strtemp.size());
- MD5_Final(szmd, &ctx);
- strtemp.clear();
- for ( int i = 0; i < 16; i++ )
- {
- sprintf_s(sztmp, "%02X", szmd[i]);
- strtemp.append(sztmp);
- }
- #ifdef _DEBUG
- WriteTextLog("MD5:%s\n", strtemp.c_str());
- #endif
- return strtemp;
- }
- /************************************************************************/
- /* 函数:[3/30/2017 Jeff];
- /* 描述:;
- /* 参数:;
- /* [IN] :;
- /* [OUT] :;
- /* [IN/OUT] :;
- /* 返回:void;
- /* 注意:;
- /* 示例:;
- /*
- /* 修改:;
- /* 日期:;
- /* 内容:;
- /************************************************************************/
- string PayApi::wxpay_invoke(const string &method, StringMap &extendParamMap, string key )
- {
- // 计算出签名;
- string sign = wxapi_getSign(extendParamMap, key);
- // 将签名加入;
- extendParamMap.insert(StringMap::value_type("sign", sign));
- tinyxml2::XMLDocument doc;
- tinyxml2::XMLNode *node = doc.InsertEndChild(doc.NewElement("xml"));
- tinyxml2::XMLElement *subelement = NULL;
- for (StringMap::const_iterator iter = extendParamMap.begin(); iter != extendParamMap.end(); ++iter)
- {
- subelement = doc.NewElement(iter->first.c_str());
- subelement->SetText(iter->second.c_str());
- node->InsertEndChild(subelement);
- }
- tinyxml2::XMLPrinter printer;
- doc.Print(&printer);
- string result = printer.CStr();
- EncodingConverion::ASCII2UTF8(result.c_str(), result);
- HttpClient httpClient;
- string responseStr = httpClient.sendSyncRequest(method, result);
- EncodingConverion::UTF82ASCII(responseStr.c_str(), responseStr);
- #ifdef _DEBUG
- WriteTextLog("返回码:%s\n", responseStr.c_str());
- #endif
- DebugLog("Response:%s", responseStr.c_str());
- return responseStr;
- }
- /************************************************************************/
- /* 函数:[3/30/2017 Jeff];
- /* 描述:;
- /* 参数:;
- /* [IN] :;
- /* [OUT] :;
- /* [IN/OUT] :;
- /* 返回:void;
- /* 注意:;
- /* 示例:;
- /*
- /* 修改:;
- /* 日期:;
- /* 内容:;
- /************************************************************************/
- string PayApi::analyzeWXRespone(const string &respone)
- {
- return "";
- }
|