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, "&") return build_str } // 生成签名sign--聚合支付 func SetSign(data map[string]interface{}, privateKey string) string { 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) 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") return headerData } // 接口验签--各客户端请求我们接口验签 func CheckSign(appid, app_secret, timeStamp, nonce, sign string, body map[string]interface{}) error { /*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 sign_str := crypter.Md5Str(str) if sign_str != sign { return errors.New("签名不正确") } 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 } 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) 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 }