Skip to content

Commit 443dd01

Browse files
committed
Initial commit
0 parents  commit 443dd01

16 files changed

+1535
-0
lines changed

cipher.go

+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package main
2+
3+
import (
4+
"crypto/aes"
5+
"crypto/cipher"
6+
"errors"
7+
"fmt"
8+
"net"
9+
"strings"
10+
11+
"golang.org/x/crypto/chacha20poly1305"
12+
13+
"github.com/Yawning/chacha20"
14+
"github.com/riobard/go-shadowsocks2/core"
15+
"github.com/riobard/go-shadowsocks2/shadowaead"
16+
"github.com/riobard/go-shadowsocks2/shadowstream"
17+
)
18+
19+
// ErrKeySize means the supplied key size does not meet the requirement of cipher choosed.
20+
var ErrKeySize = errors.New("key size error")
21+
22+
func pickCipher(name string, key []byte) (core.StreamConnCipher, core.PacketConnCipher, error) {
23+
24+
switch strings.ToLower(name) {
25+
case "aes-128-gcm", "aes-192-gcm", "aes-256-gcm":
26+
aead, err := aesGCM(key, 0) // 0 for standard 12-byte nonce
27+
return aeadStream(aead), aeadPacket(aead), err
28+
29+
case "aes-128-gcm-16", "aes-192-gcm-16", "aes-256-gcm-16":
30+
aead, err := aesGCM(key, 16) // 16-byte nonce for better collision avoidance
31+
return aeadStream(aead), aeadPacket(aead), err
32+
33+
case "chacha20-ietf-poly1305":
34+
aead, err := chacha20poly1305.New(key)
35+
return aeadStream(aead), aeadPacket(aead), err
36+
37+
case "aes-128-ctr", "aes-192-ctr", "aes-256-ctr":
38+
ciph, err := aesCTR(key)
39+
return streamStream(ciph), streamPacket(ciph), err
40+
41+
case "aes-128-cfb", "aes-192-cfb", "aes-256-cfb":
42+
ciph, err := aesCFB(key)
43+
return streamStream(ciph), streamPacket(ciph), err
44+
45+
case "chacha20-ietf":
46+
if len(key) != chacha20.KeySize {
47+
return nil, nil, ErrKeySize
48+
}
49+
k := chacha20ietfkey(key)
50+
return streamStream(k), streamPacket(k), nil
51+
52+
case "dummy": // only for benchmarking and debugging
53+
return dummyStream(), dummyPacket(), nil
54+
55+
default:
56+
err := fmt.Errorf("cipher not supported: %s", name)
57+
return nil, nil, err
58+
}
59+
}
60+
61+
func dummyStream() core.StreamConnCipher {
62+
return func(c net.Conn) net.Conn { return c }
63+
}
64+
func dummyPacket() core.PacketConnCipher {
65+
return func(c net.PacketConn) net.PacketConn { return c }
66+
}
67+
68+
func aeadStream(aead cipher.AEAD) core.StreamConnCipher {
69+
return func(c net.Conn) net.Conn { return shadowaead.NewConn(c, aead) }
70+
}
71+
func aeadPacket(aead cipher.AEAD) core.PacketConnCipher {
72+
return func(c net.PacketConn) net.PacketConn { return shadowaead.NewPacketConn(c, aead) }
73+
}
74+
75+
func aesGCM(key []byte, nonceSize int) (cipher.AEAD, error) {
76+
blk, err := aes.NewCipher(key)
77+
if err != nil {
78+
return nil, err
79+
}
80+
if nonceSize > 0 {
81+
return cipher.NewGCMWithNonceSize(blk, nonceSize)
82+
}
83+
return cipher.NewGCM(blk) // standard 12-byte nonce
84+
}
85+
86+
func streamStream(ciph shadowstream.Cipher) core.StreamConnCipher {
87+
return func(c net.Conn) net.Conn { return shadowstream.NewConn(c, ciph) }
88+
}
89+
90+
func streamPacket(ciph shadowstream.Cipher) core.PacketConnCipher {
91+
return func(c net.PacketConn) net.PacketConn { return shadowstream.NewPacketConn(c, ciph) }
92+
}
93+
94+
type ctrStream struct{ cipher.Block }
95+
96+
func (b *ctrStream) IVSize() int { return b.BlockSize() }
97+
func (b *ctrStream) Encrypter(iv []byte) cipher.Stream { return cipher.NewCTR(b, iv) }
98+
func (b *ctrStream) Decrypter(iv []byte) cipher.Stream { return b.Encrypter(iv) }
99+
100+
func aesCTR(key []byte) (shadowstream.Cipher, error) {
101+
blk, err := aes.NewCipher(key)
102+
if err != nil {
103+
return nil, err
104+
}
105+
return &ctrStream{blk}, nil
106+
}
107+
108+
type cfbStream struct{ cipher.Block }
109+
110+
func (b *cfbStream) IVSize() int { return b.BlockSize() }
111+
func (b *cfbStream) Encrypter(iv []byte) cipher.Stream { return cipher.NewCFBEncrypter(b, iv) }
112+
func (b *cfbStream) Decrypter(iv []byte) cipher.Stream { return cipher.NewCFBDecrypter(b, iv) }
113+
114+
func aesCFB(key []byte) (shadowstream.Cipher, error) {
115+
blk, err := aes.NewCipher(key)
116+
if err != nil {
117+
return nil, err
118+
}
119+
return &ctrStream{blk}, nil
120+
}
121+
122+
type chacha20ietfkey []byte
123+
124+
func (k chacha20ietfkey) IVSize() int { return chacha20.INonceSize }
125+
func (k chacha20ietfkey) Encrypter(iv []byte) cipher.Stream {
126+
ciph, err := chacha20.NewCipher(k, iv)
127+
if err != nil {
128+
panic(err)
129+
}
130+
return ciph
131+
}
132+
func (k chacha20ietfkey) Decrypter(iv []byte) cipher.Stream { return k.Encrypter(iv) }

