Files
tyapi-server/internal/infrastructure/external/yuyuecha/crypto.go
2026-07-25 14:18:14 +08:00

85 lines
2.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package yuyuecha
import (
"crypto/hmac"
"crypto/md5"
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"fmt"
"strconv"
"strings"
"time"
"unicode"
)
// HashIDCard 将身份证号转为上游要求的身份摘要。
// 规则:已是 32 位 MD5 / 64 位 SHA-256 十六进制则原样小写返回;否则对规范化身份证号做 MD5。
func HashIDCard(idCard string) string {
id := strings.TrimSpace(idCard)
if isHexDigest(id, 32) || isHexDigest(id, 64) {
return strings.ToLower(id)
}
// 末位校验码 X 统一大写后再摘要,与授权侧常见落库一致
sum := md5.Sum([]byte(strings.ToUpper(id)))
return hex.EncodeToString(sum[:])
}
func isHexDigest(s string, length int) bool {
if len(s) != length {
return false
}
for _, r := range s {
if !unicode.Is(unicode.ASCII_Hex_Digit, r) {
return false
}
}
return true
}
// SignHeaders 按 OpenAPI 规范生成签名请求头。
// nonce 传入本地请求流水 ID与日志 request_id 一致),便于上下游按同一 ID 排查;为空时回退随机生成。
// canonical:
//
// clientId={id}\ntimestamp={ms}\nnonce={nonce}\nmethod={METHOD}\npath={path}\nbodySha256={sha256}
func SignHeaders(clientID, clientSecret, method, path string, body []byte, nonce string) (map[string]string, error) {
timestamp := strconv.FormatInt(time.Now().UnixMilli(), 10)
nonce = strings.TrimSpace(nonce)
if nonce == "" {
var err error
nonce, err = randomNonce(16)
if err != nil {
return nil, fmt.Errorf("生成 nonce 失败: %w", err)
}
}
sum := sha256.Sum256(body)
bodySHA256 := hex.EncodeToString(sum[:])
canonical := "clientId=" + clientID +
"\ntimestamp=" + timestamp +
"\nnonce=" + nonce +
"\nmethod=" + method +
"\npath=" + path +
"\nbodySha256=" + bodySHA256
mac := hmac.New(sha256.New, []byte(clientSecret))
mac.Write([]byte(canonical))
signature := hex.EncodeToString(mac.Sum(nil))
return map[string]string{
"clientId": clientID,
"timestamp": timestamp,
"nonce": nonce,
"signature": signature,
}, nil
}
func randomNonce(nBytes int) (string, error) {
buf := make([]byte, nBytes)
if _, err := rand.Read(buf); err != nil {
return "", err
}
return hex.EncodeToString(buf), nil
}