forked from royalrick/weapp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcrypto.go
135 lines (108 loc) · 3.01 KB
/
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package weapp
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/sha1"
"encoding/base64"
"encoding/hex"
"errors"
"io"
"sort"
"strings"
)
const pkcs7blocksize = 32
// pkcs7encode 对需要加密的明文进行填充补位
// plaintext 需要进行填充补位操作的明文
// 返回补齐明文字符串
func pkcs7encode(plaintext []byte) []byte {
//计算需要填充的位数
pad := pkcs7blocksize - len(plaintext)%pkcs7blocksize
if pad == 0 {
pad = pkcs7blocksize
}
//获得补位所用的字符
text := bytes.Repeat([]byte{byte(pad)}, pad)
return append(plaintext, text...)
}
// pkcs7decode 对解密后的明文进行补位删除
// plaintext 解密后的明文
// 返回删除填充补位后的明文和
func pkcs7decode(plaintext []byte) []byte {
ln := len(plaintext)
// 获取最后一个字符的 ASCII
pad := int(plaintext[ln-1])
if pad < 1 || pad > pkcs7blocksize {
pad = 0
}
return plaintext[:(ln - pad)]
}
// 对加密数据包进行签名校验,确保数据的完整性。
func validateSignature(signature string, parts ...string) bool {
return signature == createSignature(parts...)
}
// 校验用户数据数据
func validateUserInfo(signature, rawData, ssk string) bool {
raw := sha1.Sum([]byte(rawData + ssk))
return signature == hex.EncodeToString(raw[:])
}
// 拼凑签名
func createSignature(parts ...string) string {
sort.Strings(parts)
raw := sha1.Sum([]byte(strings.Join(parts, "")))
return hex.EncodeToString(raw[:])
}
// cbcEncrypt CBC 加密数据
func cbcEncrypt(key, plaintext, iv []byte) ([]byte, error) {
if len(plaintext)%aes.BlockSize != 0 {
return nil, errors.New("plaintext is not a multiple of the block size")
}
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
iv = iv[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return nil, err
}
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
return ciphertext, nil
}
// CBC解密数据
func cbcDecrypt(key, ciphertext, iv []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
size := aes.BlockSize
iv = iv[:size]
// ciphertext = ciphertext[size:] TODO: really useless?
if len(ciphertext) < size {
return nil, errors.New("ciphertext too short")
}
if len(ciphertext)%size != 0 {
return nil, errors.New("ciphertext is not a multiple of the block size")
}
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(ciphertext, ciphertext)
return pkcs7decode(ciphertext), nil
}
// decryptUserData 解密用户数据
func decryptUserData(ssk, ciphertext, iv string) ([]byte, error) {
key, err := base64.StdEncoding.DecodeString(ssk)
if err != nil {
return nil, err
}
cipher, err := base64.StdEncoding.DecodeString(ciphertext)
if err != nil {
return nil, err
}
rawIV, err := base64.StdEncoding.DecodeString(iv)
if err != nil {
return nil, err
}
return cbcDecrypt(key, cipher, rawIV)
}