|
@@ -5,7 +5,6 @@ import (
|
|
|
"crypto"
|
|
"crypto"
|
|
|
"crypto/hmac"
|
|
"crypto/hmac"
|
|
|
"crypto/md5"
|
|
"crypto/md5"
|
|
|
- "crypto/rand"
|
|
|
|
|
"crypto/rsa"
|
|
"crypto/rsa"
|
|
|
"crypto/sha1"
|
|
"crypto/sha1"
|
|
|
"crypto/x509"
|
|
"crypto/x509"
|
|
@@ -17,6 +16,7 @@ import (
|
|
|
"encoding/xml"
|
|
"encoding/xml"
|
|
|
"fmt"
|
|
"fmt"
|
|
|
"io"
|
|
"io"
|
|
|
|
|
+ "math/big"
|
|
|
"net/http"
|
|
"net/http"
|
|
|
"net/url"
|
|
"net/url"
|
|
|
"rocommon/service"
|
|
"rocommon/service"
|
|
@@ -426,15 +426,17 @@ func WebPayHwXiaoQiNotify(c *gin.Context) {
|
|
|
|
|
|
|
|
c.String(http.StatusOK, "success")
|
|
c.String(http.StatusOK, "success")
|
|
|
}
|
|
}
|
|
|
-func DecryptDataToMap(encrypDataBase64 string, privateKeyStr string) (map[string]string, error) {
|
|
|
|
|
|
|
+
|
|
|
|
|
+// 使用公钥解密(对应 PHP 的 openssl_public_decrypt)
|
|
|
|
|
+func DecryptDataToMap(encrypDataBase64 string, publicKeyStr string) (map[string]string, error) {
|
|
|
// 1. Base64 解码得到 raw_encryp_data
|
|
// 1. Base64 解码得到 raw_encryp_data
|
|
|
rawEncrypData, err := base64.StdEncoding.DecodeString(encrypDataBase64)
|
|
rawEncrypData, err := base64.StdEncoding.DecodeString(encrypDataBase64)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
return nil, fmt.Errorf("base64解码失败: %v", err)
|
|
return nil, fmt.Errorf("base64解码失败: %v", err)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 2. 使用 RSA 私钥解密
|
|
|
|
|
- decryptedData, err := rsaPrivateDecrypt(rawEncrypData, privateKeyStr)
|
|
|
|
|
|
|
+ // 2. 使用 RSA 公钥解密
|
|
|
|
|
+ decryptedData, err := rsaPublicDecrypt(rawEncrypData, publicKeyStr)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
return nil, fmt.Errorf("RSA解密失败: %v", err)
|
|
return nil, fmt.Errorf("RSA解密失败: %v", err)
|
|
|
}
|
|
}
|
|
@@ -443,83 +445,54 @@ func DecryptDataToMap(encrypDataBase64 string, privateKeyStr string) (map[string
|
|
|
return parseQueryStringToMap(string(decryptedData)), nil
|
|
return parseQueryStringToMap(string(decryptedData)), nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// rsaPrivateDecrypt RSA私钥解密
|
|
|
|
|
-func rsaPrivateDecrypt(ciphertext []byte, privateKeyStr string) ([]byte, error) {
|
|
|
|
|
- // 解析私钥
|
|
|
|
|
- privateKey, err := parsePrivateKey(privateKeyStr)
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- return nil, err
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // RSA 私钥解密(PKCS1v15 填充)
|
|
|
|
|
- plaintext, err := rsa.DecryptPKCS1v15(rand.Reader, privateKey, ciphertext)
|
|
|
|
|
|
|
+func rsaPublicDecrypt(ciphertext []byte, publicKeyStr string) ([]byte, error) {
|
|
|
|
|
+ // 解析公钥
|
|
|
|
|
+ publicKey, err := parsePublicKey(publicKeyStr)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
- return nil, fmt.Errorf("解密失败: %v", err)
|
|
|
|
|
|
|
+ return nil, fmt.Errorf("解析公钥失败: %v", err)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- return plaintext, nil
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// parsePrivateKey 解析 PEM 格式的私钥
|
|
|
|
|
-func parsePrivateKey(privateKeyStr string) (*rsa.PrivateKey, error) {
|
|
|
|
|
- // 去除空白字符
|
|
|
|
|
- privateKeyStr = strings.TrimSpace(privateKeyStr)
|
|
|
|
|
-
|
|
|
|
|
- // 确保是 PEM 格式
|
|
|
|
|
- if !strings.Contains(privateKeyStr, "-----BEGIN") {
|
|
|
|
|
- privateKeyStr = "-----BEGIN RSA PRIVATE KEY-----\n" +
|
|
|
|
|
- privateKeyStr +
|
|
|
|
|
- "\n-----END RSA PRIVATE KEY-----"
|
|
|
|
|
|
|
+ // 创建一个假的私钥对象,只填充公钥部分
|
|
|
|
|
+ fakePrivateKey := &rsa.PrivateKey{
|
|
|
|
|
+ PublicKey: *publicKey,
|
|
|
|
|
+ D: new(big.Int).SetInt64(0), // 占位符
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 解码 PEM
|
|
|
|
|
- block, _ := pem.Decode([]byte(privateKeyStr))
|
|
|
|
|
- if block == nil {
|
|
|
|
|
- return nil, fmt.Errorf("PEM解码失败")
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 解析私钥(支持 PKCS1 和 PKCS8 格式)
|
|
|
|
|
- privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
|
|
|
|
|
|
+ // 使用私钥解密(实际会使用公钥)
|
|
|
|
|
+ // 注意:这个方法可能在某些 Go 版本中不工作
|
|
|
|
|
+ plaintext, err := rsa.DecryptPKCS1v15(nil, fakePrivateKey, ciphertext)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
- // 尝试 PKCS8 格式
|
|
|
|
|
- key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- return nil, fmt.Errorf("解析私钥失败: %v", err)
|
|
|
|
|
- }
|
|
|
|
|
- var ok bool
|
|
|
|
|
- privateKey, ok = key.(*rsa.PrivateKey)
|
|
|
|
|
- if !ok {
|
|
|
|
|
- return nil, fmt.Errorf("不是RSA私钥")
|
|
|
|
|
- }
|
|
|
|
|
- return privateKey, nil
|
|
|
|
|
|
|
+ return nil, fmt.Errorf("解密失败: %v", err)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- return privateKey, nil
|
|
|
|
|
|
|
+ return plaintext, nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// parseQueryStringToMap 解析查询字符串为 map
|
|
|
|
|
|
|
+// 解析查询字符串为 map
|
|
|
func parseQueryStringToMap(queryStr string) map[string]string {
|
|
func parseQueryStringToMap(queryStr string) map[string]string {
|
|
|
- params := make(map[string]string)
|
|
|
|
|
-
|
|
|
|
|
- if queryStr == "" {
|
|
|
|
|
- return params
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ result := make(map[string]string)
|
|
|
|
|
|
|
|
|
|
+ // 按 & 分割
|
|
|
pairs := strings.Split(queryStr, "&")
|
|
pairs := strings.Split(queryStr, "&")
|
|
|
for _, pair := range pairs {
|
|
for _, pair := range pairs {
|
|
|
if pair == "" {
|
|
if pair == "" {
|
|
|
continue
|
|
continue
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+ // 按 = 分割
|
|
|
kv := strings.SplitN(pair, "=", 2)
|
|
kv := strings.SplitN(pair, "=", 2)
|
|
|
if len(kv) == 2 {
|
|
if len(kv) == 2 {
|
|
|
- params[kv[0]] = kv[1]
|
|
|
|
|
|
|
+ // URL decode 值(如果需要)
|
|
|
|
|
+ value, err := url.QueryUnescape(kv[1])
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ value = kv[1]
|
|
|
|
|
+ }
|
|
|
|
|
+ result[kv[0]] = value
|
|
|
} else if len(kv) == 1 {
|
|
} else if len(kv) == 1 {
|
|
|
- params[kv[0]] = ""
|
|
|
|
|
|
|
+ result[kv[0]] = ""
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- return params
|
|
|
|
|
|
|
+ return result
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func VerifySignature(params map[string]string, publicKeyStr string) (bool, error) {
|
|
func VerifySignature(params map[string]string, publicKeyStr string) (bool, error) {
|