package wechat import ( "crypto/aes" "crypto/cipher" "encoding/base64" "encoding/json" "errors" "strings" ) type phonePayload struct { PhoneNumber string `json:"phoneNumber"` PurePhoneNumber string `json:"purePhoneNumber"` Watermark struct { AppID string `json:"appid"` } `json:"watermark"` } // DecryptPhone decrypts WeChat getPhoneNumber encryptedData (AES-128-CBC). func DecryptPhone(sessionKey, encryptedData, iv, expectAppID string) (string, error) { key, err := base64.StdEncoding.DecodeString(strings.TrimSpace(sessionKey)) if err != nil || len(key) != 16 { return "", errors.New("无效的 session_key") } raw, err := base64.StdEncoding.DecodeString(strings.TrimSpace(encryptedData)) if err != nil || len(raw) == 0 || len(raw)%aes.BlockSize != 0 { return "", errors.New("无效的加密数据") } ivb, err := base64.StdEncoding.DecodeString(strings.TrimSpace(iv)) if err != nil || len(ivb) != aes.BlockSize { return "", errors.New("无效的 iv") } block, err := aes.NewCipher(key) if err != nil { return "", err } plain := make([]byte, len(raw)) cipher.NewCBCDecrypter(block, ivb).CryptBlocks(plain, raw) plain, err = pkcs7Unpad(plain) if err != nil { return "", errors.New("解密失败") } var p phonePayload if err := json.Unmarshal(plain, &p); err != nil { return "", errors.New("解密失败") } if expectAppID != "" && p.Watermark.AppID != "" && p.Watermark.AppID != expectAppID { return "", errors.New("微信数据校验失败") } phone := strings.TrimSpace(p.PhoneNumber) if phone == "" { phone = strings.TrimSpace(p.PurePhoneNumber) } if phone == "" { return "", errors.New("未获取到手机号") } return phone, nil } func pkcs7Unpad(b []byte) ([]byte, error) { if len(b) == 0 { return nil, errors.New("empty") } n := int(b[len(b)-1]) if n == 0 || n > len(b) { return nil, errors.New("pad") } for i := 0; i < n; i++ { if b[len(b)-1-i] != byte(n) { return nil, errors.New("pad") } } return b[:len(b)-n], nil }