package hb import ( "crypto" "crypto/md5" "crypto/rand" "crypto/rsa" "crypto/sha1" "crypto/x509" "encoding/hex" "encoding/pem" "fmt" "strings" ) // buildSignString 按文档指定顺序拼接签名串(请求) // 参数顺序:merchantId, requestId, signType, type, version, orderId, amount func buildSignString(params map[string]string, orderedKeys []string) string { var parts []string for _, k := range orderedKeys { if v, ok := params[k]; ok { parts = append(parts, fmt.Sprintf("%s=%s", k, v)) } } return strings.Join(parts, "&") } // getRequestSignKeys 获取请求签名参数顺序 func getRequestSignKeys() []string { return []string{"merchantId", "requestId", "signType", "type", "version", "orderId", "amount"} } // getResponseSignKeys 获取响应签名参数顺序 func getResponseSignKeys() []string { return []string{"merchantId", "payNo", "returnCode", "message", "signType", "type", "version", "amount", "orderId", "status"} } // SignMD5 MD5签名 // 在待签名数据之后加上商户密钥(signKey),生成MD5摘要 func SignMD5(signStr, signKey string) string { data := signStr + signKey hash := md5.Sum([]byte(data)) return hex.EncodeToString(hash[:]) } // VerifyMD5 验证MD5签名 func VerifyMD5(signStr, signKey, hmac string) bool { return SignMD5(signStr, signKey) == hmac } // SignRSA RSA签名(配合SHA-1) // 使用商户私钥对签名串进行RSA-SHA1签名 func SignRSA(signStr string, privateKeyPEM string) (string, error) { block, _ := pem.Decode([]byte(privateKeyPEM)) if block == nil { return "", fmt.Errorf("failed to decode PEM private key") } var privateKey *rsa.PrivateKey // 尝试PKCS8格式 key, err := x509.ParsePKCS8PrivateKey(block.Bytes) if err == nil { var ok bool privateKey, ok = key.(*rsa.PrivateKey) if !ok { return "", fmt.Errorf("not a RSA private key") } } else { // 尝试PKCS1格式 privateKey, err = x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { return "", fmt.Errorf("failed to parse private key (PKCS1/PKCS8): %v", err) } } // 计算SHA-1哈希 hash := sha1.Sum([]byte(signStr)) // RSA签名 signature, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA1, hash[:]) if err != nil { return "", fmt.Errorf("RSA sign failed: %v", err) } return hex.EncodeToString(signature), nil } // VerifyRSA 验证RSA签名 // 使用手机支付公钥验证响应签名 func VerifyRSA(signStr, signatureHex, publicKeyPEM string) error { block, _ := pem.Decode([]byte(publicKeyPEM)) if block == nil { return fmt.Errorf("failed to decode PEM public key") } // 尝试解析公钥 pub, err := x509.ParsePKIXPublicKey(block.Bytes) if err != nil { // 尝试解析证书 cert, err := x509.ParseCertificate(block.Bytes) if err != nil { return fmt.Errorf("failed to parse public key: %v", err) } pub = cert.PublicKey } rsaPub, ok := pub.(*rsa.PublicKey) if !ok { return fmt.Errorf("not a RSA public key") } // 解码签名 signature, err := hex.DecodeString(signatureHex) if err != nil { return fmt.Errorf("failed to decode signature hex: %v", err) } // 计算SHA-1哈希 hash := sha1.Sum([]byte(signStr)) // 验证签名 err = rsa.VerifyPKCS1v15(rsaPub, crypto.SHA1, hash[:], signature) if err != nil { return fmt.Errorf("RSA verify failed: %v", err) } return nil } // extractCertFromPEM 从PEM格式的证书中提取公钥PEM // 有些场景下serverCert返回的是证书,需要提取公钥 func extractPublicKeyFromCert(certPEM string) (string, error) { block, _ := pem.Decode([]byte(certPEM)) if block == nil { return "", fmt.Errorf("failed to decode PEM certificate") } cert, err := x509.ParseCertificate(block.Bytes) if err != nil { return "", fmt.Errorf("failed to parse certificate: %v", err) } pubKeyBytes, err := x509.MarshalPKIXPublicKey(cert.PublicKey) if err != nil { return "", fmt.Errorf("failed to marshal public key: %v", err) } pubKeyPEM := pem.EncodeToMemory(&pem.Block{ Type: "PUBLIC KEY", Bytes: pubKeyBytes, }) return string(pubKeyPEM), nil }