-
Notifications
You must be signed in to change notification settings - Fork 0
/
cipher.go
140 lines (126 loc) · 3.26 KB
/
cipher.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
package cipher
import (
"crypto/md5"
"crypto/sha1"
"fmt"
"io"
"github.com/josexy/mini-ss/util/logger"
"golang.org/x/crypto/hkdf"
)
const (
aes128CTR = "aes-128-ctr"
aes192CTR = "aes-192-ctr"
aes256CTR = "aes-256-ctr"
aes128CFB = "aes-128-cfb"
aes192CFB = "aes-192-cfb"
aes256CFB = "aes-256-cfb"
bfCFB = "bf-cfb" // Blowfish in CFB mode
salsa20_ = "salsa20"
rc4Md5 = "rc4-md5"
chacha20_ = "chacha20"
chacha20IETF = "chacha20-ietf"
)
const (
aes128GCM = "aes-128-gcm"
aes192GCM = "aes-192-gcm"
aes256GCM = "aes-256-gcm"
chacha20Poly1305 = "chacha20-ietf-poly1305"
xchacha20Poly1305 = "xchacha20-ietf-poly1305"
)
var (
streamCipherMap = map[string]streamCipherWrapper{
aes128CTR: {16, 16, AesCtr},
aes192CTR: {24, 16, AesCtr},
aes256CTR: {32, 16, AesCtr},
aes128CFB: {16, 16, AesCfb},
aes192CFB: {24, 16, AesCfb},
aes256CFB: {32, 16, AesCfb},
salsa20_: {32, 8, Salsa20},
bfCFB: {16, 8, BfCfb},
rc4Md5: {16, 16, Rc4Md5},
chacha20_: {32, 8, Chacha20},
chacha20IETF: {32, 12, Chacha20Ietf},
}
aeadCipherMap = map[string]aeadCipherWrapper{
aes128GCM: {16, 16, 12, 16, AesGcm},
aes192GCM: {24, 24, 12, 16, AesGcm},
aes256GCM: {32, 32, 12, 16, AesGcm},
chacha20Poly1305: {32, 32, 12, 16, Chacha20Poly1305},
xchacha20Poly1305: {32, 32, 12, 16, XChacha20Poly1305},
}
)
type (
streamCipherWrapper struct {
KeySize int
IVSize int
NewCipher func(key []byte, ivSize int) (StreamCipher, error)
}
aeadCipherWrapper struct {
KeySize int
SaltSize int
NonceSize int
TagSize int
NewCipher func(key []byte, saltSize int) (AEADCipher, error)
}
)
func GetCipher(method, password string) (sc StreamCipher, ac AEADCipher, err error) {
if method == "none" {
return nil, nil, nil
}
if _, ok := streamCipherMap[method]; ok {
sc, err = NewStreamCipher(method, password)
} else if _, ok = aeadCipherMap[method]; ok {
ac, err = NewAEADCipher(method, password)
} else {
err = fmt.Errorf("not support method: %s", method)
}
return
}
func NewStreamCipher(method, password string) (StreamCipher, error) {
x, ok := streamCipherMap[method]
if !ok {
return nil, fmt.Errorf("not support stream cipher: %s", method)
}
// simple EVP_BytesToKey()
key := Kdf(password, x.KeySize)
return x.NewCipher(key, x.IVSize)
}
func NewAEADCipher(method, password string) (AEADCipher, error) {
x, ok := aeadCipherMap[method]
if !ok {
return nil, fmt.Errorf("not support aead cipher: %s", method)
}
// simple EVP_BytesToKey()
key := Kdf(password, x.KeySize)
return x.NewCipher(key, x.SaltSize)
}
/*
#include <openssl/evp.h>
int EVP_BytesToKey(
const EVP_CIPHER *type,
const EVP_MD *md,
const unsigned char *salt,
const unsigned char *data,
int datal,
int count,
unsigned char *key,
unsigned char *iv);
*/
func Kdf(password string, keyLen int) []byte {
var res, prev []byte
h := md5.New()
for len(res) < keyLen {
h.Write(prev)
h.Write([]byte(password))
res = h.Sum(res)
prev = res[len(res)-h.Size():]
h.Reset()
}
return res[:keyLen]
}
func hkdfSha1(key, salt, info, outKey []byte) {
r := hkdf.New(sha1.New, key, salt, info)
if _, err := io.ReadFull(r, outKey); err != nil {
logger.Logger.ErrorBy(err)
}
}