core/doc.go

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Package core provides essential interfaces for Shadowsocks
2+
package core

core/packet.go

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package core
2+
3+
import "net"
4+
5+
type PacketConnCipher func(net.PacketConn) net.PacketConn
6+
7+
func ListenPacket(network, address string, ciph PacketConnCipher) (net.PacketConn, error) {
8+
c, err := net.ListenPacket(network, address)
9+
return ciph(c), err
10+
}

core/stream.go

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package core
2+
3+
import "net"
4+
5+
type StreamConnCipher func(net.Conn) net.Conn
6+
7+
type listener struct {
8+
net.Listener
9+
StreamConnCipher
10+
}
11+
12+
func Listen(network, address string, ciph StreamConnCipher) (net.Listener, error) {
13+
l, err := net.Listen(network, address)
14+
return &listener{l, ciph}, err
15+
}
16+
17+
func (l *listener) Accept() (net.Conn, error) {
18+
c, err := l.Listener.Accept()
19+
return l.StreamConnCipher(c), err
20+
}
21+
22+
func Dial(network, address string, ciph StreamConnCipher) (net.Conn, error) {
23+
c, err := net.Dial(network, address)
24+
return ciph(c), err
25+
}

main.go

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package main
2+
3+
import (
4+
"encoding/hex"
5+
"flag"
6+
"log"
7+
"os"
8+
"os/signal"
9+
"strings"
10+
"syscall"
11+
"time"
12+
)
13+
14+
var config struct {
15+
Verbose bool
16+
UDPTimeout time.Duration
17+
}
18+
19+
func logf(f string, v ...interface{}) {
20+
if config.Verbose {
21+
log.Printf(f, v...)
22+
}
23+
}
24+
25+
func main() {
26+
27+
var flags struct {
28+
Client string
29+
Server string
30+
Cipher string
31+
Key string
32+
Socks string
33+
RedirTCP string
34+
RedirTCP6 string
35+
TCPTun string
36+
UDPTun string
37+
}
38+
39+
flag.BoolVar(&config.Verbose, "verbose", false, "verbose mode")
40+
flag.StringVar(&flags.Cipher, "cipher", "aes-128-gcm", "cipher to encrypt/decrypt")
41+
flag.StringVar(&flags.Key, "key", "", "secret key in hexadecimal")
42+
flag.StringVar(&flags.Server, "s", "", "server listen address")
43+
flag.StringVar(&flags.Client, "c", "", "client connect address")
44+
flag.StringVar(&flags.Socks, "socks", ":1080", "(client-only) SOCKS listen address")
45+
flag.StringVar(&flags.RedirTCP, "redir", "", "(client-only) redirect TCP from this address")
46+
flag.StringVar(&flags.RedirTCP6, "redir6", "", "(client-only) redirect TCP IPv6 from this address")
47+
flag.StringVar(&flags.TCPTun, "tcptun", "", "(client-only) TCP tunnel (laddr1=raddr1,laddr2=raddr2,...)")
48+
flag.StringVar(&flags.UDPTun, "udptun", "", "(client-only) UDP tunnel (laddr1=raddr1,laddr2=raddr2,...)")
49+
flag.DurationVar(&config.UDPTimeout, "udptimeout", 5*time.Minute, "UDP tunnel timeout")
50+
flag.Parse()
51+
52+
key, err := hex.DecodeString(flags.Key)
53+
if err != nil {
54+
log.Fatalf("failed to parse key: %v", err)
55+
}
56+
57+
streamCipher, packetCipher, err := pickCipher(flags.Cipher, key)
58+
if err != nil {
59+
log.Fatalf("failed to create cipher %s: %v", flags.Cipher, err)
60+
}
61+
62+
if flags.Client != "" { // client mode
63+
if flags.UDPTun != "" {
64+
for _, tun := range strings.Split(flags.UDPTun, ",") {
65+
p := strings.Split(tun, "=")
66+
go udpLocal(p[0], flags.Client, p[1], packetCipher)
67+
}
68+
}
69+
70+
if flags.TCPTun != "" {
71+
for _, tun := range strings.Split(flags.TCPTun, ",") {
72+
p := strings.Split(tun, "=")
73+
go tcpTun(p[0], flags.Client, p[1], streamCipher)
74+
}
75+
}
76+
77+
if flags.Socks != "" {
78+
go socksLocal(flags.Socks, flags.Client, streamCipher)
79+
}
80+
81+
if flags.RedirTCP != "" {
82+
go redirLocal(flags.RedirTCP, flags.Client, streamCipher)
83+
}
84+
85+
if flags.RedirTCP6 != "" {
86+
go redir6Local(flags.RedirTCP6, flags.Client, streamCipher)
87+
}
88+
} else if flags.Server != "" { // server mode
89+
go udpRemote(flags.Server, packetCipher)
90+
go tcpRemote(flags.Server, streamCipher)
91+
} else {
92+
flag.Usage()
93+
return
94+
}
95+
96+
sigCh := make(chan os.Signal, 1)
97+
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
98+
<-sigCh
99+
}

