添加文件: 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