Skip to content

Commit

Permalink
add some basic encrypt methods and support password
Browse files Browse the repository at this point in the history
  • Loading branch information
asche910 committed Oct 16, 2019
1 parent ee7ff74 commit 303c7af
Show file tree
Hide file tree
Showing 10 changed files with 224 additions and 31 deletions.
6 changes: 4 additions & 2 deletions client/flyclient.go
Expand Up @@ -6,6 +6,8 @@ type FlyClient struct {
Mode int
localhost string
Ports []string // ports[0] stands for the listening port; others are for reserve
Method string
Password string
protocol string // tcp or udp protocol
ServerAddr string

Expand All @@ -19,8 +21,8 @@ func (client *FlyClient) LocalHttpProxy(port string) {
fly.StartHttp(port)
}

func (client *FlyClient) Socks5ProxyForTCP(localPort, serverAddr string) {
fly.Socks5ForClientByTCP(localPort, serverAddr)
func (client *FlyClient) Socks5ProxyForTCP(localPort, serverAddr, method, key string) {
fly.Socks5ForClientByTCP(localPort, serverAddr, method, key)
}

func (client *FlyClient) Socks5ProxyForUDP(localPort, serverAddr string) {
Expand Down
26 changes: 24 additions & 2 deletions cmd/client/client.go
Expand Up @@ -30,7 +30,7 @@ func main() {
case 2:
flyClient.LocalSocks5Proxy(flyClient.Ports[0])
case 3:
flyClient.Socks5ProxyForTCP(flyClient.Ports[0], flyClient.ServerAddr)
flyClient.Socks5ProxyForTCP(flyClient.Ports[0], flyClient.ServerAddr, flyClient.Method, flyClient.Password)
case 4:
flyClient.Socks5ProxyForUDP(flyClient.Ports[0], flyClient.ServerAddr)
case 5:
Expand All @@ -48,8 +48,12 @@ func printHelp() {
'socks5-tcp', 'socks5-udp', 'forward']
-L, --listen choose which port(s) to listen or forward
-S, --server the server address client connect to
-m, --method choose a encrypt method, which must be one of ['aes-128-cfb','aes-192-cfb',
'aes-256-cfb', 'aes-128-ctr', 'aes-192-ctr', 'aes-256-ctr', 'rc4-md5',
'rc4-md5-6', 'chacha20', 'chacha20-ietf'], default is 'aes-256-cfb'
-P, --password password of server
-V, --verbose output detail info
-l, --logs output detail info to logs file
-l, --logs output detail info to logs file
-H, --help show detail usage
Mail bug reports and suggestions to <asche910@gmail.com>
Expand Down Expand Up @@ -110,6 +114,24 @@ func parseArgs(args []string) {
printHelp()
os.Exit(1)
}
case "-m", "--method":
if len(args) > 1 && !strings.HasPrefix(args[1], "-") {
flyClient.Method = args[1]
parseArgs(args[2:])
} else {
fmt.Println("fly: no password found!")
printHelp()
os.Exit(1)
}
case "--password", "-P":
if len(args) > 1 && !strings.HasPrefix(args[1], "-") {
flyClient.Password = args[1]
parseArgs(args[2:])
} else {
fmt.Println("fly: no password found!")
printHelp()
os.Exit(1)
}
case "--verbose", "-V":
logs.EnableDebug(true)
parseArgs(args[1:])
Expand Down
26 changes: 24 additions & 2 deletions cmd/server/server.go
Expand Up @@ -31,7 +31,7 @@ func main() {
case 2:
flyServer.LocalSocks5Proxy(flyServer.Ports[0])
case 3:
flyServer.Socks5ProxyForTCP(flyServer.Ports[0])
flyServer.Socks5ProxyForTCP(flyServer.Ports[0], flyServer.Method, flyServer.Password)
case 4:
flyServer.Socks5ProxyForUDP(flyServer.Ports[0])
case 5:
Expand All @@ -48,8 +48,12 @@ func printHelp() {
-M, --mode choose which mode to run. the mode must be one of['http', 'socks5',
'socks5-tcp', 'socks5-udp', 'forward']
-L, --listen choose which port(s) to listen or forward
-m, --method choose a encrypt method, which must be one of ['aes-128-cfb','aes-192-cfb',
'aes-256-cfb', 'aes-128-ctr', 'aes-192-ctr', 'aes-256-ctr', 'rc4-md5',
'rc4-md5-6', 'chacha20', 'chacha20-ietf'], default is 'aes-256-cfb'
-P, --password password for client connecting
-V, --verbose output detail info
-l, --logs output detail info to logs file
-l, --logs output detail info to logs file
-H, --help show detail usage
Mail bug reports and suggestions to <asche910@gmail.com>
Expand Down Expand Up @@ -101,6 +105,24 @@ func parseArgs(args []string) {
printHelp()
os.Exit(1)
}
case "-m", "--method":
if len(args) > 1 && !strings.HasPrefix(args[1], "-") {
flyServer.Method = args[1]
parseArgs(args[2:])
} else {
fmt.Println("fly: no password found!")
printHelp()
os.Exit(1)
}
case "--password", "-P":
if len(args) > 1 && !strings.HasPrefix(args[1], "-") {
flyServer.Password = args[1]
parseArgs(args[2:])
} else {
fmt.Println("fly: no password found!")
printHelp()
os.Exit(1)
}
case "--verbose", "-V":
logs.EnableDebug(true)
parseArgs(args[1:])
Expand Down
117 changes: 106 additions & 11 deletions fly/cipher.go
Expand Up @@ -3,35 +3,130 @@ package fly
import (
"crypto/aes"
"crypto/cipher"
"crypto/md5"
"crypto/rc4"
"fmt"

"github.com/aead/chacha20"
)

const key = "asche910-flynet-"
var key = "asche910-flynet-"

type EncOrDec int

const (
ENC EncOrDec = iota
DEC
)

var (
commonIV = []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}
IV = []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}
)

var cipherMap = map[string]*cipherEntity{
"aes-128-cfb": {16, 16, newAESCFBStream},
"aes-192-cfb": {24, 16, newAESCFBStream},
"aes-256-cfb": {32, 16, newAESCFBStream},
"aes-128-ctr": {16, 16, newAESCTRStream},
"aes-192-ctr": {24, 16, newAESCTRStream},
"aes-256-ctr": {32, 16, newAESCTRStream},
"rc4-md5": {16, 16, newRC4MD5Stream},
"rc4-md5-6": {16, 6, newRC4MD5Stream},
"chacha20": {32, 8, newChaCha20Stream},
"chacha20-ietf": {32, 12, newChaCha20Stream},
}

// generate a fixed length key
func genKey(rawKey string, len int) []byte {
key := make([]byte, 256)
cur := 0
for cur < len {
sum := md5.Sum([]byte(fmt.Sprintf("%s%d", rawKey, cur)))
copy(key[cur:cur+16], sum[:])
cur += 16
}
return key[:len]
}

type Cipher struct {
encoder cipher.Stream
decoder cipher.Stream
key []byte
method string
}

func NewCipherInstance() *Cipher{
c, err := aes.NewCipher([]byte(key))
func (cipher *Cipher) Encrypt(dst, src []byte) {
cipher.encoder.XORKeyStream(dst, src)
}

func (cipher *Cipher) Decrypt(dst, src []byte) {
cipher.decoder.XORKeyStream(dst, src)
}

// a detail encrypt or decrypt method
type cipherEntity struct {
keyLen int
ivLen int
newStream func(key, iv []byte, eod EncOrDec) cipher.Stream
}

func NewCipherInstance(secretKey, method string) *Cipher {
if secretKey == "" {
secretKey = key
}
entity := cipherMap[method]
if entity == nil {
entity = cipherMap["aes-256-cfb"]
}
key := genKey(secretKey, entity.keyLen)
newIV := IV[:entity.ivLen]
enc := entity.newStream(key, newIV, ENC)
dec := entity.newStream(key, newIV, DEC)
return &Cipher{encoder: enc, decoder: dec}
}

func newAESCFBStream(key, iv []byte, eod EncOrDec) cipher.Stream {
block, err := aes.NewCipher(key)
if err != nil {
logger.Println("aes.NewCipher failed!", err)
return nil
}
if eod == ENC {
enc := cipher.NewCFBEncrypter(block, IV)
return enc
} else {
dec := cipher.NewCFBDecrypter(block, IV)
return dec
}
enc := cipher.NewCFBEncrypter(c, commonIV)
dec := cipher.NewCFBDecrypter(c, commonIV)
return &Cipher{encoder:enc, decoder:dec}
}

func (cipher *Cipher) Encrypt(dst, src []byte) {
cipher.encoder.XORKeyStream(dst, src)
func newAESCTRStream(key, iv []byte, eod EncOrDec) cipher.Stream {
block, err := aes.NewCipher(key)
if err != nil {
logger.Println("aes.NewCipher failed!", err)
return nil
}
return cipher.NewCTR(block, iv)
}

func (cipher *Cipher) Decrypt(dst, src []byte) {
cipher.decoder.XORKeyStream(dst, src)
func newChaCha20Stream(key, iv []byte, eod EncOrDec) cipher.Stream {
stream, err := chacha20.NewCipher(iv, key)
if err != nil {
logger.Println("chacha20.NewCipher failed!", err)
return nil
}
return stream
}

func newRC4MD5Stream(key, iv []byte, eod EncOrDec) cipher.Stream {
hs := md5.New()
hs.Write(key)
hs.Write(iv)
rc4key := hs.Sum(nil)
stream, err := rc4.NewCipher(rc4key)
if err != nil {
logger.Println("rc4.NewCipher failed!", err)
return nil
}
return stream
}
48 changes: 48 additions & 0 deletions fly/cipher_test.go
@@ -0,0 +1,48 @@
package fly

import (
"fmt"
"testing"
)

const text = "hello,world!"

func testCipher(t *testing.T, method string) {
textLen := len(text)
cipherInstance := NewCipherInstance(key, method)

textBuff := make([]byte, textLen)
encryptBuff := make([]byte, textLen)

cipherInstance.Encrypt(encryptBuff, []byte(text))
fmt.Println("after", encryptBuff)
cipherInstance.Decrypt(textBuff, encryptBuff)
if string(textBuff) != text {
t.Error(method, " test failed!")
}
}

func TestCipher(t *testing.T) {
key := "123456"
keyLen := len(key)
buff := make([]byte, 1024)
cipherInstance := NewCipherInstance(key, "aes-128-cfb")
cipherInstance.encoder.XORKeyStream(buff, []byte(key))
fmt.Println("before", string(buff[:keyLen]))
cipherInstance.decoder.XORKeyStream(buff, buff[:keyLen])
fmt.Println("after", string(buff[:keyLen]))
}

func TestAESCTR(t *testing.T) {
testCipher(t, "aes-128-ctr")
}

func TestChacha20(t *testing.T) {
testCipher(t, "chacha20")
//testCipher(t, "chacha20-ietf")
}

func TestRC4MD5(t *testing.T) {
testCipher(t, "rc4-md5")
//testCipher(t, "rc4-md5-6")
}
4 changes: 2 additions & 2 deletions fly/conn.go
Expand Up @@ -17,13 +17,13 @@ func NewConn(con net.Conn, cipher *Cipher) *Conn {
}

// dial server and send request addr of client
func DialWithAddr(server string, addr []byte) *Conn {
func DialWithAddr(server, method, key string, addr []byte) *Conn {
conn, err := net.Dial("tcp", server)
if err != nil {
logger.Println("Dial server failed!", err)
return nil
}
newConn := NewConn(conn, NewCipherInstance())
newConn := NewConn(conn, NewCipherInstance(key, method))
if _, err := newConn.Write(addr); err != nil {
logger.Println("write addr to server failed!", err)
return nil
Expand Down
1 change: 0 additions & 1 deletion fly/error_utils.go
Expand Up @@ -10,7 +10,6 @@ var logger *log.Logger

func InitLog() {
logger = logs.GetLogger()

}

// just check error and print if err is not nil
Expand Down
4 changes: 2 additions & 2 deletions fly/relay.go
Expand Up @@ -48,10 +48,10 @@ func RelayTraffic(dst, src net.Conn) {
fmt.Println(err)
break
}
fmt.Println("Read", n)
//logger.Println("Read", n)
if n > 0 {
if n, err = dst.Write(buff[:n]); err != nil {
fmt.Println(err)
logger.Println(err)
break
}
}
Expand Down

0 comments on commit 303c7af

Please sign in to comment.