Skip to content

Instantly share code, notes, and snippets.

@zjx20
Created August 13, 2016 06:55
Show Gist options
  • Save zjx20/867de752768a2d7f13a9b82b77e577de to your computer and use it in GitHub Desktop.
Save zjx20/867de752768a2d7f13a9b82b77e577de to your computer and use it in GitHub Desktop.
alipay in c++
#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 &notifyId) {
stringstream ss;
ss << HTTPS_VERIFY_URL
<< "&partner="
<< PARTNER
<< "&notify_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