From c95794da1fb493788a8392a7b231856c1e1044d7 Mon Sep 17 00:00:00 2001 From: Russ Magee Date: Fri, 16 Aug 2019 23:16:40 -0700 Subject: [PATCH] Uncoupled kcp-go UDP support by moving into hkexnet/kcp.go TODO: cmdline param to set KCP symmetric key & salt at launch (consider also from a file to avoid putting inline in invocations, eg., init scripts) Signed-off-by: Russ Magee --- hkexnet/hkexnet.go | 20 ++----- hkexnet/kcp.go | 129 +++++++++++++++++++++++++++++++++++++++++++++ hkexsh/hkexsh.go | 12 ++--- hkexshd/hkexshd.go | 8 +-- 4 files changed, 144 insertions(+), 25 deletions(-) create mode 100644 hkexnet/kcp.go diff --git a/hkexnet/hkexnet.go b/hkexnet/hkexnet.go index c557589..5d38bc0 100644 --- a/hkexnet/hkexnet.go +++ b/hkexnet/hkexnet.go @@ -25,7 +25,6 @@ package hkexnet import ( "bytes" "crypto/cipher" - "crypto/sha1" "encoding/binary" "encoding/hex" "errors" @@ -41,9 +40,6 @@ import ( "sync" "time" - kcp "github.com/xtaci/kcp-go" - "golang.org/x/crypto/pbkdf2" - hkex "blitter.com/go/herradurakex" "blitter.com/go/hkexsh/logger" kyber "git.schwanenlied.me/yawning/kyber.git" @@ -699,9 +695,7 @@ func Dial(protocol string, ipport string, extensions ...string) (hc Conn, err er var c net.Conn if protocol == "kcp" { - kcpKey := pbkdf2.Key([]byte("demo pass"), []byte("demo salt"), 1024, 32, sha1.New) - block, _ := kcp.NewNoneBlockCrypt(kcpKey) - c, err = kcp.DialWithOptions(ipport, block, 10, 3) + c, err = kcpDial(ipport, extensions) if err != nil { return Conn{}, err } @@ -839,19 +833,16 @@ type HKExListener struct { // Listen for a connection // // See go doc net.Listen -func Listen(proto string, ipport string) (hl HKExListener, e error) { +func Listen(proto string, ipport string, extensions ...string) (hl HKExListener, e error) { if Log == nil { Init(false, "server", logger.LOG_DAEMON|logger.LOG_DEBUG) } - kcpKey := pbkdf2.Key([]byte("demo pass"), []byte("demo salt"), 1024, 32, sha1.New) - //var block kcp.BlockCrypt var lErr error var l net.Listener - + if proto == "kcp" { - block, _ := kcp.NewNoneBlockCrypt(kcpKey) - l, lErr = kcp.ListenWithOptions(ipport, block, 10, 3) + l, lErr = kcpListen(ipport, extensions) } else { l, lErr = net.Listen(proto, ipport) } @@ -886,11 +877,10 @@ func (hl HKExListener) Addr() net.Addr { func (hl *HKExListener) Accept() (hc Conn, err error) { var c net.Conn if hl.proto == "kcp" { - c, err = hl.l.(*kcp.Listener).AcceptKCP() + c, err = hl.AcceptKCP() if err != nil { return Conn{}, err } - logger.LogDebug(fmt.Sprintln("[kcp.Listener Accepted]")) } else { // Open raw Conn c diff --git a/hkexnet/kcp.go b/hkexnet/kcp.go new file mode 100644 index 0000000..be52650 --- /dev/null +++ b/hkexnet/kcp.go @@ -0,0 +1,129 @@ +package hkexnet + +import ( + "crypto/sha1" + "errors" + "fmt" + "net" + + "blitter.com/go/hkexsh/logger" + kcp "github.com/xtaci/kcp-go" + "golang.org/x/crypto/pbkdf2" +) + +const ( + KCP_NONE = iota + KCP_AES + KCP_BLOWFISH + KCP_CAST5 + KCP_SM4 + KCP_SALSA20 + KCP_SIMPLEXOR + KCP_TEA + KCP_3DES + KCP_TWOFISH + KCP_XTEA +) + +// for github.com/xtaci/kcp-go BlockCrypt alg selection +type KCPAlg uint8 + +var ( + kcpKeyBytes []byte = []byte("SET THIS") // symmetric crypto key for KCP (github.com/xtaci/kcp-go) if used + kcpSaltBytes []byte = []byte("ALSO SET THIS") +) + +func getKCPalgnum(extensions []string) (k KCPAlg) { + k = KCP_AES // default + var s string + for _, s = range extensions { + switch s { + case "KCP_NONE": + k = KCP_NONE + break //out of for + case "KCP_AES": + k = KCP_AES + break //out of for + case "KCP_BLOWFISH": + k = KCP_BLOWFISH + break //out of for + case "KCP_CAST5": + k = KCP_CAST5 + break //out of for + case "KCP_SM4": + k = KCP_SM4 + break //out of for + case "KCP_SALSA20": + k = KCP_SALSA20 + break //out of for + case "KCP_SIMPLEXOR": + k = KCP_SIMPLEXOR + break //out of for + case "KCP_TEA": + k = KCP_TEA + break //out of for + case "KCP_3DES": + k = KCP_3DES + break //out of for + case "KCP_TWOFISH": + k = KCP_TWOFISH + break //out of for + case "KCP_XTEA": + k = KCP_XTEA + break //out of for + } + } + logger.LogDebug(fmt.Sprintf("[KCP BlockCrypt '%s' activated]", s)) + return +} + +func SetKCPKeyAndSalt(key []byte, salt []byte) { + kcpKeyBytes = key + kcpSaltBytes = salt +} + +func _newKCPBlockCrypt(key []byte, extensions []string) (b kcp.BlockCrypt, e error) { + switch getKCPalgnum(extensions) { + case KCP_NONE: + return kcp.NewNoneBlockCrypt(key) + case KCP_AES: + return kcp.NewAESBlockCrypt(key) + case KCP_BLOWFISH: + return kcp.NewBlowfishBlockCrypt(key) + case KCP_CAST5: + return kcp.NewCast5BlockCrypt(key) + case KCP_SM4: + return kcp.NewSM4BlockCrypt(key) + case KCP_SALSA20: + return kcp.NewSalsa20BlockCrypt(key) + case KCP_SIMPLEXOR: + return kcp.NewSimpleXORBlockCrypt(key) + case KCP_TEA: + return kcp.NewTEABlockCrypt(key) + case KCP_3DES: + return kcp.NewTripleDESBlockCrypt(key) + case KCP_TWOFISH: + return kcp.NewTwofishBlockCrypt(key) + case KCP_XTEA: + return kcp.NewXTEABlockCrypt(key) + } + return nil, errors.New("Invalid KCP BlockCrypto specified") +} + +func kcpDial(ipport string, extensions []string) (c net.Conn, err error) { + kcpKey := pbkdf2.Key(kcpKeyBytes, kcpSaltBytes, 1024, 32, sha1.New) + block, be := _newKCPBlockCrypt([]byte(kcpKey), extensions) + _ = be + return kcp.DialWithOptions(ipport, block, 10, 3) +} + +func kcpListen(ipport string, extensions []string) (l net.Listener, err error) { + kcpKey := pbkdf2.Key(kcpKeyBytes, kcpSaltBytes, 1024, 32, sha1.New) + block, be := _newKCPBlockCrypt([]byte(kcpKey), extensions) + _ = be + return kcp.ListenWithOptions(ipport, block, 10, 3) +} + +func (hl *HKExListener) AcceptKCP() (c net.Conn, e error) { + return hl.l.(*kcp.Listener).AcceptKCP() +} diff --git a/hkexsh/hkexsh.go b/hkexsh/hkexsh.go index 597559e..2492240 100755 --- a/hkexsh/hkexsh.go +++ b/hkexsh/hkexsh.go @@ -47,7 +47,7 @@ var ( // wg controls when the goroutines handling client I/O complete wg sync.WaitGroup - kopt bool // set to use kcp (encrypted reliable UDP) instead of TCP + kcpMode string // set to a valid KCP BlockCrypt alg tag to use rather than TCP // Log defaults to regular syslog output (no -d) Log *logger.Writer @@ -627,7 +627,7 @@ func main() { flag.StringVar(&cipherAlg, "c", "C_AES_256", "`cipher` [\"C_AES_256\" | \"C_TWOFISH_128\" | \"C_BLOWFISH_64\" | \"C_CRYPTMT1\"]") flag.StringVar(&hmacAlg, "m", "H_SHA256", "`hmac` [\"H_SHA256\" | \"H_SHA512\"]") flag.StringVar(&kexAlg, "k", "KEX_HERRADURA512", "`kex` [\"KEX_HERRADURA{256/512/1024/2048}\" | \"KEX_KYBER{512/768/1024}\" | \"KEX_NEWHOPE\" | \"KEX_NEWHOPE_SIMPLE\"]") - flag.BoolVar(&kopt, "K", false, "set true to use KCP (github.com/xtaci/kcp-go) reliable UDP instead of TCP") + flag.StringVar(&kcpMode, "K", "unused", `set to one of ["KCP_NONE","KCP_AES", "KCP_BLOWFISH", "KCP_CAST5", "KCP_SM4", "KCP_SALSA20", "KCP_SIMPLEXOR", "KCP_TEA", "KCP_3DES", "KCP_TWOFISH", "KCP_XTEA"] to use KCP (github.com/xtaci/kcp-go) reliable UDP instead of TCP`) flag.UintVar(&port, "p", 2000, "`port`") //flag.StringVar(&authCookie, "a", "", "auth cookie") flag.BoolVar(&chaffEnabled, "e", true, "enable chaff pkts") @@ -821,12 +821,12 @@ func main() { cmdStr = string(copySrc) } } - + proto := "tcp" - if kopt { - proto = "kcp" + if kcpMode != "unused" { + proto = "kcp" } - conn, err := hkexnet.Dial(proto, server, cipherAlg, hmacAlg, kexAlg) + conn, err := hkexnet.Dial(proto, server, cipherAlg, hmacAlg, kexAlg, kcpMode) if err != nil { fmt.Println(err) exitWithStatus(3) diff --git a/hkexshd/hkexshd.go b/hkexshd/hkexshd.go index b4ae354..ae75617 100755 --- a/hkexshd/hkexshd.go +++ b/hkexshd/hkexshd.go @@ -39,7 +39,7 @@ var ( gitCommit string // set in -ldflags by build useSysLogin bool - kopt bool // set to use kcp (encrypted reliable UDP) instead of TCP + kcpMode string // set to a valid KCP BlockCrypt alg tag to use rather than TCP // Log - syslog output (with no -d) Log *logger.Writer @@ -444,7 +444,7 @@ func main() { flag.BoolVar(&vopt, "v", false, "show version") flag.StringVar(&laddr, "l", ":2000", "interface[:port] to listen") - flag.BoolVar(&kopt, "K", false, "set true to use KCP (github.com/xtaci/kcp-go) reliable UDP instead of TCP") + flag.StringVar(&kcpMode, "K", "unused", `set to one of ["KCP_NONE","KCP_AES", "KCP_BLOWFISH", "KCP_CAST5", "KCP_SM4", "KCP_SALSA20", "KCP_SIMPLEXOR", "KCP_TEA", "KCP_3DES", "KCP_TWOFISH", "KCP_XTEA"] to use KCP (github.com/xtaci/kcp-go) reliable UDP instead of TCP`) flag.BoolVar(&useSysLogin, "L", false, "use system login") flag.BoolVar(&chaffEnabled, "e", true, "enable chaff pkts") flag.UintVar(&chaffFreqMin, "f", 100, "chaff pkt freq min (msecs)") @@ -508,10 +508,10 @@ func main() { }() proto := "tcp" - if kopt { + if kcpMode != "unused" { proto = "kcp" } - l, err := hkexnet.Listen(proto, laddr) + l, err := hkexnet.Listen(proto, laddr, kcpMode) if err != nil { log.Fatal(err) }