wxbizmsgcrypt.go 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. package wxbizmsgcrypt
  2. import (
  3. "bytes"
  4. "crypto/aes"
  5. "crypto/cipher"
  6. "crypto/sha1"
  7. "encoding/base64"
  8. "encoding/binary"
  9. "encoding/xml"
  10. "fmt"
  11. "math/rand"
  12. "sort"
  13. "strings"
  14. )
  15. const letterBytes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
  16. const (
  17. ValidateSignatureError int = -40001
  18. ParseXmlError int = -40002
  19. ComputeSignatureError int = -40003
  20. IllegalAesKey int = -40004
  21. ValidateCorpidError int = -40005
  22. EncryptAESError int = -40006
  23. DecryptAESError int = -40007
  24. IllegalBuffer int = -40008
  25. EncodeBase64Error int = -40009
  26. DecodeBase64Error int = -40010
  27. GenXmlError int = -40010
  28. ParseJsonError int = -40012
  29. GenJsonError int = -40013
  30. IllegalProtocolType int = -40014
  31. )
  32. type ProtocolType int
  33. const (
  34. XmlType ProtocolType = 1
  35. )
  36. type CryptError struct {
  37. ErrCode int
  38. ErrMsg string
  39. }
  40. func NewCryptError(err_code int, err_msg string) *CryptError {
  41. return &CryptError{ErrCode: err_code, ErrMsg: err_msg}
  42. }
  43. type WXBizMsg4Recv struct {
  44. Tousername string `xml:"ToUserName"`
  45. Encrypt string `xml:"Encrypt"`
  46. Agentid string `xml:"AgentID"`
  47. }
  48. type CDATA struct {
  49. Value string `xml:",cdata"`
  50. }
  51. type WXBizMsg4Send struct {
  52. XMLName xml.Name `xml:"xml"`
  53. Encrypt CDATA `xml:"Encrypt"`
  54. Signature CDATA `xml:"MsgSignature"`
  55. Timestamp string `xml:"TimeStamp"`
  56. Nonce CDATA `xml:"Nonce"`
  57. }
  58. type MsgContent struct {
  59. ToUsername string `xml:"ToUserName"`
  60. FromUsername string `xml:"FromUserName"`
  61. CreateTime uint32 `xml:"CreateTime"`
  62. MsgType string `xml:"MsgType"`
  63. Content string `xml:"Content"`
  64. MsgId string `xml:"MsgId"`
  65. AgentId uint32 `xml:"AgentId"`
  66. Event string `xml:"Event"`
  67. }
  68. func NewWXBizMsg4Send(encrypt, signature, timestamp, nonce string) *WXBizMsg4Send {
  69. return &WXBizMsg4Send{Encrypt: CDATA{Value: encrypt}, Signature: CDATA{Value: signature}, Timestamp: timestamp, Nonce: CDATA{Value: nonce}}
  70. }
  71. type ProtocolProcessor interface {
  72. parse(src_data []byte) (*WXBizMsg4Recv, *CryptError)
  73. serialize(msg_send *WXBizMsg4Send) ([]byte, *CryptError)
  74. }
  75. type WXBizMsgCrypt struct {
  76. token string
  77. encoding_aeskey string
  78. receiver_id string
  79. protocol_processor ProtocolProcessor
  80. }
  81. type XmlProcessor struct {
  82. }
  83. func (self *XmlProcessor) parse(src_data []byte) (*WXBizMsg4Recv, *CryptError) {
  84. var msg4_recv WXBizMsg4Recv
  85. err := xml.Unmarshal(src_data, &msg4_recv)
  86. if nil != err {
  87. return nil, NewCryptError(ParseXmlError, "xml to msg fail")
  88. }
  89. return &msg4_recv, nil
  90. }
  91. func (self *XmlProcessor) serialize(msg4_send *WXBizMsg4Send) ([]byte, *CryptError) {
  92. xml_msg, err := xml.Marshal(msg4_send)
  93. if nil != err {
  94. return nil, NewCryptError(GenXmlError, err.Error())
  95. }
  96. return xml_msg, nil
  97. }
  98. func NewWXBizMsgCrypt(token, encoding_aeskey, receiver_id string, protocol_type ProtocolType) *WXBizMsgCrypt {
  99. var protocol_processor ProtocolProcessor
  100. if protocol_type != XmlType {
  101. panic("unsupport protocal")
  102. } else {
  103. protocol_processor = new(XmlProcessor)
  104. }
  105. return &WXBizMsgCrypt{token: token, encoding_aeskey: (encoding_aeskey + "="), receiver_id: receiver_id, protocol_processor: protocol_processor}
  106. }
  107. func (self *WXBizMsgCrypt) randString(n int) string {
  108. b := make([]byte, n)
  109. for i := range b {
  110. b[i] = letterBytes[rand.Int63()%int64(len(letterBytes))]
  111. }
  112. return string(b)
  113. }
  114. func (self *WXBizMsgCrypt) pKCS7Padding(plaintext string, block_size int) []byte {
  115. padding := block_size - (len(plaintext) % block_size)
  116. padtext := bytes.Repeat([]byte{byte(padding)}, padding)
  117. var buffer bytes.Buffer
  118. buffer.WriteString(plaintext)
  119. buffer.Write(padtext)
  120. return buffer.Bytes()
  121. }
  122. func (self *WXBizMsgCrypt) pKCS7Unpadding(plaintext []byte, block_size int) ([]byte, *CryptError) {
  123. plaintext_len := len(plaintext)
  124. if nil == plaintext || plaintext_len == 0 {
  125. return nil, NewCryptError(DecryptAESError, "pKCS7Unpadding error nil or zero")
  126. }
  127. if plaintext_len%block_size != 0 {
  128. return nil, NewCryptError(DecryptAESError, "pKCS7Unpadding text not a multiple of the block size")
  129. }
  130. padding_len := int(plaintext[plaintext_len-1])
  131. return plaintext[:plaintext_len-padding_len], nil
  132. }
  133. func (self *WXBizMsgCrypt) cbcEncrypter(plaintext string) ([]byte, *CryptError) {
  134. aeskey, err := base64.StdEncoding.DecodeString(self.encoding_aeskey)
  135. if nil != err {
  136. return nil, NewCryptError(DecodeBase64Error, err.Error())
  137. }
  138. const block_size = 32
  139. pad_msg := self.pKCS7Padding(plaintext, block_size)
  140. block, err := aes.NewCipher(aeskey)
  141. if err != nil {
  142. return nil, NewCryptError(EncryptAESError, err.Error())
  143. }
  144. ciphertext := make([]byte, len(pad_msg))
  145. iv := aeskey[:aes.BlockSize]
  146. mode := cipher.NewCBCEncrypter(block, iv)
  147. mode.CryptBlocks(ciphertext, pad_msg)
  148. base64_msg := make([]byte, base64.StdEncoding.EncodedLen(len(ciphertext)))
  149. base64.StdEncoding.Encode(base64_msg, ciphertext)
  150. return base64_msg, nil
  151. }
  152. func (self *WXBizMsgCrypt) cbcDecrypter(base64_encrypt_msg string) ([]byte, *CryptError) {
  153. aeskey, err := base64.StdEncoding.DecodeString(self.encoding_aeskey)
  154. if nil != err {
  155. return nil, NewCryptError(DecodeBase64Error, err.Error())
  156. }
  157. encrypt_msg, err := base64.StdEncoding.DecodeString(base64_encrypt_msg)
  158. if nil != err {
  159. return nil, NewCryptError(DecodeBase64Error, err.Error())
  160. }
  161. block, err := aes.NewCipher(aeskey)
  162. if err != nil {
  163. return nil, NewCryptError(DecryptAESError, err.Error())
  164. }
  165. if len(encrypt_msg) < aes.BlockSize {
  166. return nil, NewCryptError(DecryptAESError, "encrypt_msg size is not valid")
  167. }
  168. iv := aeskey[:aes.BlockSize]
  169. if len(encrypt_msg)%aes.BlockSize != 0 {
  170. return nil, NewCryptError(DecryptAESError, "encrypt_msg not a multiple of the block size")
  171. }
  172. mode := cipher.NewCBCDecrypter(block, iv)
  173. mode.CryptBlocks(encrypt_msg, encrypt_msg)
  174. return encrypt_msg, nil
  175. }
  176. func (self *WXBizMsgCrypt) calSignature(timestamp, nonce, data string) string {
  177. sort_arr := []string{self.token, timestamp, nonce, data}
  178. sort.Strings(sort_arr)
  179. var buffer bytes.Buffer
  180. for _, value := range sort_arr {
  181. buffer.WriteString(value)
  182. }
  183. sha := sha1.New()
  184. sha.Write(buffer.Bytes())
  185. signature := fmt.Sprintf("%x", sha.Sum(nil))
  186. return string(signature)
  187. }
  188. func (self *WXBizMsgCrypt) ParsePlainText(plaintext []byte) ([]byte, uint32, []byte, []byte, *CryptError) {
  189. const block_size = 32
  190. plaintext, err := self.pKCS7Unpadding(plaintext, block_size)
  191. if nil != err {
  192. return nil, 0, nil, nil, err
  193. }
  194. text_len := uint32(len(plaintext))
  195. if text_len < 20 {
  196. return nil, 0, nil, nil, NewCryptError(IllegalBuffer, "plain is to small 1")
  197. }
  198. random := plaintext[:16]
  199. msg_len := binary.BigEndian.Uint32(plaintext[16:20])
  200. if text_len < (20 + msg_len) {
  201. return nil, 0, nil, nil, NewCryptError(IllegalBuffer, "plain is to small 2")
  202. }
  203. msg := plaintext[20 : 20+msg_len]
  204. receiver_id := plaintext[20+msg_len:]
  205. return random, msg_len, msg, receiver_id, nil
  206. }
  207. func (self *WXBizMsgCrypt) VerifyURL(msg_signature, timestamp, nonce, echostr string) ([]byte, *CryptError) {
  208. signature := self.calSignature(timestamp, nonce, echostr)
  209. if strings.Compare(signature, msg_signature) != 0 {
  210. return nil, NewCryptError(ValidateSignatureError, "signature not equal")
  211. }
  212. plaintext, err := self.cbcDecrypter(echostr)
  213. if nil != err {
  214. return nil, err
  215. }
  216. _, _, msg, receiver_id, err := self.ParsePlainText(plaintext)
  217. if nil != err {
  218. return nil, err
  219. }
  220. if len(self.receiver_id) > 0 && strings.Compare(string(receiver_id), self.receiver_id) != 0 {
  221. fmt.Println(string(receiver_id), self.receiver_id, len(receiver_id), len(self.receiver_id))
  222. return nil, NewCryptError(ValidateCorpidError, "receiver_id is not equil")
  223. }
  224. return msg, nil
  225. }
  226. func (self *WXBizMsgCrypt) EncryptMsg(reply_msg, timestamp, nonce string) ([]byte, *CryptError) {
  227. rand_str := self.randString(16)
  228. var buffer bytes.Buffer
  229. buffer.WriteString(rand_str)
  230. msg_len_buf := make([]byte, 4)
  231. binary.BigEndian.PutUint32(msg_len_buf, uint32(len(reply_msg)))
  232. buffer.Write(msg_len_buf)
  233. buffer.WriteString(reply_msg)
  234. buffer.WriteString(self.receiver_id)
  235. tmp_ciphertext, err := self.cbcEncrypter(buffer.String())
  236. if nil != err {
  237. return nil, err
  238. }
  239. ciphertext := string(tmp_ciphertext)
  240. signature := self.calSignature(timestamp, nonce, ciphertext)
  241. msg4_send := NewWXBizMsg4Send(ciphertext, signature, timestamp, nonce)
  242. return self.protocol_processor.serialize(msg4_send)
  243. }
  244. func (self *WXBizMsgCrypt) DecryptMsg(msg_signature, timestamp, nonce string, post_data []byte) ([]byte, *CryptError) {
  245. msg4_recv, crypt_err := self.protocol_processor.parse(post_data)
  246. if nil != crypt_err {
  247. return nil, crypt_err
  248. }
  249. signature := self.calSignature(timestamp, nonce, msg4_recv.Encrypt)
  250. if strings.Compare(signature, msg_signature) != 0 {
  251. return nil, NewCryptError(ValidateSignatureError, "signature not equal")
  252. }
  253. plaintext, crypt_err := self.cbcDecrypter(msg4_recv.Encrypt)
  254. if nil != crypt_err {
  255. return nil, crypt_err
  256. }
  257. _, _, msg, receiver_id, crypt_err := self.ParsePlainText(plaintext)
  258. if nil != crypt_err {
  259. return nil, crypt_err
  260. }
  261. if len(self.receiver_id) > 0 && strings.Compare(string(receiver_id), self.receiver_id) != 0 {
  262. return nil, NewCryptError(ValidateCorpidError, "receiver_id is not equil")
  263. }
  264. return msg, nil
  265. }