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
142
143
144
145
|
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/sha256"
"encoding/base64"
"fmt"
"math/rand"
"time"
)
type AesCipher struct {
block cipher.Block
blockBytes int
}
func NewAesCipher(key []byte, bits int) (*AesCipher, error) {
// 对密钥算哈希,这样密钥不必是固定长度
hash := sha256.Sum256(key)
key = hash[:bits>>3]
// 以哈希值为密钥,初始化加密器
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
return &AesCipher{
block: block,
blockBytes: block.BlockSize(),
}, nil
}
func (a *AesCipher) Encrypt(plaintext []byte, b64 bool) ([]byte, error) {
// 对明文进行填充
plaintext = Pkcs5Padding(plaintext, a.blockBytes)
// 随机生成初始向量
iv := make([]byte, a.blockBytes)
if _, err := rand.Read(iv); err != nil {
return nil, err
}
// 为密文分配空间(为拼接IV预留空间),并完成加密
ciphertext := make([]byte, len(plaintext), len(plaintext)+len(iv))
cipher.NewCBCEncrypter(a.block, iv).CryptBlocks(ciphertext, plaintext)
// 将IV拼接在密文后面,两者合在一起作为加密结果
result := append(ciphertext, iv...)
// 由于结果是无序的二进制字节序列,可以做BASE64编码(可选)
if b64 {
result = Base64Encode(base64.StdEncoding, result)
}
return result, nil
}
func (a *AesCipher) Decrypt(cipherdata []byte, b64 bool) ([]byte, error) {
// 如果做了BASE64编码,需要先解密
if b64 {
var err error
cipherdata, err = Base64Decode(base64.StdEncoding, cipherdata)
if err != nil {
return nil, err
}
}
// 计算密文长度
textBytes := len(cipherdata) - a.blockBytes
// 切出密文和IV
iv := cipherdata[textBytes:]
ciphertext := cipherdata[:textBytes]
// 为明文分配空间并解密
plaintext := make([]byte, len(ciphertext))
cipher.NewCBCDecrypter(a.block, iv).CryptBlocks(plaintext, ciphertext)
// 取出填充字符
return Pkcs5Unpadding(plaintext), nil
}
func Pkcs5Padding(data []byte, blockSize int) []byte {
padding := blockSize - len(data)%blockSize
paddings := bytes.Repeat([]byte{byte(padding)}, padding)
return append(data, paddings...)
}
func Pkcs5Unpadding(data []byte) []byte {
bytes := len(data)
padding := int(data[bytes-1])
return data[:bytes-padding]
}
func Base64Encode(enc *base64.Encoding, data []byte) []byte {
result := make([]byte, enc.EncodedLen(len(data)))
enc.Encode(result, data)
return result
}
func Base64Decode(enc *base64.Encoding, data []byte) ([]byte, error) {
result := make([]byte, enc.DecodedLen(len(data)))
if n, err := enc.Decode(result, data); err != nil {
return nil, err
} else {
return result[:n], nil
}
}
func main() {
// 设置随机数种子(随机生成IV)
rand.Seed(time.Now().UnixMicro())
cipher, err := NewAesCipher([]byte("abc"), 256)
if err != nil {
panic(err)
}
for _, text := range [][]byte{
[]byte("fasionchan"),
[]byte("小菜学编程"),
[]byte("fasionchan.com"),
[]byte("coding-fans"),
[]byte("https://fasionchan.com"),
[]byte("Python源码剖析"),
} {
ciphertext, err := cipher.Encrypt(text, true)
if err != nil {
panic(err)
}
plaintext, err := cipher.Decrypt(ciphertext, true)
if err != nil {
panic(err)
}
if bytes.Compare(plaintext, text) != 0 {
panic(fmt.Sprintf("case failed: %s", text))
}
}
}
|