Created
August 13, 2016 06:55
-
-
Save zjx20/867de752768a2d7f13a9b82b77e577de to your computer and use it in GitHub Desktop.
alipay in c++
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef __ALIPAY_H__ | |
#define __ALIPAY_H__ | |
#include "base64/base64.h" | |
#include <curl/curl.h> | |
#include <map> | |
#include <openssl/bio.h> | |
#include <openssl/rsa.h> | |
#include <openssl/pem.h> | |
#include <openssl/err.h> | |
class Rsa { | |
public: | |
static bool verify(const char *public_key, | |
const string &content, const string &sign) { | |
BIO *bufio = NULL; | |
RSA *rsa = NULL; | |
EVP_PKEY *evpKey = NULL; | |
bool verify = false; | |
EVP_MD_CTX ctx; | |
int result = 0; | |
string decodedSign = base64_decode(sign); | |
char *chDecodedSign = const_cast<char*>(decodedSign.c_str()); | |
bufio = BIO_new_mem_buf((void*)public_key, -1); | |
if (bufio == NULL) { | |
ERR("BIO_new_mem_buf failed"); | |
goto safe_exit; | |
} | |
rsa = PEM_read_bio_RSA_PUBKEY(bufio, NULL, NULL, NULL); | |
if (rsa == NULL) { | |
ERR("PEM_read_bio_RSA_PUBKEY failed"); | |
goto safe_exit; | |
} | |
evpKey = EVP_PKEY_new(); | |
if (evpKey == NULL) { | |
ERR("EVP_PKEY_new failed"); | |
goto safe_exit; | |
} | |
if ((result = EVP_PKEY_set1_RSA(evpKey, rsa)) != 1) { | |
ERR("EVP_PKEY_set1_RSA failed"); | |
goto safe_exit; | |
} | |
EVP_MD_CTX_init(&ctx); | |
if (result == 1 && (result = EVP_VerifyInit_ex(&ctx, | |
EVP_sha1(), NULL)) != 1) { | |
ERR("EVP_VerifyInit_ex failed"); | |
} | |
if (result == 1 && (result = EVP_VerifyUpdate(&ctx, | |
content.c_str(), content.size())) != 1) { | |
ERR("EVP_VerifyUpdate failed"); | |
} | |
if (result == 1 && (result = EVP_VerifyFinal(&ctx, | |
(unsigned char*)chDecodedSign, | |
decodedSign.size(), evpKey)) != 1) { | |
ERR("EVP_VerifyFinal failed"); | |
} | |
if (result == 1) { | |
verify = true; | |
} else { | |
ERR("verify failed"); | |
} | |
EVP_MD_CTX_cleanup(&ctx); | |
safe_exit: | |
if (rsa != NULL) { | |
RSA_free(rsa); | |
rsa = NULL; | |
} | |
if (evpKey != NULL) { | |
EVP_PKEY_free(evpKey); | |
evpKey = NULL; | |
} | |
if (bufio != NULL) { | |
BIO_free_all(bufio); | |
bufio = NULL; | |
} | |
return verify; | |
} | |
static string sign(const char *private_key, | |
const string &content) { | |
BIO *bufio = NULL; | |
RSA *rsa = NULL; | |
EVP_PKEY *evpKey = NULL; | |
bool verify = false; | |
EVP_MD_CTX ctx; | |
int result = 0; | |
unsigned int size = 0; | |
char *sign = NULL; | |
string signStr = ""; | |
bufio = BIO_new_mem_buf((void*)private_key, -1); | |
if (bufio == NULL) { | |
ERR("BIO_new_mem_buf failed"); | |
goto safe_exit; | |
} | |
rsa = PEM_read_bio_RSAPrivateKey(bufio, NULL, NULL, NULL); | |
if (rsa == NULL) { | |
ERR("PEM_read_bio_RSAPrivateKey failed"); | |
goto safe_exit; | |
} | |
evpKey = EVP_PKEY_new(); | |
if (evpKey == NULL) { | |
ERR("EVP_PKEY_new failed"); | |
goto safe_exit; | |
} | |
if ((result = EVP_PKEY_set1_RSA(evpKey, rsa)) != 1) { | |
ERR("EVP_PKEY_set1_RSA failed"); | |
goto safe_exit; | |
} | |
EVP_MD_CTX_init(&ctx); | |
if (result == 1 && (result = EVP_SignInit_ex(&ctx, | |
EVP_sha1(), NULL)) != 1) { | |
ERR("EVP_SignInit_ex failed"); | |
} | |
if (result == 1 && (result = EVP_SignUpdate(&ctx, | |
content.c_str(), content.size())) != 1) { | |
ERR("EVP_SignUpdate failed"); | |
} | |
size = EVP_PKEY_size(evpKey); | |
sign = (char*)malloc(size+1); | |
memset(sign, 0, size+1); | |
if (result == 1 && (result = EVP_SignFinal(&ctx, | |
(unsigned char*)sign, | |
&size, evpKey)) != 1) { | |
ERR("EVP_SignFinal failed"); | |
} | |
if (result == 1) { | |
verify = true; | |
} else { | |
ERR("verify failed"); | |
} | |
signStr = base64_encode((const unsigned char*)sign, size); | |
EVP_MD_CTX_cleanup(&ctx); | |
free(sign); | |
safe_exit: | |
if (rsa != NULL) { | |
RSA_free(rsa); | |
rsa = NULL; | |
} | |
if (evpKey != NULL) { | |
EVP_PKEY_free(evpKey); | |
evpKey = NULL; | |
} | |
if (bufio != NULL) { | |
BIO_free_all(bufio); | |
bufio = NULL; | |
} | |
return signStr; | |
} | |
private: | |
static void ERR(const string &pre) { | |
ERR_load_crypto_strings(); | |
char buf[512]; | |
ERR_error_string_n(ERR_get_error(), buf, sizeof buf); | |
// log error here | |
} | |
}; | |
// partner number, start with 2088 | |
#define PARTNER "" | |
// alipay verify url, used to check notify_id | |
// to confirm the data is sent by alibaba | |
#define HTTPS_VERIFY_URL "https://mapi.alipay.com/gateway.do?service=notify_verify" | |
// our private key, PKCS#8 format | |
#define PRIVATE_KEY "" | |
// alipay public key, used to check data from alibaba | |
#define PUBLIC_KEY "" | |
#define SUBJECT "" | |
#define SELLER_ID "" | |
#define BODY "" | |
class Alipay { | |
public: | |
/* verify callback data */ | |
static bool verify(CgiUtil &cgi) { | |
string responseTxt = "true"; | |
string notifyId = cgi.get_str("notify_id", ""); | |
if (!notifyId.empty()) { | |
responseTxt = verify_response(notifyId); | |
} | |
string sign = cgi.get_str("sign", ""); | |
bool isSign = get_sign_verify(cgi, sign); | |
if (isSign && responseTxt == "true") { | |
return true; | |
} | |
return false; | |
} | |
static string get_order(const string &oid, | |
unsigned int price, const string &cb_url) { | |
string orderInfo = get_order_info(oid, price, cb_url); | |
// we just support RSA right now, don't bother | |
string sign = Rsa::sign(PRIVATE_KEY, orderInfo); | |
stringstream ss; | |
ss << orderInfo | |
<< "&sign=\"" | |
<< url_encode(sign) | |
<< "\"&" | |
<< "sign_type=\"RSA\""; | |
return ss.str(); | |
} | |
private: | |
static string get_order_info(const string &oid, | |
unsigned int price, const string &cb_url) { | |
float payMoney = (float)price / 100.0; | |
string encode_url = url_encode(cb_url); | |
stringstream ss; | |
ss << "service=\"mobile.securitypay.pay\"&" | |
<< "partner=\"" | |
<< PARTNER | |
<< "\"&" | |
<< "_input_charset=\"utf-8\"&" | |
<< "notify_url=\"" | |
<< encode_url | |
<< "\"&" | |
<< "out_trade_no=\"" | |
<< oid | |
<< "\"&" | |
<< "subject=\"" | |
<< SUBJECT | |
<< "\"&" | |
<< "payment_type=\"1\"&" | |
<< "seller_id=\"" | |
<< SELLER_ID | |
<< "\"&" | |
<< "total_fee=\"" | |
<< payMoney | |
<< "\"&" | |
<< "body=\"" | |
<< BODY | |
<< "\""; | |
return ss.str(); | |
} | |
static string verify_response(const string ¬ifyId) { | |
stringstream ss; | |
ss << HTTPS_VERIFY_URL | |
<< "&partner=" | |
<< PARTNER | |
<< "¬ify_id=" | |
<< notifyId; | |
// do it yourself using curl | |
return check_alipay_cb_url(ss.str().c_str()); | |
} | |
static bool get_sign_verify(CgiUtil &cgi, string sign) { | |
std::map<string, string> map; | |
para_filter(cgi, map); | |
string preSignStr = create_link_string(map); | |
bool isSign = false; | |
// RSA verify | |
if (Rsa::verify(PUBLIC_KEY, preSignStr, sign)) { | |
isSign = true; | |
} | |
return isSign; | |
} | |
static void para_filter(CgiUtil &cgi, | |
std::map<string, string> &hmap) { | |
vector<FormEntry> entry = cgi.getElements(); | |
vector<FormEntry>::iterator it = entry.begin(); | |
for (; it != entry.end(); it++) { | |
FormEntry fe = *it; | |
string name = fe.getName(); | |
string value = fe.getValue(); | |
if (value == "" || iequal(name, "sign") || | |
iequal(name, "sign_type")) { | |
continue; | |
} | |
hmap.insert(pair<string, string>(name, value)); | |
} | |
} | |
static string create_link_string(std::map<string, string> &map) { | |
std::map<string, string>::iterator it = map.begin(); | |
unsigned int size = map.size(); | |
stringstream ss; | |
for (unsigned int i = 0; it != map.end() && | |
i < size; it ++, i ++) { | |
if (i == size - 1) { | |
ss << it->first << "=" << it->second; | |
} else { | |
ss << it->first << "=" << it->second << "&"; | |
} | |
} | |
return ss.str(); | |
} | |
static string url_encode(const string &url) { | |
string encode = ""; | |
char *data_encode = curl_easy_escape(NULL, url.c_str(), 0); | |
if (data_encode) { | |
encode = data_encode; | |
curl_free(data_encode); | |
} | |
return encode; | |
} | |
}; | |
#endif /* __ALIPAY_H__ */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment