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 <rmagee@gmail.com>
This commit is contained in:
Russ Magee 2019-08-16 23:16:40 -07:00
parent d7dbcd8fdf
commit c95794da1f
4 changed files with 144 additions and 25 deletions

View file

@ -25,7 +25,6 @@ package hkexnet
import ( import (
"bytes" "bytes"
"crypto/cipher" "crypto/cipher"
"crypto/sha1"
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"errors" "errors"
@ -41,9 +40,6 @@ import (
"sync" "sync"
"time" "time"
kcp "github.com/xtaci/kcp-go"
"golang.org/x/crypto/pbkdf2"
hkex "blitter.com/go/herradurakex" hkex "blitter.com/go/herradurakex"
"blitter.com/go/hkexsh/logger" "blitter.com/go/hkexsh/logger"
kyber "git.schwanenlied.me/yawning/kyber.git" 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 var c net.Conn
if protocol == "kcp" { if protocol == "kcp" {
kcpKey := pbkdf2.Key([]byte("demo pass"), []byte("demo salt"), 1024, 32, sha1.New) c, err = kcpDial(ipport, extensions)
block, _ := kcp.NewNoneBlockCrypt(kcpKey)
c, err = kcp.DialWithOptions(ipport, block, 10, 3)
if err != nil { if err != nil {
return Conn{}, err return Conn{}, err
} }
@ -839,19 +833,16 @@ type HKExListener struct {
// Listen for a connection // Listen for a connection
// //
// See go doc net.Listen // 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 { if Log == nil {
Init(false, "server", logger.LOG_DAEMON|logger.LOG_DEBUG) 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 lErr error
var l net.Listener var l net.Listener
if proto == "kcp" { if proto == "kcp" {
block, _ := kcp.NewNoneBlockCrypt(kcpKey) l, lErr = kcpListen(ipport, extensions)
l, lErr = kcp.ListenWithOptions(ipport, block, 10, 3)
} else { } else {
l, lErr = net.Listen(proto, ipport) l, lErr = net.Listen(proto, ipport)
} }
@ -886,11 +877,10 @@ func (hl HKExListener) Addr() net.Addr {
func (hl *HKExListener) Accept() (hc Conn, err error) { func (hl *HKExListener) Accept() (hc Conn, err error) {
var c net.Conn var c net.Conn
if hl.proto == "kcp" { if hl.proto == "kcp" {
c, err = hl.l.(*kcp.Listener).AcceptKCP() c, err = hl.AcceptKCP()
if err != nil { if err != nil {
return Conn{}, err return Conn{}, err
} }
logger.LogDebug(fmt.Sprintln("[kcp.Listener Accepted]")) logger.LogDebug(fmt.Sprintln("[kcp.Listener Accepted]"))
} else { } else {
// Open raw Conn c // Open raw Conn c

129
hkexnet/kcp.go Normal file
View file

@ -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()
}

View file

@ -47,7 +47,7 @@ var (
// wg controls when the goroutines handling client I/O complete // wg controls when the goroutines handling client I/O complete
wg sync.WaitGroup 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 defaults to regular syslog output (no -d)
Log *logger.Writer 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(&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(&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.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.UintVar(&port, "p", 2000, "`port`")
//flag.StringVar(&authCookie, "a", "", "auth cookie") //flag.StringVar(&authCookie, "a", "", "auth cookie")
flag.BoolVar(&chaffEnabled, "e", true, "enable chaff pkts") flag.BoolVar(&chaffEnabled, "e", true, "enable chaff pkts")
@ -823,10 +823,10 @@ func main() {
} }
proto := "tcp" proto := "tcp"
if kopt { if kcpMode != "unused" {
proto = "kcp" proto = "kcp"
} }
conn, err := hkexnet.Dial(proto, server, cipherAlg, hmacAlg, kexAlg) conn, err := hkexnet.Dial(proto, server, cipherAlg, hmacAlg, kexAlg, kcpMode)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
exitWithStatus(3) exitWithStatus(3)

View file

@ -39,7 +39,7 @@ var (
gitCommit string // set in -ldflags by build gitCommit string // set in -ldflags by build
useSysLogin bool 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 - syslog output (with no -d)
Log *logger.Writer Log *logger.Writer
@ -444,7 +444,7 @@ func main() {
flag.BoolVar(&vopt, "v", false, "show version") flag.BoolVar(&vopt, "v", false, "show version")
flag.StringVar(&laddr, "l", ":2000", "interface[:port] to listen") 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(&useSysLogin, "L", false, "use system login")
flag.BoolVar(&chaffEnabled, "e", true, "enable chaff pkts") flag.BoolVar(&chaffEnabled, "e", true, "enable chaff pkts")
flag.UintVar(&chaffFreqMin, "f", 100, "chaff pkt freq min (msecs)") flag.UintVar(&chaffFreqMin, "f", 100, "chaff pkt freq min (msecs)")
@ -508,10 +508,10 @@ func main() {
}() }()
proto := "tcp" proto := "tcp"
if kopt { if kcpMode != "unused" {
proto = "kcp" proto = "kcp"
} }
l, err := hkexnet.Listen(proto, laddr) l, err := hkexnet.Listen(proto, laddr, kcpMode)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }