Skip to content

Commit a4d0f1d

Browse files
authored
加解密包
1 parent 14a2cd8 commit a4d0f1d

File tree

1 file changed

+154
-1
lines changed

1 file changed

+154
-1
lines changed

crypto.go

+154-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,164 @@
11
package godingtalk
22

3+
import (
4+
"bytes"
5+
"crypto/aes"
6+
"crypto/cipher"
7+
"encoding/base64"
8+
"encoding/binary"
9+
"errors"
10+
"math/rand"
11+
r "math/rand"
12+
"sort"
13+
"time"
14+
)
15+
16+
const (
17+
AES_ENCODE_KEY_LENGTH = 43
18+
)
19+
20+
var DefaultDingtalkCrypto *Crypto
21+
322
type Crypto struct {
423
Token string
524
AesKey string
625
SuiteKey string
26+
block cipher.Block
27+
bkey []byte
28+
}
29+
30+
/*
31+
token 数据签名需要用到的token,ISV(服务提供商)推荐使用注册套件时填写的token,普通企业可以随机填写
32+
aesKey 数据加密密钥。用于回调数据的加密,长度固定为43个字符,从a-z, A-Z, 0-9共62个字符中选取,您可以随机生成,ISV(服务提供商)推荐使用注册套件时填写的EncodingAESKey
33+
suiteKey 一般使用corpID
34+
*/
35+
func NewCrypto(token, aesKey, suiteKey string) (c *Crypto) {
36+
c = &Crypto{
37+
Token: token,
38+
AesKey: aesKey,
39+
SuiteKey: suiteKey,
40+
}
41+
if len(c.AesKey) != AES_ENCODE_KEY_LENGTH {
42+
panic("不合法的aeskey")
43+
}
44+
var err error
45+
c.bkey, err = base64.StdEncoding.DecodeString(aesKey + "=")
46+
if err != nil {
47+
panic(err.Error())
48+
}
49+
c.block, err = aes.NewCipher(c.bkey)
50+
if err != nil {
51+
panic(err.Error())
52+
}
53+
return c
54+
}
55+
56+
/*
57+
signature: 签名字符串
58+
timeStamp: 时间戳
59+
nonce: 随机字符串
60+
secretStr: 密文
61+
返回: 解密后的明文
62+
*/
63+
func (c *Crypto) DecryptMsg(signature, timeStamp, nonce, secretStr string) (string, error) {
64+
if !c.VerifySignature(c.Token, timeStamp, nonce, secretStr, signature) {
65+
return "", errors.New("签名不匹配")
66+
}
67+
decode, err := base64.StdEncoding.DecodeString(secretStr)
68+
if err != nil {
69+
return "", err
70+
}
71+
if len(decode) < aes.BlockSize {
72+
return "", errors.New("密文太短啦")
73+
}
74+
blockMode := cipher.NewCBCDecrypter(c.block, c.bkey[:c.block.BlockSize()])
75+
plantText := make([]byte, len(decode))
76+
blockMode.CryptBlocks(plantText, decode)
77+
plantText = PKCS7UnPadding(plantText)
78+
size := binary.BigEndian.Uint32(plantText[16 : 16+4])
79+
plantText = plantText[16+4:]
80+
cropid := plantText[size:]
81+
if string(cropid) != c.SuiteKey {
82+
return "", errors.New("CropID不正确")
83+
}
84+
return string(plantText[:size]), nil
85+
}
86+
87+
func PKCS7UnPadding(plantText []byte) []byte {
88+
length := len(plantText)
89+
unpadding := int(plantText[length-1])
90+
return plantText[:(length - unpadding)]
791
}
892

9-
func (c *Crypto) Encrypt(str string) {
93+
/*
94+
replyMsg: 明文字符串
95+
timeStamp: 时间戳
96+
nonce: 随机字符串
97+
返回: 密文,签名字符串
98+
*/
99+
func (c *Crypto) EncryptMsg(replyMsg, timeStamp, nonce string) (string, string, error) {
100+
//原生消息体长度
101+
size := make([]byte, 4)
102+
binary.BigEndian.PutUint32(size, uint32(len(replyMsg)))
103+
replyMsg = c.RandomString(16) + string(size) + replyMsg + c.SuiteKey
104+
plantText := PKCS7Padding([]byte(replyMsg), c.block.BlockSize())
105+
if len(plantText)%aes.BlockSize != 0 {
106+
return "", "", errors.New("消息体大小不为16的倍数")
107+
}
108+
109+
blockMode := cipher.NewCBCEncrypter(c.block, c.bkey[:c.block.BlockSize()])
110+
ciphertext := make([]byte, len(plantText))
111+
blockMode.CryptBlocks(ciphertext, plantText)
112+
outStr := base64.StdEncoding.EncodeToString(ciphertext)
113+
sigStr := c.GenerateSignature(c.Token, timeStamp, nonce, string(outStr))
114+
return string(outStr), sigStr, nil
115+
}
116+
117+
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
118+
padding := blockSize - len(ciphertext)%blockSize
119+
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
120+
return append(ciphertext, padtext...)
121+
}
122+
123+
// 数据签名
124+
func (c *Crypto) GenerateSignature(token, timeStamp, nonce, secretStr string) string {
125+
// 先将参数值进行排序
126+
params := make([]string, 0)
127+
params = append(params, token)
128+
params = append(params, secretStr)
129+
params = append(params, timeStamp)
130+
params = append(params, nonce)
131+
sort.Strings(params)
132+
return sha1Sign(params[0] + params[1] + params[2] + params[3])
133+
}
134+
135+
// 校验数据签名
136+
func (c *Crypto) VerifySignature(token, timeStamp, nonce, secretStr, sigture string) bool {
137+
return c.GenerateSignature(token, timeStamp, nonce, secretStr) == sigture
138+
}
10139

140+
func (c *Crypto) RandomString(n int, alphabets ...byte) string {
141+
const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
142+
var bytes = make([]byte, n)
143+
var randby bool
144+
if num, err := rand.Read(bytes); num != n || err != nil {
145+
r.Seed(time.Now().UnixNano())
146+
randby = true
147+
}
148+
for i, b := range bytes {
149+
if len(alphabets) == 0 {
150+
if randby {
151+
bytes[i] = alphanum[r.Intn(len(alphanum))]
152+
} else {
153+
bytes[i] = alphanum[b%byte(len(alphanum))]
154+
}
155+
} else {
156+
if randby {
157+
bytes[i] = alphabets[r.Intn(len(alphabets))]
158+
} else {
159+
bytes[i] = alphabets[b%byte(len(alphabets))]
160+
}
161+
}
162+
}
163+
return string(bytes)
11164
}

0 commit comments

Comments
 (0)