forked from riobard/go-shadowsocks2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcipher.go
132 lines (106 loc) · 3.89 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
package main
import (
"crypto/aes"
"crypto/cipher"
"errors"
"fmt"
"net"
"strings"
"golang.org/x/crypto/chacha20poly1305"
"github.com/Yawning/chacha20"
"github.com/riobard/go-shadowsocks2/core"
"github.com/riobard/go-shadowsocks2/shadowaead"
"github.com/riobard/go-shadowsocks2/shadowstream"
)
// ErrKeySize means the supplied key size does not meet the requirement of cipher choosed.
var ErrKeySize = errors.New("key size error")
func pickCipher(name string, key []byte) (core.StreamConnCipher, core.PacketConnCipher, error) {
switch strings.ToLower(name) {
case "aes-128-gcm", "aes-192-gcm", "aes-256-gcm":
aead, err := aesGCM(key, 0) // 0 for standard 12-byte nonce
return aeadStream(aead), aeadPacket(aead), err
case "aes-128-gcm-16", "aes-192-gcm-16", "aes-256-gcm-16":
aead, err := aesGCM(key, 16) // 16-byte nonce for better collision avoidance
return aeadStream(aead), aeadPacket(aead), err
case "chacha20-ietf-poly1305":
aead, err := chacha20poly1305.New(key)
return aeadStream(aead), aeadPacket(aead), err
case "aes-128-ctr", "aes-192-ctr", "aes-256-ctr":
ciph, err := aesCTR(key)
return streamStream(ciph), streamPacket(ciph), err
case "aes-128-cfb", "aes-192-cfb", "aes-256-cfb":
ciph, err := aesCFB(key)
return streamStream(ciph), streamPacket(ciph), err
case "chacha20-ietf":
if len(key) != chacha20.KeySize {
return nil, nil, ErrKeySize
}
k := chacha20ietfkey(key)
return streamStream(k), streamPacket(k), nil
case "dummy": // only for benchmarking and debugging
return dummyStream(), dummyPacket(), nil
default:
err := fmt.Errorf("cipher not supported: %s", name)
return nil, nil, err
}
}
func dummyStream() core.StreamConnCipher {
return func(c net.Conn) net.Conn { return c }
}
func dummyPacket() core.PacketConnCipher {
return func(c net.PacketConn) net.PacketConn { return c }
}
func aeadStream(aead cipher.AEAD) core.StreamConnCipher {
return func(c net.Conn) net.Conn { return shadowaead.NewConn(c, aead) }
}
func aeadPacket(aead cipher.AEAD) core.PacketConnCipher {
return func(c net.PacketConn) net.PacketConn { return shadowaead.NewPacketConn(c, aead) }
}
func aesGCM(key []byte, nonceSize int) (cipher.AEAD, error) {
blk, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
if nonceSize > 0 {
return cipher.NewGCMWithNonceSize(blk, nonceSize)
}
return cipher.NewGCM(blk) // standard 12-byte nonce
}
func streamStream(ciph shadowstream.Cipher) core.StreamConnCipher {
return func(c net.Conn) net.Conn { return shadowstream.NewConn(c, ciph) }
}
func streamPacket(ciph shadowstream.Cipher) core.PacketConnCipher {
return func(c net.PacketConn) net.PacketConn { return shadowstream.NewPacketConn(c, ciph) }
}
type ctrStream struct{ cipher.Block }
func (b *ctrStream) IVSize() int { return b.BlockSize() }
func (b *ctrStream) Encrypter(iv []byte) cipher.Stream { return cipher.NewCTR(b, iv) }
func (b *ctrStream) Decrypter(iv []byte) cipher.Stream { return b.Encrypter(iv) }
func aesCTR(key []byte) (shadowstream.Cipher, error) {
blk, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
return &ctrStream{blk}, nil
}
type cfbStream struct{ cipher.Block }
func (b *cfbStream) IVSize() int { return b.BlockSize() }
func (b *cfbStream) Encrypter(iv []byte) cipher.Stream { return cipher.NewCFBEncrypter(b, iv) }
func (b *cfbStream) Decrypter(iv []byte) cipher.Stream { return cipher.NewCFBDecrypter(b, iv) }
func aesCFB(key []byte) (shadowstream.Cipher, error) {
blk, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
return &ctrStream{blk}, nil
}
type chacha20ietfkey []byte
func (k chacha20ietfkey) IVSize() int { return chacha20.INonceSize }
func (k chacha20ietfkey) Encrypter(iv []byte) cipher.Stream {
ciph, err := chacha20.NewCipher(k, iv)
if err != nil {
panic(err)
}
return ciph
}
func (k chacha20ietfkey) Decrypter(iv []byte) cipher.Stream { return k.Encrypter(iv) }