广告平台(站长使用)
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

201 lines
6.5 KiB

  1. package wechat
  2. import (
  3. "bytes"
  4. "encoding/base64"
  5. "encoding/binary"
  6. "encoding/xml"
  7. "errors"
  8. "fmt"
  9. )
  10. type msgCrypt struct {
  11. token string
  12. aesKey string
  13. appid string
  14. }
  15. // EventEncryptRequest 微信事件推送结构体
  16. type EventEncryptRequest struct {
  17. XMLName xml.Name `xml:"xml"`
  18. Encrypt string `xml:"Encrypt"`
  19. Appid string `xml:"Appid"`
  20. }
  21. // MessageEncryptRequest 微信消息加密结构体
  22. type MessageEncryptRequest struct {
  23. XMLName xml.Name `xml:"xml"`
  24. Encrypt string `xml:"Encrypt"`
  25. MsgSignature string `xml:"MsgSignature"`
  26. TimeStamp string `xml:"TimeStamp"`
  27. Nonce string `xml:"Nonce"`
  28. }
  29. // NewWechatMsgCrypt 实例化微信加解密
  30. func NewWechatMsgCrypt(token string, aesKey string, appid string) *msgCrypt {
  31. instance := new(msgCrypt)
  32. instance.token = token
  33. instance.aesKey = aesKey
  34. instance.appid = appid
  35. return instance
  36. }
  37. // WechatEventDecrypt 微信事件推送解密
  38. func (w *msgCrypt) WechatEventDecrypt(eventRequest EventEncryptRequest, msgSignature string, timestamp, nonce string) EventMessageBody {
  39. errCode, data := w.decryptMsg(msgSignature, timestamp, nonce, eventRequest.Encrypt)
  40. if errCode != SuccessCode {
  41. panic(fmt.Sprintf("消息解密失败,code:%d", errCode))
  42. }
  43. message := EventMessageBody{}
  44. _, err := FormatMessage(data, &message)
  45. if err != nil {
  46. panic(fmt.Sprintf("消息格式化失败,%s", err.Error()))
  47. }
  48. return message
  49. }
  50. // WechatMessageDecrypt 微信消息解密
  51. func (w *msgCrypt) WechatMessageDecrypt(messageEncryptRequest MessageEncryptRequest) interface{} {
  52. errCode, data := w.decryptMsg(messageEncryptRequest.MsgSignature, messageEncryptRequest.TimeStamp, messageEncryptRequest.Nonce, messageEncryptRequest.Encrypt)
  53. if errCode != SuccessCode {
  54. panic(fmt.Sprintf("消息解密失败,code:%d", errCode))
  55. }
  56. message := MessageBodyDecrypt{}
  57. _, err := FormatMessage(data, &message)
  58. if err != nil {
  59. panic(fmt.Sprintf("消息格式化失败,%s", err.Error()))
  60. }
  61. return message
  62. }
  63. // WechatTextMessage 微信文本消息加密
  64. func (w *msgCrypt) WechatTextMessage(fromUserName string, toUserName string, content string) MessageEncryptBody {
  65. message := FormatTextMessage(fromUserName, toUserName, content)
  66. encrypted, err := w.encryptMsg(message)
  67. if err != nil {
  68. panic("消息加密失败:" + err.Error())
  69. }
  70. data := FormatEncryptData(encrypted, w.token)
  71. return data
  72. }
  73. // WechatImageMessage 微信图片消息加密
  74. func (w *msgCrypt) WechatImageMessage(fromUserName string, toUserName string, mediaId string) MessageEncryptBody {
  75. message := FormatImageMessage(fromUserName, toUserName, mediaId)
  76. encrypted, err := w.encryptMsg(message)
  77. if err != nil {
  78. panic("消息加密失败:" + err.Error())
  79. }
  80. data := FormatEncryptData(encrypted, w.token)
  81. return data
  82. }
  83. // WechatVoiceMessage 微信语音消息加密
  84. func (w *msgCrypt) WechatVoiceMessage(fromUserName string, toUserName string, mediaId string) MessageEncryptBody {
  85. message := FormatVoiceMessage(fromUserName, toUserName, mediaId)
  86. encrypted, err := w.encryptMsg(message)
  87. if err != nil {
  88. panic("消息加密失败:" + err.Error())
  89. }
  90. data := FormatEncryptData(encrypted, w.token)
  91. return data
  92. }
  93. // WechatVideoMessage 微信视频消息加密
  94. func (w *msgCrypt) WechatVideoMessage(fromUserName string, toUserName string, mediaId string, title string, description string) MessageEncryptBody {
  95. message := FormatVideoMessage(fromUserName, toUserName, mediaId, title, description)
  96. encrypted, err := w.encryptMsg(message)
  97. if err != nil {
  98. panic("消息加密失败:" + err.Error())
  99. }
  100. data := FormatEncryptData(encrypted, w.token)
  101. return data
  102. }
  103. // WechatMusicMessage 微信音乐消息加密
  104. func (w *msgCrypt) WechatMusicMessage(fromUserName string, toUserName string, thumbMediaId string, title string, description string, musicUrl string, hQMusicUrl string) MessageEncryptBody {
  105. message := FormatMusicMessage(fromUserName, toUserName, thumbMediaId, title, description, musicUrl, hQMusicUrl)
  106. encrypted, err := w.encryptMsg(message)
  107. if err != nil {
  108. panic("消息加密失败:" + err.Error())
  109. }
  110. data := FormatEncryptData(encrypted, w.token)
  111. return data
  112. }
  113. // WechatArticlesMessage 微信图文消息加密
  114. func (w *msgCrypt) WechatArticlesMessage(fromUserName string, toUserName string, items []ArticleItem) MessageEncryptBody {
  115. message := FormatArticlesMessage(fromUserName, toUserName, items)
  116. encrypted, err := w.encryptMsg(message)
  117. if err != nil {
  118. panic("消息加密失败:" + err.Error())
  119. }
  120. data := FormatEncryptData(encrypted, w.token)
  121. return data
  122. }
  123. // decryptMsg aes消息解密
  124. func (w *msgCrypt) decryptMsg(msgSignature string, timestamp, nonce string, encrypted string) (int, []byte) {
  125. //验证aes
  126. if len(w.aesKey) != 43 {
  127. return IllegalAesKey, nil
  128. }
  129. //判断签名是否一致
  130. if err := w.validSignature(msgSignature, timestamp, nonce, encrypted); err != nil {
  131. return ValidateSignatureError, nil
  132. }
  133. //解密
  134. prp := NewPrpCrypt(w.aesKey)
  135. plainText, err := prp.decrypt(encrypted)
  136. if err != nil {
  137. return DecryptAESError, nil
  138. }
  139. //验证appid是否一致(消息来源是否一致)
  140. if err := w.validMessageSource(plainText); err != nil {
  141. return ValidateAppidError, nil
  142. }
  143. return SuccessCode, plainText
  144. }
  145. // encryptMsg aes消息加密
  146. func (w *msgCrypt) encryptMsg(message []byte) (string, error) {
  147. //计算消息长度
  148. buf := new(bytes.Buffer)
  149. err := binary.Write(buf, binary.BigEndian, int32(len(message)))
  150. if err != nil {
  151. return "", err
  152. }
  153. messageLength := buf.Bytes()
  154. //生成随机字符串
  155. randBytes := []byte(makeRandomString(16))
  156. plainData := bytes.Join([][]byte{randBytes, messageLength, message, []byte(w.appid)}, nil)
  157. prp := NewPrpCrypt(w.aesKey)
  158. //消息加密
  159. encrypted, err := prp.encrypt(plainData)
  160. if err != nil {
  161. return "", err
  162. }
  163. return base64.StdEncoding.EncodeToString(encrypted), nil
  164. }
  165. // validSignature 验证签名是否一致
  166. func (w *msgCrypt) validSignature(msgSignature string, timestamp, nonce string, encrypted string) error {
  167. validSignature := GetSignature(timestamp, nonce, encrypted, w.token)
  168. if validSignature != msgSignature {
  169. return errors.New("签名不一致:valid sign error")
  170. }
  171. return nil
  172. }
  173. // validMessageSource 验证消息来源
  174. func (w *msgCrypt) validMessageSource(plainText []byte) error {
  175. messageLength := GetMessageLength(plainText)
  176. //获取appid位置
  177. appIdStartPos := 20 + messageLength
  178. id := plainText[appIdStartPos : int(appIdStartPos)+len(w.appid)]
  179. if string(id) != w.appid {
  180. return errors.New("消息来源不一致:Appid is invalid")
  181. }
  182. return nil
  183. }