shadowaead/doc.go

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
Package shadowaead implements a simple AEAD-protected secure protocol.
3+
4+
In general, there are two types of connections: stream-oriented and packet-oriented.
5+
Stream-oriented connections (e.g. TCP) assume reliable and orderly delivery of bytes.
6+
Packet-oriented connections (e.g. UDP) assume unreliable and out-of-order delivery of packets,
7+
where each packet is either delivered intact or lost.
8+
9+
An encrypted stream starts with a nonce, followed by any number of encrypted records.
10+
Each encrypted record has the following structure:
11+
12+
[encrypted payload length]
13+
[payload length tag]
14+
[encrypted payload]
15+
[payload tag]
16+
17+
Payload length is 2-byte unsigned big-endian integer capped at 0x3FFF (16383).
18+
The higher 2 bits are reserved and must be set to zero. The first AEAD encrypt/decrypt
19+
operation uses the nonce at the beginning of the stream. After each encrypt/decrypt operation,
20+
the nonce is incremented by one as if it were an unsigned little-endian integer.
21+
22+
23+
Each encrypted packet transmitted on a packet-oriented connection has the following structure:
24+
25+
[nonce]
26+
[encrypted payload]
27+
[payload tag]
28+
29+
Packets are encrypted/decrypted independently.
30+
31+
In both stream-oriented and packet-oriented connections, length of nonce and tag varies
32+
depending on which AEAD is used. Nonces are assumed to be randomly generated and
33+
of sufficient length (at least 12 bytes).
34+
*/
35+
package shadowaead

shadowaead/packet.go

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package shadowaead
2+
3+
import (
4+
"crypto/cipher"
5+
"crypto/rand"
6+
"errors"
7+
"io"
8+
"net"
9+
)
10+
11+
// ErrShortPacket means that the packet is too short for a valid encrypted packet.
12+
var ErrShortPacket = errors.New("shadow: short packet")
13+
14+
// Pack encrypts plaintext using aead with a randomly generated nonce and
15+
// returns a slice of dst containing the encrypted packet and any error occurred.
16+
// Ensure len(dst) >= aead.NonceSize() + len(plaintext) + aead.Overhead().
17+
func Pack(dst, plaintext []byte, aead cipher.AEAD) ([]byte, error) {
18+
nsiz := aead.NonceSize()
19+
if len(dst) < nsiz+len(plaintext)+aead.Overhead() {
20+
return nil, io.ErrShortBuffer
21+
}
22+
23+
nonce := dst[:nsiz]
24+
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
25+
return nil, err
26+
}
27+
28+
b := aead.Seal(dst[nsiz:nsiz], nonce, plaintext, nil)
29+
return dst[:nsiz+len(b)], nil
30+
}
31+
32+
// Unpack decrypts pkt using aead and returns a slice of dst containing the decrypted payload and any error occurred.
33+
// Ensure len(dst) >= len(pkt) - aead.NonceSize() - aead.Overhead().
34+
func Unpack(dst, pkt []byte, aead cipher.AEAD) ([]byte, error) {
35+
nsiz := aead.NonceSize()
36+
37+
if len(pkt) < nsiz+aead.Overhead() {
38+
return nil, ErrShortPacket
39+
}
40+
41+
if len(dst) < len(pkt)-nsiz-aead.Overhead() {
42+
return nil, io.ErrShortBuffer
43+
}
44+
45+
b, err := aead.Open(dst[:0], pkt[:nsiz], pkt[nsiz:], nil)
46+
return b, err
47+
}
48+
49+
// packetConn encrypts net.packetConn with cipher.AEAD
50+
type packetConn struct {
51+
net.PacketConn
52+
cipher.AEAD
53+
}
54+
55+
// NewPacketConn wraps a net.PacketConn with AEAD protection.
56+
func NewPacketConn(c net.PacketConn, aead cipher.AEAD) net.PacketConn {
57+
return &packetConn{PacketConn: c, AEAD: aead}
58+
}
59+
60+
// WriteTo encrypts b and write to addr using the embedded PacketConn.
61+
func (c *packetConn) WriteTo(b []byte, addr net.Addr) (int, error) {
62+
buf := make([]byte, c.AEAD.NonceSize()+len(b)+c.AEAD.Overhead())
63+
buf, err := Pack(buf, b, c.AEAD)
64+
if err != nil {
65+
return 0, err
66+
}
67+
_, err = c.PacketConn.WriteTo(buf, addr)
68+
return len(b), err
69+
}
70+
71+
// ReadFrom reads from the embedded PacketConn and decrypts into b.
72+
func (c *packetConn) ReadFrom(b []byte) (int, net.Addr, error) {
73+
n, addr, err := c.PacketConn.ReadFrom(b)
74+
if err != nil {
75+
return n, addr, err
76+
}
77+
b, err = Unpack(b, b[:n], c.AEAD)
78+
return len(b), addr, err
79+
}

0 commit comments

Comments
 (0)