添加文件: hb/crypto.go
This commit is contained in:
parent
189ffc83fc
commit
6f5b142bfc
|
|
@ -0,0 +1,155 @@
|
||||||
|
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
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue