/
msg_crypto.go
119 lines (104 loc) · 3.07 KB
/
msg_crypto.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/**
* 微信信息加解密/签名/随机数
* 1. HashStrings([]string) -- 微信常用的签名算法 []string -> sort -> sha1 -> hex
* 2. GetRandomBytes(int) -- 获取指定长度的随机串,随机字符为 数字/小写字母/大写字母
*/
package wxmsg
import (
"sort"
"fmt"
"crypto/cipher"
"crypto/sha1"
"crypto/aes"
"encoding/base64"
"encoding/binary"
"math/rand"
"time"
"bytes"
"io"
"github.com/rosbit/go-wx-api/conf"
)
func init() {
rand.Seed(time.Now().Unix())
}
func HashStrings(sl []string) string {
sort.Strings(sl)
h := sha1.New()
for _, s := range sl {
io.WriteString(h, s)
}
return fmt.Sprintf("%x", h.Sum(nil))
}
func _PKCS5Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext) % blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
func _PKCS5UnPadding(origData []byte) []byte {
length := len(origData)
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}
func decryptMsg(wxParams *wxconf.WxParamsT, body string, signature string, timestamp string, nonce string) ([]byte, error) {
l := []string{wxParams.Token, timestamp, nonce, body}
hashcode := HashStrings(l)
if hashcode != signature {
return nil, fmt.Errorf("bad signature")
}
cryptedMsg, err := base64.StdEncoding.DecodeString(body)
if err != nil {
return nil, err
}
key := wxParams.AesKey
aesBlk, err := aes.NewCipher(key)
blockSize := aesBlk.BlockSize()
iv := key[:blockSize]
blockMode := cipher.NewCBCDecrypter(aesBlk, iv)
plainText := make([]byte, len(cryptedMsg))
blockMode.CryptBlocks(plainText, cryptedMsg)
plainText = _PKCS5UnPadding(plainText)
xmlLen := binary.BigEndian.Uint32(plainText[16:20])
return plainText[20:xmlLen+20], nil
}
var _rule = []byte("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
const _block_size = 32
func GetRandomBytes(n int) []byte {
b := make([]byte, n)
rc := len(_rule)
for i:=0; i<n; i++ {
b[i] = _rule[rand.Intn(rc)]
}
return b
}
func _msgToPad(msgLen int) []byte {
paddingLen := _block_size - (msgLen % _block_size)
if paddingLen == 0 {
paddingLen = _block_size
}
padByte := byte(paddingLen)
pad := make([]byte, paddingLen)
for i:=0; i<paddingLen; i++ {
pad[i] = padByte
}
return pad
}
func encryptMsg(wxParams *wxconf.WxParamsT, msg []byte, timestamp, nonce string) (string, string) {
randBytes := GetRandomBytes(16)
msgLenInNet := make([]byte, 4)
binary.BigEndian.PutUint32(msgLenInNet, uint32(len(msg)))
origData := bytes.Buffer{}
origData.Write(randBytes)
origData.Write(msgLenInNet)
origData.Write(msg)
origData.WriteString(wxParams.AppId)
pad := _msgToPad(origData.Len())
origData.Write(pad)
key := wxParams.AesKey
block, _ := aes.NewCipher(key)
iv := key[:block.BlockSize()]
blockMode := cipher.NewCBCEncrypter(block, iv)
crypted := make([]byte, origData.Len())
blockMode.CryptBlocks(crypted, origData.Bytes())
cryptedText := base64.StdEncoding.EncodeToString(crypted)
return cryptedText, HashStrings([]string{wxParams.Token, timestamp, nonce, cryptedText})
}