-
Notifications
You must be signed in to change notification settings - Fork 155
/
aes.go
141 lines (115 loc) · 3.88 KB
/
aes.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
136
137
138
139
140
141
package support
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
)
const (
ErrorBase64Decode = -40010 // base64 解码失败
ErrorEncryptAes = -40006 // AES 加密失败
ErrorDecryptAes = -40007 // AES 解密失败
ErrorInvalidAesKey = -40004 // AESKey 非法
ErrorInvalidIv = -10001 // AESKey 非法
)
type CryptError struct {
ErrCode int
ErrMsg string
}
func NewCryptError(errCode int, errMsg string) *CryptError {
return &CryptError{ErrCode: errCode, ErrMsg: errMsg}
}
type AES struct{}
func NewAES() *AES {
return &AES{}
}
func (a AES) Encrypt(text []byte, key, iv []byte) ([]byte, *CryptError) {
const blockSize = 32
padMsg := a.PKCS7Padding(text, blockSize)
block, err := aes.NewCipher(key)
if err != nil {
return nil, NewCryptError(ErrorEncryptAes, err.Error())
}
ciphertext := make([]byte, len(padMsg))
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext, padMsg)
base64Msg := make([]byte, base64.StdEncoding.EncodedLen(len(ciphertext)))
base64.StdEncoding.Encode(base64Msg, ciphertext)
return base64Msg, nil
}
// Decrypt AES解密
// cipherText 是密文的base64字符串
// key和iv是经过反base64之后的byte内容
// 例如:原始值是"tiihtNczf5v6AKRyjwEUhQ==",那么应该用base64.StdEncoding.DecodeString("tiihtNczf5v6AKRyjwEUhQ==")解码之后传过来
func (a AES) Decrypt(cipherText string, key, iv []byte) ([]byte, *CryptError) {
encryptMsg, err := base64.StdEncoding.DecodeString(cipherText)
//log.Println("cipherText: ", cipherText, err)
if nil != err {
return nil, NewCryptError(ErrorBase64Decode, err.Error())
}
//log.Println("ready to gen block")
block, err := aes.NewCipher(key)
if err != nil {
return nil, NewCryptError(ErrorDecryptAes, err.Error())
}
if len(encryptMsg) < aes.BlockSize {
return nil, NewCryptError(ErrorDecryptAes, "encrypt_msg size is not valid")
}
//iv := aesKey[:aes.BlockSize]
if len(encryptMsg)%aes.BlockSize != 0 {
return nil, NewCryptError(ErrorDecryptAes, "encrypt_msg not a multiple of the block size")
}
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(encryptMsg, encryptMsg)
//log.Println("encryptMsg: ", string(encryptMsg))
originalMsg, err2 := a.PKCS7UnPadding(encryptMsg)
if err2 != nil {
return nil, err2
}
return originalMsg, nil
}
// PKCS7Padding PKCS#7 padding.
func (a *AES) PKCS7Padding(text []byte, blockSize int) []byte {
padding := blockSize - (len(text) % blockSize)
padText := bytes.Repeat([]byte{byte(padding)}, padding)
var buffer bytes.Buffer
buffer.Write(text)
buffer.Write(padText)
return buffer.Bytes()
}
// PKCS7UnPadding KCS#7 unPadding.
func (a *AES) PKCS7UnPadding(text []byte) ([]byte, *CryptError) {
plaintextLen := len(text)
if text == nil || plaintextLen == 0 {
return nil, NewCryptError(ErrorDecryptAes, "pKCS7UnPadding error nil or zero")
}
// TODO: 不清楚微信官方为什么需要这里校验一下
//if plaintextLen%encryptor.blockSize != 0 {
// return nil, NewCryptError(ErrorDecryptAes, "pKCS7UnPadding text not a multiple of the block size")
//}
paddingLen := int(text[plaintextLen-1])
return text[:plaintextLen-paddingLen], nil
}
// DecryptAES256GCM 使用 AEAD_AES_256_GCM 算法进行解密
//
// 你可以使用此算法完成微信支付平台证书和回调报文解密,详见:
// https://wechatpay-api.gitbook.io/wechatpay-api-v3/qian-ming-zhi-nan-1/zheng-shu-he-hui-tiao-bao-wen-jie-mi
func DecryptAES256GCM(aesKey, associatedData, nonce, ciphertext string) (plaintext string, err error) {
decodedCiphertext, err := base64.StdEncoding.DecodeString(ciphertext)
if err != nil {
return "", err
}
c, err := aes.NewCipher([]byte(aesKey))
if err != nil {
return "", err
}
gcm, err := cipher.NewGCM(c)
if err != nil {
return "", err
}
dataBytes, err := gcm.Open(nil, []byte(nonce), decodedCiphertext, []byte(associatedData))
if err != nil {
return "", err
}
return string(dataBytes), nil
}