package main
import "fmt"
import (
"crypto"
"crypto/md5"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"errors"
"encoding/json"
"reflect"
"encoding/hex"
)
const (
privateKey = `-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDY4HhGmw99mqAqkwjQdQg04M4Ny1RqilunCD3+DMT9eTqeLkzu68dc2AX8pFlwyL+BOE2knz8sWuY287zrk0+wC+kNmq/agDMSHW/HsQOEq5LQ00sca1cmcc3BMb82yAUMJDxxt2cnknWoXziGtEIu+AMU3X/aULoztd67sq5hPvElEzKc3O8uq6k3UoG5LXDIKcNnkK7z/aoS673ie9/zj9Rjl8QTXh77WuzOfLeKbcR9whcokqnyLfM9vnskXdwTZrZzrDTx0aZ4YNZgyvlcKRqQlty6oVE2JuW6Aq2F+odN8f4Gh49hWFX7q+WNQl+ycyLsGfiT+TceGIcTMq8ZAgMBAAECggEBAKFJ1skTmmKb8w+Wh9CXqMHCihtiIuaU/PJsw8XC82FanghzgI2S1ZIrqdAo3cdt1FYibEPIlq/C7kDh5ZcA2Buhz/FpH+0MuG55a98Duw0YmDgrW0nIXmjd69oIyB7ShEZyUG11qwaX+l58akprlmjd01TaIbJXpRK95+aJTPxN9sJTaAZ91bydswO4cvPJd0aC7LO1BsEvLYOP0uyEDrOMIDUKiSTGgzwGHkqbNsSaY0UaPu+HFfwLY/GfldhuCiqXChBGZf+4ER741EiUVl3qNWOY+6x0WQuPNdXvKSrVRAIRec8gcv3snxbfrJMAry+zT93pt3ih6x+gE+5J4p0CgYEA++F6PGQ8BykOwxwwJ1UQ2PhKa3pFy5LFUA8QPU7C+4OEDiG6gChl9KAD0hMHl99DJSaRo9rfsQIv+z0DzAmgNh/gY0unMcqqeXlKXMa0sIl06cQUhMNwCYY8+YLhB/VYcKsv34CTymC24uVRX/SqO2/mHZtEKgna+h1O3Yht6a8CgYEA3Gxx8HsVX5OC4Uw7WJaV8MCMyLhoKGQNMu11ie9mHhiZPDSv7idn9XuOma+S4zFS/lmSODmWWVnf5KhutxEukrqrwXeMzYuvVhjHIpkPPxbDJz7iiodfY4lGeBfSTWxg296SIiI/oAM7j+eucYSAk/0Jfvo8FLCMYkGHUhjZTbcCgYBmLdACk77uQK+mYtb9/bo56m92LkIGFWJJ2fKCjGL42R9HBFO+DaVemVMzc1jPOVjpxz2ptO6txe9lAhl6OiVuD3xdi6Elx8tkP9n0zP8b5ocxFcQlH4thsb0mkvtq2RKpkih3iJdrr9RBMznRrVUpi3lUZVo/m4PjluQZZnEALQKBgBvxU3Bc6hS3qnvNIijUziU7A53eYrXcGSA/ogreYl+mVqafNz5FmJQyGZ25+DD867x6tmKSSlEBZ7Sg9YgXkYPgTi20bhEQiCWt9nCYXqpsxEiRXD6bcqg3mstWmb5e4th8mqHhHZe3UTGo+SBC39ni1fVW247z4pgCHpl1tPZ5AoGBAI5q0wJhcuonoR3hChrltshRT41uM+U6MTxBpUOkicbg8WvIvyRrERppG7EqN+kEG4nYSxQzQhe7N5VaE7kanQE4cl59qkqPCptjoBcxiuIhLfrkbARCknzqFLUzqCyoi4kWxYWiLaCK5uO6VuQfY+siP45jNCHm+v4SbjjY/ecN
-----END PRIVATE KEY-----`
)
const (
payerMaxPublicKey = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApeo7M6vybSYxCN3eS4T4l9dtyVkfVtIbxeOljYL1lqaQr3vBbmS9sgsBM/Lt0mZZ4M2EF8Fq5KXlYwLTrWsXstjBzAcIBYThBK4DfnpEhBcXVCn7GRYZ2cQxLaSgJsbHYMVVX0X/5Tb4qZaGZuNiXsNi5D74nz0E/8EkUWesGWtw6tmtnJBzhGxylgX3Zm42GUhuNdWiC/nKthW0vw/S+pnOk1eZqzZrvKlnjpGdqPZTf0R0bEMJdKPAXufPZN1wsphWWw1jKmyWCgDKthljXcKzydu5yR7TrItGz2KlIJem/5P2+428F9Lt3S+cM6wNlHpF+6vyXbJCrVSJtbMSmwIDAQAB
-----END PUBLIC KEY-----`
)
func MD5(data []byte) string {
has := md5.Sum(data)
return fmt.Sprintf("%x", has)
}
func getParams(req interface{}) (map[string]string, error) {
typeOf := reflect.TypeOf(req)
if typeOf.Kind() != reflect.Ptr {
return nil, errors.New("req must be a pointer")
}
val := reflect.ValueOf(req).Elem()
typ := val.Type()
if val.Kind() != reflect.Struct {
return nil, errors.New("val must be a struct")
}
params := make(map[string]string)
for i := 0; i < val.NumField(); i++ {
if !val.Field(i).CanInterface() {
continue
}
typFd := typ.Field(i)
valFd := val.Field(i)
ftyp := typFd.Type.Kind()
if ftyp == reflect.Ptr {
if valFd.IsNil() {
continue
}
valFd = valFd.Elem()
}
params[typFd.Tag.Get("json")] = func() string {
if ftyp != reflect.String {
return fmt.Sprintf("%v", valFd)
}
return valFd.String()
}()
}
fmt.Println("getParams", params)
return params, nil
}
func ParsePrivateKey(privateKey string) (*rsa.PrivateKey, error) {
block, _ := pem.Decode([]byte(privateKey))
if block == nil {
return nil, errors.New("私钥信息错误!")
}
priKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
rsaPrivateKey, ok := priKey.(*rsa.PrivateKey)
if !ok {
return nil, fmt.Errorf("parsed key is not an RSA private key")
}
return rsaPrivateKey, nil
}
func GenRSASign(params map[string]string) string {
priKey, err := ParsePrivateKey(privateKey)
if err != nil {
fmt.Println("ParsePrivateKey err :", err)
return ""
}
b, _ := json.Marshal(params)
fmt.Println("=======00", string(b))
hashed := sha256.Sum256(b)
signature, err := rsa.SignPKCS1v15(rand.Reader, priKey, crypto.SHA256, hashed[:])
if err != nil {
fmt.Println("err Failed to sign the request body:", err)
return ""
}
fmt.Println("=======", base64.StdEncoding.EncodeToString(signature))
return base64.StdEncoding.EncodeToString(signature)
}
func RSAVerify(src []byte, sign []byte) (pass bool, err error) {
block, _ := pem.Decode([]byte(payerMaxPublicKey))
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
fmt.Printf("Failed to parse RSA public key: %s\n", err)
return
}
rsaPub, _ := pub.(*rsa.PublicKey)
hashed := sha256.Sum256(src)
data, _ := base64.StdEncoding.DecodeString(string(sign))
hexSig := hex.EncodeToString(data)
fmt.Printf("base decoder: %v, %v\n", string(sign), hexSig)
err = rsa.VerifyPKCS1v15(rsaPub, crypto.SHA256, hashed[:], data)
if err != nil {
fmt.Println("Verify sig error, reason: ", err)
return false, err
}
return true, nil
}
func main () {
fmt.Println("Hello world! - go.jsrun.net ")
tests := []map[string]string{
{"merchantId":"SP19529488","bizType":"CUSTOMIZE","version":"2.3","orderId":"1781390517431621299578","userId":"1324411","subject":"Android 套餐一【勿上架】","countryCode":"ID","currency":"IDR","totalAmount":"9999","frontCallBackScheme":"ukiapp://ucoinhome/payermax","reference":"1324411","showResult":"1","receipt":"1","expireTime":"1800","appId":"64d7fd9ee67149edaf1dc04dc5f0c8c6"},
}
for _, tt := range tests {
GenRSASign(tt)
}
resp := map[string]interface{}{
"data": map[string]interface{}{
"tradeNo": "T2023082406066925034261",
"orderId": "1780520453336721299574",
"status": 2,
},
"bizCode": "0000",
}
b, _ := json.Marshal(resp)
sign := "1oboiExExZpSYyKOv+TbEmgLOqqYsqMEwGQydkPgfEfFPK4VTV/6vURUqfPm/SnJ8tBy5rkxZ8R1+/ZrW5T7CVmOiKhIBw/4LPv5Xj08MmL5qPPrdg+UbnF+G7b2FEyAfFblF+CdXnn89k7r0Ma/6JEr0bIpJ4BmOmuzMEtDdhCQZ43kXD40P5Cf1MkvrSO4Au+hJtRBVRVtCCGJt1bTRA1G7BvXj7DKUaF6w3yikf7D1DYfD6vDO95Tdzy+Ge1fl/oZK48JQNii0Xouekd76UARm54q9iynSy8a4Hj1dHzyTGa7q6uooALD57ryQRA/5Dt1Rzej/tTcQyVIl0Nbiw=="
ok, _ := RSAVerify(b, []byte(sign))
fmt.Println("Verify======: ", resp, ok)
}