package core import ( "context" "crypto/aes" "crypto/cipher" "encoding/base32" "encoding/base64" "encoding/json" "fmt" g "proxy-server/gateway/globals" "time" ) type SecuredReq struct { Content string `json:"content"` Nonce string `json:"nonce"` Timestamp int64 `json:"timestamp"` } func Decrypt[T any](req *SecuredReq, secretStr string) (resp *T, err error) { var encoding = base32.StdEncoding.WithPadding(base32.NoPadding) secret, err := encoding.DecodeString(secretStr) if err != nil { return nil, fmt.Errorf("解码密钥失败: %w", err) } // 解密请求 block, err := aes.NewCipher(secret) if err != nil { return nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } nonce, err := encoding.DecodeString(req.Nonce) if err != nil { return nil, err } content, err := base64.StdEncoding.DecodeString(req.Content) if err != nil { return nil, err } var aad = []byte(fmt.Sprintf("%s:%d", req.Nonce, req.Timestamp)) bytes, err := gcm.Open(nil, nonce, content, aad) if err != nil { return nil, err } // 检查时间与 nonce 是否匹配 var duration = time.Now().UnixMilli() - req.Timestamp if duration > 1000*60*5 { // 5分钟 return nil, fmt.Errorf("请求超时,当前时间:%d,接收时间:%d", time.Now().UnixMilli(), req.Timestamp) } result, err := g.Redis.Exists(context.Background(), req.Nonce).Result() if err != nil { return nil, err } if result > 0 { return nil, fmt.Errorf("请求已被使用,nonce:%s", req.Nonce) } // 将 nonce 存入 redis,设置过期时间为 5 分钟 err = g.Redis.Set(context.Background(), req.Nonce, 1, time.Minute*5).Err() if err != nil { return nil, err } // 返回解密后的数据 err = json.Unmarshal(bytes, &resp) if err != nil { return nil, err } return resp, nil }