From 9d3e3e814f3600fdbd5f5bfda9a65c823dcd30c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=B0=E4=BA=AE?= Date: Thu, 10 Oct 2019 19:37:13 +0800 Subject: [PATCH] =?UTF-8?q?Add=20RSA=20=E7=AD=BE=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/route/middleware/sign/rsa/rsa.go | 120 +++++++++++++++++++++++++++ app/util/rsa.go | 78 +++++++++++++++++ rsa/private.pem | 27 ++++++ rsa/public.pem | 9 ++ 4 files changed, 234 insertions(+) create mode 100644 app/route/middleware/sign/rsa/rsa.go create mode 100644 app/util/rsa.go create mode 100644 rsa/private.pem create mode 100644 rsa/public.pem diff --git a/app/route/middleware/sign/rsa/rsa.go b/app/route/middleware/sign/rsa/rsa.go new file mode 100644 index 00000000..841db166 --- /dev/null +++ b/app/route/middleware/sign/rsa/rsa.go @@ -0,0 +1,120 @@ +package sign_rsa + +import ( + "errors" + "fmt" + "github.com/gin-gonic/gin" + "go-gin-api/app/config" + "go-gin-api/app/util" + "net/url" + "sort" + "strconv" + "strings" + "time" +) + +var AppSecret string + +// RSA 非对称加密 +func SetUp() gin.HandlerFunc { + + return func(c *gin.Context) { + utilGin := util.Gin{Ctx: c} + + sign, err := verifySign(c) + + if sign != nil { + utilGin.Response(-1, "Debug Sign", sign) + c.Abort() + return + } + + if err != nil { + utilGin.Response(-1, err.Error(), sign) + c.Abort() + return + } + + c.Next() + } +} + +// 验证签名 +func verifySign(c *gin.Context) (map[string]string, error) { + _ = c.Request.ParseForm() + req := c.Request.Form + debug := strings.Join(c.Request.Form["debug"], "") + ak := strings.Join(c.Request.Form["ak"], "") + sn := strings.Join(c.Request.Form["sn"], "") + ts := strings.Join(c.Request.Form["ts"], "") + + // 验证来源 + value, ok := config.ApiAuthConfig[ak] + if ok { + AppSecret = value["rsa"] + } else { + return nil, errors.New("ak Error") + } + + if debug == "1" { + currentUnix := util.GetCurrentUnix() + req.Set("ts", strconv.FormatInt(currentUnix, 10)) + + sn, err := createSign(req) + if err != nil { + return nil, errors.New("sn Exception") + } + + res := map[string]string{ + "ts": strconv.FormatInt(currentUnix, 10), + "sn": sn, + } + return res, nil + } + + // 验证过期时间 + timestamp := time.Now().Unix() + exp, _ := strconv.ParseInt(config.AppSignExpiry, 10, 64) + tsInt, _ := strconv.ParseInt(ts, 10, 64) + if tsInt > timestamp || timestamp - tsInt >= exp { + return nil, errors.New("ts Error") + } + + // 验证签名 + if sn == "" { + return nil, errors.New("sn Error") + } + + decryptStr, decryptErr := util.RsaPrivateDecrypt(sn, config.AppRsaPrivateFile) + if decryptErr != nil { + return nil, errors.New(decryptErr.Error()) + } + if decryptStr != createEncryptStr(req) { + return nil, errors.New("sn Error") + } + return nil, nil +} + +// 创建签名 +func createSign(params url.Values) (string, error) { + return util.RsaPublicEncrypt(createEncryptStr(params), AppSecret) +} + +func createEncryptStr(params url.Values) string { + var key []string + var str = "" + for k := range params { + if k != "sn" && k != "debug" { + key = append(key, k) + } + } + sort.Strings(key) + for i := 0; i < len(key); i++ { + if i == 0 { + str = fmt.Sprintf("%v=%v", key[i], params.Get(key[i])) + } else { + str = str + fmt.Sprintf("&%v=%v", key[i], params.Get(key[i])) + } + } + return str +} diff --git a/app/util/rsa.go b/app/util/rsa.go new file mode 100644 index 00000000..9eccafdf --- /dev/null +++ b/app/util/rsa.go @@ -0,0 +1,78 @@ +package util + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "os" +) + +// 公钥加密 +func RsaPublicEncrypt(encryptStr string, path string) (string, error) { + // 打开文件 + file, err := os.Open(path) + if err != nil { + return "", err + } + defer file.Close() + + // 读取文件内容 + info, _ := file.Stat() + buf := make([]byte,info.Size()) + file.Read(buf) + + // pem 解码 + block, _ := pem.Decode(buf) + + // x509 解码 + publicKeyInterface, err := x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + return "", err + } + + // 类型断言 + publicKey := publicKeyInterface.(*rsa.PublicKey) + + //对明文进行加密 + encryptedStr, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, []byte(encryptStr)) + if err != nil { + return "", err + } + + //返回密文 + return base64.URLEncoding.EncodeToString(encryptedStr), nil +} + +// 私钥解密 +func RsaPrivateDecrypt(decryptStr string, path string) (string, error) { + // 打开文件 + file, err := os.Open(path) + if err != nil { + return "", err + } + defer file.Close() + + // 获取文件内容 + info, _ := file.Stat() + buf := make([]byte,info.Size()) + file.Read(buf) + + // pem 解码 + block, _ := pem.Decode(buf) + + // X509 解码 + privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes) + if err != nil { + return "", err + } + decryptBytes, err := base64.URLEncoding.DecodeString(decryptStr) + + //对密文进行解密 + decrypted, _ := rsa.DecryptPKCS1v15(rand.Reader,privateKey,decryptBytes) + + //返回明文 + return string(decrypted), nil +} + diff --git a/rsa/private.pem b/rsa/private.pem new file mode 100644 index 00000000..96a1c140 --- /dev/null +++ b/rsa/private.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpgIBAAKCAQEA1O3p0JN0/RrP7eY3f81izPf16FS0WMNGCJkd+y5c6yBzUvN0 +IEeoxiIWIBhoMKH0pzlzBg0rfttojSodOgNom/UCAzAYEgdIsNee5LSN/7e0T2/Q +vsIAHINuA8gI8fGoGiSA2TEzpUo6aVXwhZT34GGRdrSJ+m4iVk/Kt95tavBNk+ND +VSeb5xAjxBchT5BjAMMlE0ffGZb0MMjjO5+e9Tn8f99M2VMqpzXHXZzv1ABmqufz +S20iWcSvnjhWcJ9hiKwO8Z30GgJyACmml+HMxLYEFN9h2MWYgxLm9Z0rLMrWwMM+ +E2rCs8tsxAD5sO9RZMJPl1C0FIsMR53ngqbzowIDAQABAoIBAQCO1RE1ItUlO6kj +Un0ENAgEqojAUqGvsT33Yo7kAZO+/cOeb0UEqk0iq5bf7L9ncBynWDg6ZPc6X3/g +wdFdKxAvHck9zjM3VL+EMP+bNyrR0K8ZYk5Kx+Q/PEK+Mp8dfRdgggAUsZaNWB+a +rVVspiMo1wo28KBl5x8NevTnJkOLqXAyB7UyLWqnOL1fb988lZvZPR7ZUYroVIZa +pyXtZcafIJeKyQ3bvWI5+eFqOe61Z4Bx1+TpfZ3fKfSDW0vhxzNqaimOa8jSXtMJ +jMeOctL4nZ0TPo/jS3I+XlaH4ZQlFLuUWGscpxwfEeBN23I8HRLkZXJsw66yvRN3 +s4bUKPXRAoGBAP/3oSZAECvfsYYzs76tnrAmR/0GxCqgguxDlWn5DowQzdWFOdHC +ZbTo/hUVoMSQnO1EKCFlnBS+wg/3TuIzUO0ewC1aeT7qHbOMDl0zKbNpS2Z9/j+U +zro+qz7XmkWolMCfmDrCrw9CtCxcMSII+ajbI8SAgFVMz9XnDt+xW9E9AoGBANT0 +4F6kCUJTEyqf2+v84tjQ2wGIF6XtZPU9JR806zeMyahQ9F6z3hY8BYb0tIy5b3uJ +VlJ9TG1qg/t59TWxIq43mYSUJHe0aJi3ilooObQtHlhPu8nwmmX47sX0PyG2hMoD +kBVxTpTDmBaDz7O9uBnlMXJN5qEygctaixpEbmZfAoGBAMBA9kEMjRjnAyeRXcgy +D6aumhNqKZz6wltCx864yjxZwsBFOJBcOpgPCAg+HmqFU9jCAIJVF05dmNT1I8Ky +WG5BUoa+FaMzpOtenstRylh/Far9pyGKW1t4BpdEyRLY9CFZvbUk1OfZagqHlD/E +DgDN16eX/MwUzWYUDg/l3tjhAoGBAKGip/ZNjVWRFpggs9z/mfK1O7WC5Wgksp9N +ZLK2CN6l9p3RrFmBLk00C4HulGfHi+15RVLhFbRqx3iFje/N3iPbwaMWikNtZIKd +tN5Pb9To9gJTqpZRD+/cLOeFRrHBBjMK1z7fPKS/fN2B+JFVq7nD827t3+J0In4F +4FT0odMDAoGBAJk3ELB/FHY8xzZ4jF1wG/a1CK681Xm6SuU5KIELDSAUNoou6OPG +mS8gU20MMPAeV2z7khyDcSxlHsUyL73eLeaakbQov9NMW7cc99XX4wnP4W7FRpmr +QbHmKuHIRFHCFv+XX8c0aK2mDZMUlzJdy4FgD/YCEZ7kZMZKyvZW/ZuV +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/rsa/public.pem b/rsa/public.pem new file mode 100644 index 00000000..80a8672d --- /dev/null +++ b/rsa/public.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1O3p0JN0/RrP7eY3f81i +zPf16FS0WMNGCJkd+y5c6yBzUvN0IEeoxiIWIBhoMKH0pzlzBg0rfttojSodOgNo +m/UCAzAYEgdIsNee5LSN/7e0T2/QvsIAHINuA8gI8fGoGiSA2TEzpUo6aVXwhZT3 +4GGRdrSJ+m4iVk/Kt95tavBNk+NDVSeb5xAjxBchT5BjAMMlE0ffGZb0MMjjO5+e +9Tn8f99M2VMqpzXHXZzv1ABmqufzS20iWcSvnjhWcJ9hiKwO8Z30GgJyACmml+HM +xLYEFN9h2MWYgxLm9Z0rLMrWwMM+E2rCs8tsxAD5sO9RZMJPl1C0FIsMR53ngqbz +owIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file