95 lines
2.6 KiB
Go
95 lines
2.6 KiB
Go
|
|
package rongxing
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"crypto"
|
|||
|
|
"crypto/md5"
|
|||
|
|
"crypto/rand"
|
|||
|
|
"crypto/rsa"
|
|||
|
|
"crypto/sha256"
|
|||
|
|
"crypto/x509"
|
|||
|
|
"encoding/base64"
|
|||
|
|
"encoding/hex"
|
|||
|
|
"encoding/pem"
|
|||
|
|
"fmt"
|
|||
|
|
"sort"
|
|||
|
|
"strings"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// MD5Upper 对明文做 MD5,返回 32 位大写十六进制(入参说明要求大写)。
|
|||
|
|
func MD5Upper(plaintext string) string {
|
|||
|
|
sum := md5.Sum([]byte(strings.TrimSpace(plaintext)))
|
|||
|
|
return strings.ToUpper(hex.EncodeToString(sum[:]))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// EncodePasswordBase64 将明文密码做 Base64 编码(登录接口要求)。
|
|||
|
|
func EncodePasswordBase64(password string) string {
|
|||
|
|
return base64.StdEncoding.EncodeToString([]byte(password))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// BuildSignContent 生成登录签名原文:过滤 sign/空值 → 按 key 升序 → key=value&...
|
|||
|
|
func BuildSignContent(params map[string]interface{}) string {
|
|||
|
|
keys := make([]string, 0, len(params))
|
|||
|
|
for k, v := range params {
|
|||
|
|
if strings.EqualFold(k, "sign") || v == nil {
|
|||
|
|
continue
|
|||
|
|
}
|
|||
|
|
keys = append(keys, k)
|
|||
|
|
}
|
|||
|
|
sort.Strings(keys)
|
|||
|
|
|
|||
|
|
parts := make([]string, 0, len(keys))
|
|||
|
|
for _, k := range keys {
|
|||
|
|
parts = append(parts, fmt.Sprintf("%s=%v", k, params[k]))
|
|||
|
|
}
|
|||
|
|
return strings.Join(parts, "&")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// SignSHA256WithRSA 使用私钥对原文做 SHA256withRSA 签名,返回 Base64。
|
|||
|
|
func SignSHA256WithRSA(content string, privateKey *rsa.PrivateKey) (string, error) {
|
|||
|
|
if privateKey == nil {
|
|||
|
|
return "", fmt.Errorf("私钥为空")
|
|||
|
|
}
|
|||
|
|
hashed := sha256.Sum256([]byte(content))
|
|||
|
|
signed, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, hashed[:])
|
|||
|
|
if err != nil {
|
|||
|
|
return "", fmt.Errorf("RSA 签名失败: %w", err)
|
|||
|
|
}
|
|||
|
|
return base64.StdEncoding.EncodeToString(signed), nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ParsePrivateKey 解析 RSA 私钥(支持 PEM / PKCS#8 / PKCS#1 原始 Base64)。
|
|||
|
|
func ParsePrivateKey(raw string) (*rsa.PrivateKey, error) {
|
|||
|
|
raw = strings.TrimSpace(raw)
|
|||
|
|
if raw == "" {
|
|||
|
|
return nil, fmt.Errorf("私钥为空")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var der []byte
|
|||
|
|
if block, _ := pem.Decode([]byte(raw)); block != nil {
|
|||
|
|
der = block.Bytes
|
|||
|
|
} else {
|
|||
|
|
normalized := strings.ReplaceAll(raw, "\n", "")
|
|||
|
|
normalized = strings.ReplaceAll(normalized, "\r", "")
|
|||
|
|
normalized = strings.ReplaceAll(normalized, " ", "")
|
|||
|
|
decoded, err := base64.StdEncoding.DecodeString(normalized)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, fmt.Errorf("私钥 Base64 解码失败: %w", err)
|
|||
|
|
}
|
|||
|
|
der = decoded
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if key, err := x509.ParsePKCS8PrivateKey(der); err == nil {
|
|||
|
|
rsaKey, ok := key.(*rsa.PrivateKey)
|
|||
|
|
if !ok {
|
|||
|
|
return nil, fmt.Errorf("私钥不是 RSA 类型")
|
|||
|
|
}
|
|||
|
|
return rsaKey, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if key, err := x509.ParsePKCS1PrivateKey(der); err == nil {
|
|||
|
|
return key, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return nil, fmt.Errorf("无法解析 RSA 私钥(需 PKCS#8 或 PKCS#1)")
|
|||
|
|
}
|