wxbizjsonmsgcrypt.go 8.7 KB

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