leitao666 4 days ago
parent
commit
f5beed8ead
1 changed files with 101 additions and 12 deletions
  1. 101 12
      RO_Server_Trunk-branch_0.1.39/roserver/gmweb/msg/web_paymsg.go

+ 101 - 12
RO_Server_Trunk-branch_0.1.39/roserver/gmweb/msg/web_paymsg.go

@@ -430,7 +430,7 @@ func WebPayHwXiaoQiNotify(c *gin.Context) {
 // 使用公钥解密(对应 PHP 的 openssl_public_decrypt)
 func DecryptDataToMap(encrypDataBase64 string, publicKeyStr string) (map[string]string, error) {
 	// 1. Base64 解码得到 raw_encryp_data
-	rawEncrypData, err := base64.StdEncoding.DecodeString(encrypDataBase64)
+	rawEncrypData, err := decodeBase64Compat(encrypDataBase64)
 	if err != nil {
 		return nil, fmt.Errorf("base64解码失败: %v", err)
 	}
@@ -452,20 +452,109 @@ func rsaPublicDecrypt(ciphertext []byte, publicKeyStr string) ([]byte, error) {
 		return nil, fmt.Errorf("解析公钥失败: %v", err)
 	}
 
-	// 创建一个假的私钥对象,只填充公钥部分
-	fakePrivateKey := &rsa.PrivateKey{
-		PublicKey: *publicKey,
-		D:         new(big.Int).SetInt64(0), // 占位符
+	keySize := (publicKey.N.BitLen() + 7) / 8
+	if keySize == 0 {
+		return nil, fmt.Errorf("无效RSA公钥")
 	}
 
-	// 使用私钥解密(实际会使用公钥)
-	// 注意:这个方法可能在某些 Go 版本中不工作
-	plaintext, err := rsa.DecryptPKCS1v15(nil, fakePrivateKey, ciphertext)
-	if err != nil {
-		return nil, fmt.Errorf("解密失败: %v", err)
+	if len(ciphertext)%keySize != 0 {
+		return nil, fmt.Errorf("密文长度非法: len=%d keySize=%d", len(ciphertext), keySize)
+	}
+
+	// 兼容长消息分段密文(每段一个 RSA block)。
+	plainData := make([]byte, 0, len(ciphertext))
+	e := big.NewInt(int64(publicKey.E))
+	for offset := 0; offset < len(ciphertext); offset += keySize {
+		block := ciphertext[offset : offset+keySize]
+		c := new(big.Int).SetBytes(block)
+		if c.Cmp(publicKey.N) > 0 {
+			return nil, fmt.Errorf("密文块超出模数范围")
+		}
+
+		m := new(big.Int).Exp(c, e, publicKey.N)
+		em := leftPadToSize(m.Bytes(), keySize)
+		plainBlock, err := unpadPKCS1v15ForPublicDecrypt(em)
+		if err != nil {
+			return nil, fmt.Errorf("块解密失败: %v", err)
+		}
+		plainData = append(plainData, plainBlock...)
+	}
+
+	return plainData, nil
+}
+
+func decodeBase64Compat(raw string) ([]byte, error) {
+	// form-urlencoded 场景下,+ 可能被自动转为空格。
+	s := strings.TrimSpace(strings.ReplaceAll(raw, " ", "+"))
+	if s == "" {
+		return nil, fmt.Errorf("空字符串")
+	}
+
+	encodings := []*base64.Encoding{
+		base64.StdEncoding,
+		base64.RawStdEncoding,
+		base64.URLEncoding,
+		base64.RawURLEncoding,
+	}
+
+	var lastErr error
+	for _, enc := range encodings {
+		data, err := enc.DecodeString(s)
+		if err == nil {
+			return data, nil
+		}
+		lastErr = err
+	}
+	return nil, lastErr
+}
+
+func leftPadToSize(src []byte, size int) []byte {
+	if len(src) >= size {
+		return src
+	}
+	dst := make([]byte, size)
+	copy(dst[size-len(src):], src)
+	return dst
+}
+
+// unpadPKCS1v15ForPublicDecrypt 兼容 openssl_public_decrypt 的 PKCS#1 v1.5 去填充。
+func unpadPKCS1v15ForPublicDecrypt(em []byte) ([]byte, error) {
+	if len(em) < 11 {
+		return nil, fmt.Errorf("EM 长度过短")
+	}
+	if em[0] != 0x00 {
+		return nil, fmt.Errorf("EM 格式错误: 缺少前导0x00")
 	}
 
-	return plaintext, nil
+	switch em[1] {
+	case 0x01:
+		i := 2
+		for i < len(em) && em[i] == 0xFF {
+			i++
+		}
+		if i < 10 {
+			return nil, fmt.Errorf("PKCS#1 type1 填充长度不足")
+		}
+		if i >= len(em) || em[i] != 0x00 {
+			return nil, fmt.Errorf("PKCS#1 type1 分隔符缺失")
+		}
+		return em[i+1:], nil
+	case 0x02:
+		// 某些渠道可能走普通公钥加密块,这里也做兼容。
+		i := 2
+		for i < len(em) && em[i] != 0x00 {
+			i++
+		}
+		if i < 10 {
+			return nil, fmt.Errorf("PKCS#1 type2 填充长度不足")
+		}
+		if i >= len(em) || em[i] != 0x00 {
+			return nil, fmt.Errorf("PKCS#1 type2 分隔符缺失")
+		}
+		return em[i+1:], nil
+	default:
+		return nil, fmt.Errorf("不支持的填充类型: 0x%02x", em[1])
+	}
 }
 
 // 解析查询字符串为 map
@@ -503,7 +592,7 @@ func VerifySignature(params map[string]string, publicKeyStr string) (bool, error
 	}
 
 	// base64_decode 得到 raw_sign_data
-	rawSignData, err := base64.StdEncoding.DecodeString(signDataBase64)
+	rawSignData, err := decodeBase64Compat(signDataBase64)
 	if err != nil {
 		return false, fmt.Errorf("base64解码失败: %v", err)
 	}