|
|
@ -0,0 +1,402 @@ |
|
|
|
package helper |
|
|
|
|
|
|
|
import ( |
|
|
|
"bytes" |
|
|
|
"encoding/base64" |
|
|
|
"encoding/hex" |
|
|
|
"errors" |
|
|
|
"git.tetele.net/tgo/crypter" |
|
|
|
"github.com/ZZMarquis/gm/sm2" |
|
|
|
"github.com/ZZMarquis/gm/sm3" |
|
|
|
jsoniter "github.com/json-iterator/go" |
|
|
|
"io/ioutil" |
|
|
|
"log" |
|
|
|
"math/big" |
|
|
|
"net/http" |
|
|
|
"reflect" |
|
|
|
"sort" |
|
|
|
"strings" |
|
|
|
"time" |
|
|
|
) |
|
|
|
|
|
|
|
var json = jsoniter.ConfigCompatibleWithStandardLibrary |
|
|
|
|
|
|
|
// 合并map数据
|
|
|
|
func MergeMapData(x, y map[string]interface{}) map[string]interface{} { |
|
|
|
|
|
|
|
n := make(map[string]interface{}) |
|
|
|
|
|
|
|
for i, v := range x { |
|
|
|
for j, w := range y { |
|
|
|
if i == j { |
|
|
|
n[i] = w |
|
|
|
|
|
|
|
} else { |
|
|
|
if _, ok := n[i]; !ok { |
|
|
|
n[i] = v |
|
|
|
} |
|
|
|
if _, ok := n[j]; !ok { |
|
|
|
n[j] = w |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return n |
|
|
|
} |
|
|
|
|
|
|
|
// 针对传参为json或者数组类型的字段,进行字符串排序
|
|
|
|
func HttpBuildSort(data map[string]interface{}) string { |
|
|
|
keySlice := []string{} |
|
|
|
|
|
|
|
for k, _ := range data { |
|
|
|
keySlice = append(keySlice, k) |
|
|
|
} |
|
|
|
// 排序字符串
|
|
|
|
sort.Strings(keySlice) |
|
|
|
|
|
|
|
res := make(map[string]interface{}, 0) |
|
|
|
|
|
|
|
for _, value := range keySlice { |
|
|
|
data_val := ToStr(data[value]) |
|
|
|
|
|
|
|
if value != "" && data_val != "" { |
|
|
|
res[value] = data_val |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
res_byte, _ := json.Marshal(res) |
|
|
|
|
|
|
|
return string(res_byte) |
|
|
|
} |
|
|
|
|
|
|
|
// body参数处理
|
|
|
|
func FormatBodyData(body map[string]interface{}) map[string]interface{} { |
|
|
|
data := map[string]interface{}{} |
|
|
|
|
|
|
|
if len(body) > 0 { |
|
|
|
for k, v := range body { |
|
|
|
typeOfA := reflect.TypeOf(v) |
|
|
|
|
|
|
|
if typeOfA.Kind().String() == "map" { |
|
|
|
build_str_format, _ := InterfaceToMapInterface(v) |
|
|
|
|
|
|
|
if len(build_str_format) < 1 { |
|
|
|
continue |
|
|
|
} |
|
|
|
// json键值对处理
|
|
|
|
data[k] = HttpBuildSort(build_str_format) |
|
|
|
// log.Println("排序后的数据: ", data[k])
|
|
|
|
} else if typeOfA.Kind().String() == "slice" { |
|
|
|
val_slice := []interface{}{} |
|
|
|
// json键值对处理
|
|
|
|
for _, val_inter := range v.([]interface{}) { |
|
|
|
val_map, _ := InterfaceToMapInterface(val_inter) |
|
|
|
each_val := HttpBuildSort(val_map) |
|
|
|
val_slice = append(val_slice, each_val) |
|
|
|
} |
|
|
|
|
|
|
|
if len(val_slice) < 1 { |
|
|
|
continue |
|
|
|
} |
|
|
|
|
|
|
|
data[k] = val_slice |
|
|
|
// log.Println("排序后的数据: ", data[k])
|
|
|
|
} else { |
|
|
|
data[k] = v |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return data |
|
|
|
} |
|
|
|
|
|
|
|
// 字符串排序拼接
|
|
|
|
func CmbHttpBuildQuery(data map[string]interface{}, filter_sign bool) string { |
|
|
|
keySlice := []string{} |
|
|
|
// 剔除sign字段
|
|
|
|
for k, _ := range data { |
|
|
|
if filter_sign && k == "sign" { |
|
|
|
continue |
|
|
|
} |
|
|
|
keySlice = append(keySlice, k) |
|
|
|
} |
|
|
|
// 排序字符串
|
|
|
|
sort.Strings(keySlice) |
|
|
|
|
|
|
|
var query string |
|
|
|
|
|
|
|
for _, value := range keySlice { |
|
|
|
if value != "" && data[value] != "" { |
|
|
|
query += StringJoin(value, "=", ToStr(data[value]), "&") |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
build_str := strings.Trim(query, "&") |
|
|
|
|
|
|
|
log.Println("拼接后的数据: ", build_str) |
|
|
|
return build_str |
|
|
|
} |
|
|
|
|
|
|
|
// 生成签名sign--聚合支付
|
|
|
|
func SetSign(data map[string]interface{}, privateKey string) string { |
|
|
|
log.Println("招行加签start") |
|
|
|
build_str := CmbHttpBuildQuery(data, true) |
|
|
|
|
|
|
|
priv := new(sm2.PrivateKey) |
|
|
|
priv.Curve = sm2.GetSm2P256V1() |
|
|
|
dBytes, _ := hex.DecodeString(privateKey) |
|
|
|
priv.D = new(big.Int).SetBytes(dBytes) |
|
|
|
|
|
|
|
signature, err := sm2.Sign(priv, []byte("1234567812345678"), []byte(build_str)) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
log.Println("国密加密异常", err) |
|
|
|
return "" |
|
|
|
} |
|
|
|
|
|
|
|
sign := base64.StdEncoding.EncodeToString(signature) |
|
|
|
|
|
|
|
log.Println("加密后sign值: ", sign) |
|
|
|
log.Println("招行加签end") |
|
|
|
return sign |
|
|
|
} |
|
|
|
|
|
|
|
// 创建请求头信息--聚合支付
|
|
|
|
func HeaderInfo(appid, secret, sign string) map[string]string { |
|
|
|
if appid == "" || secret == "" || sign == "" { |
|
|
|
return map[string]string{} |
|
|
|
} |
|
|
|
|
|
|
|
headerData := map[string]string{} |
|
|
|
|
|
|
|
headerData["appid"] = appid |
|
|
|
headerData["sign"] = sign |
|
|
|
headerData["secret"] = secret |
|
|
|
headerData["timestamp"] = ToStr(time.Now().Unix()) |
|
|
|
|
|
|
|
build_str := CmbHttpBuildQuery(MapStringToInterface(headerData), false) |
|
|
|
|
|
|
|
headerData["apisign"] = crypter.Md5Str(build_str) |
|
|
|
|
|
|
|
delete(headerData, "sign") |
|
|
|
delete(headerData, "secret") |
|
|
|
|
|
|
|
log.Println("header信息", headerData) |
|
|
|
|
|
|
|
return headerData |
|
|
|
} |
|
|
|
|
|
|
|
// 接口验签--各客户端请求我们接口验签
|
|
|
|
func CheckSign(appid, app_secret, timeStamp, nonce, sign string, body map[string]interface{}) error { |
|
|
|
log.Println("请求验签start") |
|
|
|
|
|
|
|
/*time_now := time.Now().Unix() |
|
|
|
|
|
|
|
if time_now-ToInt64(timeStamp) > 10 { |
|
|
|
return errors.New("请求时间超出范围,拒绝访问") |
|
|
|
}*/ |
|
|
|
|
|
|
|
sign_info := map[string]interface{}{ |
|
|
|
"appid": appid, |
|
|
|
"timestamp": timeStamp, |
|
|
|
"nonce": nonce, |
|
|
|
} |
|
|
|
|
|
|
|
if len(body) > 0 { |
|
|
|
body_format := FormatBodyDataNoList(body) |
|
|
|
sign_info = MergeMapData(sign_info, body_format) |
|
|
|
} |
|
|
|
|
|
|
|
str := CmbHttpBuildQuery(sign_info, false) + "&" + app_secret |
|
|
|
log.Println("加密前数据: ", str) |
|
|
|
sign_str := crypter.Md5Str(str) |
|
|
|
log.Println("加密后数据: ", sign_str) |
|
|
|
|
|
|
|
if sign_str != sign { |
|
|
|
return errors.New("签名不正确") |
|
|
|
} |
|
|
|
|
|
|
|
log.Println("请求验签end") |
|
|
|
|
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
// post 请求
|
|
|
|
func PostJsonData(url string, param interface{}, headerinfo map[string]string) ([]byte, error) { |
|
|
|
httpClient := &http.Client{} |
|
|
|
params, err := json.Marshal(param) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
return []byte(""), err |
|
|
|
} |
|
|
|
|
|
|
|
log.Println(bytes.NewBuffer(params)) |
|
|
|
|
|
|
|
req, err := http.NewRequest("POST", url, bytes.NewBuffer(params)) |
|
|
|
if err != nil { |
|
|
|
return []byte(""), err |
|
|
|
} |
|
|
|
|
|
|
|
req.Header.Set("Content-Type", "application/json") |
|
|
|
|
|
|
|
if len(headerinfo) > 0 { |
|
|
|
for k, v := range headerinfo { |
|
|
|
req.Header[k] = []string{v} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
resp, err := httpClient.Do(req) |
|
|
|
if err != nil { |
|
|
|
return []byte(""), err |
|
|
|
} |
|
|
|
|
|
|
|
defer resp.Body.Close() |
|
|
|
body, err := ioutil.ReadAll(resp.Body) |
|
|
|
if err != nil { |
|
|
|
return []byte(""), err |
|
|
|
} |
|
|
|
|
|
|
|
return body, nil |
|
|
|
} |
|
|
|
|
|
|
|
func SetSignsm3(data map[string]interface{}) string { |
|
|
|
build_str := HttpBuildjson(data, false) |
|
|
|
h := sm3.New() |
|
|
|
h.Write([]byte(build_str)) |
|
|
|
sum := h.Sum(nil) |
|
|
|
sign := hex.EncodeToString(sum) |
|
|
|
return sign |
|
|
|
} |
|
|
|
|
|
|
|
func CashierHeaderInfoCompany(appid, secret, sign, private_key string) map[string]string { |
|
|
|
if appid == "" || secret == "" || sign == "" || private_key == "" { |
|
|
|
return map[string]string{} |
|
|
|
} |
|
|
|
|
|
|
|
headerData := map[string]string{} |
|
|
|
|
|
|
|
headerData["appid"] = appid |
|
|
|
headerData["sign"] = sign |
|
|
|
headerData["secret"] = secret |
|
|
|
headerData["timestamp"] = ToStr(time.Now().Unix()) |
|
|
|
headerData["apisign"] = SetSignhex(headerData, private_key) |
|
|
|
headerData["verify"] = "SM3withSM2" |
|
|
|
delete(headerData, "secret") |
|
|
|
return headerData |
|
|
|
} |
|
|
|
|
|
|
|
// 生成签名sign
|
|
|
|
func SetSignhex(data map[string]string, privateKey string) string { |
|
|
|
build_str := CmbHttpBuildQuery(MapStringToInterface(data), false) |
|
|
|
priv := new(sm2.PrivateKey) |
|
|
|
priv.Curve = sm2.GetSm2P256V1() |
|
|
|
dBytes, _ := hex.DecodeString(privateKey) |
|
|
|
priv.D = new(big.Int).SetBytes(dBytes) |
|
|
|
sign, _ := sm2.Sign(priv, []byte("1234567812345678"), []byte(build_str)) |
|
|
|
sign = SM2Asn1ToRaw(sign) |
|
|
|
return hex.EncodeToString(sign) |
|
|
|
} |
|
|
|
func SM2Asn1ToRaw(data []byte) []byte { |
|
|
|
i := 3 |
|
|
|
ret := []byte{} |
|
|
|
if data[i] == 32 { |
|
|
|
i = i + 1 |
|
|
|
} else if data[i] == 33 { |
|
|
|
i = i + 2 |
|
|
|
} |
|
|
|
for k := 0; k < 32; k++ { |
|
|
|
ret = append(ret, data[i+k]) |
|
|
|
} |
|
|
|
i = i + 32 |
|
|
|
i = i + 1 |
|
|
|
if data[i] == 32 { |
|
|
|
i = i + 1 |
|
|
|
} else if data[i] == 33 { |
|
|
|
i = i + 2 |
|
|
|
} |
|
|
|
for k := 0; k < 32; k++ { |
|
|
|
ret = append(ret, data[i+k]) |
|
|
|
} |
|
|
|
return ret |
|
|
|
} |
|
|
|
|
|
|
|
// 字符串排序拼接
|
|
|
|
func HttpBuildjson(data map[string]interface{}, filter_sign bool) string { |
|
|
|
keySlice := []string{} |
|
|
|
res := map[string]interface{}{} |
|
|
|
// 剔除sign字段
|
|
|
|
for k, _ := range data { |
|
|
|
if filter_sign && k == "sign" { |
|
|
|
continue |
|
|
|
} |
|
|
|
keySlice = append(keySlice, k) |
|
|
|
} |
|
|
|
// 排序字符串
|
|
|
|
sort.Strings(keySlice) |
|
|
|
for _, value := range keySlice { |
|
|
|
if value != "" && data[value] != "" { |
|
|
|
res[value] = data[value] |
|
|
|
} |
|
|
|
} |
|
|
|
ss, _ := json.Marshal(res) |
|
|
|
log.Println("拼接后的数据: ", string(ss)) |
|
|
|
return string(ss) |
|
|
|
} |
|
|
|
|
|
|
|
// body参数处理
|
|
|
|
func FormatBodyDataNoList(body map[string]interface{}) map[string]interface{} { |
|
|
|
data := map[string]interface{}{} |
|
|
|
|
|
|
|
if len(body) > 0 { |
|
|
|
for k, v := range body { |
|
|
|
typeOfA := reflect.TypeOf(v) |
|
|
|
|
|
|
|
if typeOfA.Kind().String() == "map" || typeOfA.Kind().String() == "slice" { |
|
|
|
continue |
|
|
|
} else { |
|
|
|
if typeOfA.Kind().String() == "string" { |
|
|
|
if ToStr(v) != "" { |
|
|
|
data[k] = v |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return data |
|
|
|
} |
|
|
|
|
|
|
|
// 聚合支付异步回调验签
|
|
|
|
func JhNotifyCheckSign(sign, public_key string, data map[string]string) bool { |
|
|
|
build_sort_str := CmbHttpBuildQuery(MapStringToInterface(data), true) |
|
|
|
pub_x := "" |
|
|
|
pub_y := "" |
|
|
|
// 私钥截取
|
|
|
|
if len(public_key) == 128 { |
|
|
|
pub_x = public_key[:64] |
|
|
|
pub_y = public_key[64:] |
|
|
|
} else if len(public_key) == 130 && (public_key[:2] == "04") { |
|
|
|
public_key = public_key[2:] |
|
|
|
pub_x = public_key[:64] |
|
|
|
pub_y = public_key[64:] |
|
|
|
} else { |
|
|
|
log.Println("异步验签公钥出错", public_key) |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
|
sign_b64, _ := base64.StdEncoding.DecodeString(sign) |
|
|
|
pub := new(sm2.PublicKey) |
|
|
|
pub.Curve = sm2.GetSm2P256V1() |
|
|
|
xBytes, _ := hex.DecodeString(pub_x) |
|
|
|
yBytes, _ := hex.DecodeString(pub_y) |
|
|
|
pub.X = new(big.Int).SetBytes(xBytes) |
|
|
|
pub.Y = new(big.Int).SetBytes(yBytes) |
|
|
|
result := sm2.Verify(pub, []byte("1234567812345678"), []byte(build_sort_str), sign_b64) |
|
|
|
|
|
|
|
if !result { |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
|
return true |
|
|
|
} |