Compare commits

..

No commits in common. "master" and "v0.9.8" have entirely different histories.

23 changed files with 285 additions and 2643 deletions

View File

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2017 - 2025 Russell Magee (xs/xsd/xsnet/xspasswd) Copyright (c) 2017 - 2021 Russell Magee (xs/xsd/xsnet/xspasswd)
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -1,4 +1,4 @@
VERSION := 0.9.15 VERSION := 0.9.8
.PHONY: lint vis clean common client server passwd\ .PHONY: lint vis clean common client server passwd\
subpkgs install uninstall reinstall scc subpkgs install uninstall reinstall scc
@ -43,10 +43,13 @@ ifeq ($(GOOS),)
endif endif
ifeq ($(GOOS),windows) ifeq ($(GOOS),windows)
INSTPREFIX = /usr ifeq ($(MSYSTEM),MSYS)
else WIN_MSYS=1
INSTPREFIX = /usr/local
endif endif
endif
INSTPREFIX = /usr/local
all: common client server all: common client server
@ -70,7 +73,7 @@ tools:
common: common:
$(GO) build . $(GO) build .
go install -a . go install .
client: common client: common
@ -78,7 +81,7 @@ client: common
server: common server: common
ifeq ($(GOOS),windows) ifeq ($(MSYSTEM),MSYS)
echo "Build of xsd server for Windows not yet supported" echo "Build of xsd server for Windows not yet supported"
else else
$(MAKE) BUILDOPTS=$(BUILDOPTS) -C xsd $(MAKE) BUILDOPTS=$(BUILDOPTS) -C xsd
@ -103,10 +106,13 @@ lint:
reinstall: uninstall install reinstall: uninstall install
install: install:
ifeq ($(GOOS),windows) echo "WIN_MSYS:" $(WIN_MSYS)
cp xs/xs $(INSTPREFIX)/bin/xs ifdef WIN_MSYS
cp xs/xs $(INSTPREFIX)/bin/xc cp xs/mintty_wrapper.sh $(INSTPREFIX)/bin/xs
@echo "Install of xsd server for Windows not yet supported" cp xs/mintty_wrapper.sh $(INSTPREFIX)/bin/xc
cp xs/xs $(INSTPREFIX)/bin/_xs
cp xs/xs $(INSTPREFIX)/bin/_xc
echo "Install of xsd server for Windows not yet supported"
else else
cp xs/xs $(INSTPREFIX)/bin cp xs/xs $(INSTPREFIX)/bin
cd $(INSTPREFIX)/bin && ln -s xs xc && cd - cd $(INSTPREFIX)/bin && ln -s xs xc && cd -
@ -114,7 +120,8 @@ else
endif endif
uninstall: uninstall:
rm -f $(INSTPREFIX)/bin/xs $(INSTPREFIX)/bin/xc rm -f $(INSTPREFIX)/bin/xs $(INSTPREFIX)/bin/xc \
$(INSTPREFIX)/bin/_xs $(INSTPREFIX)/bin/_xc
ifndef $(WIN_MSYS) ifndef $(WIN_MSYS)
rm -f $(INSTPREFIX)/sbin/xsd rm -f $(INSTPREFIX)/sbin/xsd
endif endif

View File

@ -3,7 +3,6 @@
# XS # XS
![last build status](https://bacillus.blitter.com/onPush-xs-build/lastStatusIcon) ![last build status](https://bacillus.blitter.com/onPush-xs-build/lastStatusIcon)
![terminal screenshot on MSYS64](https://blitter.com/~russtopia/files/xs-msys64.png)
-- --
XS (**X**perimental **S**hell) is a simple alternative to ssh (<5% total SLOCC) written from scratch in Go. XS (**X**perimental **S**hell) is a simple alternative to ssh (<5% total SLOCC) written from scratch in Go.
@ -45,12 +44,10 @@ Currently supported session algorithms:
* Blowfish-64 * Blowfish-64
* CryptMTv1 (64bit) (https://eprint.iacr.org/2005/165.pdf) * CryptMTv1 (64bit) (https://eprint.iacr.org/2005/165.pdf)
* ChaCha20 (https://github.com/aead/chacha20) * ChaCha20 (https://github.com/aead/chacha20)
* HOPSCOTCH (https://gogs.blitter.com/Russtopia/hopscotch)
[HMAC] [HMAC]
* HMAC-SHA256 * HMAC-SHA256
* HMAC-SHA512 * HMAC-SHA512
* WHIRLPOOL
*** ***
**A Note on 'cryptographic agility'** **A Note on 'cryptographic agility'**
@ -95,6 +92,18 @@ KYBER IND-CCA-2 KEM
As of this time (Oct 2018) Kyber is one of the candidate algorithms submitted to the [NIST post-quantum cryptography project](https://csrc.nist.gov/Projects/Post-Quantum-Cryptography). The authors recommend using it in "... so-called hybrid mode in combination with established "pre-quantum" security; for example in combination with elliptic-curve Diffie-Hellman." THIS PROJECT DOES NOT DO THIS (in case you didn't notice yet, THIS PROJECT IS EXPERIMENTAL.) As of this time (Oct 2018) Kyber is one of the candidate algorithms submitted to the [NIST post-quantum cryptography project](https://csrc.nist.gov/Projects/Post-Quantum-Cryptography). The authors recommend using it in "... so-called hybrid mode in combination with established "pre-quantum" security; for example in combination with elliptic-curve Diffie-Hellman." THIS PROJECT DOES NOT DO THIS (in case you didn't notice yet, THIS PROJECT IS EXPERIMENTAL.)
### Dependencies:
* Recent version of go (tested, at various times, with go-1.9 to go-1.12.4)
* [github.com/mattn/go-isatty](http://github.com/mattn/go-isatty) //terminal tty detection
* [github.com/kr/pty](http://github.com/kr/pty) //unix pty control (server pty connections)
* [github.com/jameskeane/bcrypt](http://github.com/jameskeane/bcrypt) //password storage/auth
* [blitter.com/go/goutmp](https://gogs.blitter.com/RLabs/goutmp) // wtmp/lastlog C bindings for user accounting
* [https://gitlab.com/yawning/kyber](https://gogs.blitter.com/RLabs/kyber) // golang Kyber KEM
* [https://gitlab.com/yawning/kyber](https://gogs.blitter.com/RLabs/newhope) // golang NEWHOPE,NEWHOPE-SIMPLE KEX
* [blitter.com/go/mtwist](https://gogs.blitter.com/RLabs/mtwist) // 64-bit Mersenne Twister PRNG
* [blitter.com/go/cryptmt](https://gogs.blitter.com/RLabs/cryptmt) // CryptMTv1 stream cipher
### Installing ### Installing
@ -188,17 +197,15 @@ or is interrupted.
### Setting up an 'authtoken' for scripted (password-free) logins ### Setting up an 'authtoken' for scripted (password-free) logins
Use the -g option of xs to request a token from the remote server, which will return a Use the -g option of xs to request a token from the remote server, which will return a
hostname:token string. Place this string into $HOME/.config/xs/.xs_id to allow logins without hostname:token string. Place this string into $HOME/.xs_id to allow logins without
entering a password (obviously, $HOME/.config/xs/.xs_id on both server and client for the user entering a password (obviously, $HOME/.xs_id on both server and client for the user
should *not* be world-readable.) should *not* be world-readable.)
``` ```
$ xs -g user@host.net >>~/.config/xs/.xs_id $ xs -g user@host.net >~/.xs_id
``` ```
[enter password blindly, authtoken entry will be stored in ~/.config/xs/.xs_id] [enter password blindly, authtoken entry will be stored in ~/.xs_id]
NOTE you may need to remove older entries for the same host if this is not the first time you have added
it to your .xs_id file.
### File Copying using xc ### File Copying using xc
@ -211,12 +218,6 @@ If no leading / is specified in src-or-dest-path, it is assumed to be relative t
remote user. File operations are all performed as the remote user, so account permissions apply remote user. File operations are all performed as the remote user, so account permissions apply
as expected. as expected.
When running under MSYS2, one must set the MINGW_ROOT environment variable to assist in
determining how to convert Windows paths to UNIX-style paths. This should be the installation path
of one's MSYS2 environment (eg., _C:/msys2_). Go's stdlib, under the hood, still uses Windows
style paths (drive letters and all) to locate other executables and _xc_ uses _tar_ as part of the copy
functionality.
Local (client) to remote (server) copy: Local (client) to remote (server) copy:
``` ```
$ xc fileA /some/where/fileB /some/where/else/dirC joebloggs@host-or-ip:remoteDir $ xc fileA /some/where/fileB /some/where/else/dirC joebloggs@host-or-ip:remoteDir

38
auth.go Normal file → Executable file
View File

@ -2,7 +2,7 @@ package xs
// Package xs - a secure terminal client/server written from scratch in Go // Package xs - a secure terminal client/server written from scratch in Go
// //
// Copyright (c) 2017-2025 Russell Magee // Copyright (c) 2017-2020 Russell Magee
// Licensed under the terms of the MIT license (see LICENSE.mit in this // Licensed under the terms of the MIT license (see LICENSE.mit in this
// distribution) // distribution)
// //
@ -23,7 +23,6 @@ import (
"runtime" "runtime"
"strings" "strings"
"blitter.com/go/xs/xsnet"
"github.com/jameskeane/bcrypt" "github.com/jameskeane/bcrypt"
passlib "gopkg.in/hlandau/passlib.v1" passlib "gopkg.in/hlandau/passlib.v1"
) )
@ -53,7 +52,7 @@ func VerifyPass(ctx *AuthCtx, user, password string) (bool, error) {
} else if runtime.GOOS == "freebsd" { } else if runtime.GOOS == "freebsd" {
pwFileName = "/etc/master.passwd" pwFileName = "/etc/master.passwd"
} else { } else {
return false, errors.New("Unsupported platform") pwFileName = "unsupported"
} }
pwFileData, e := ctx.reader(pwFileName) pwFileData, e := ctx.reader(pwFileName)
if e != nil { if e != nil {
@ -155,7 +154,7 @@ func AuthUserByPasswd(ctx *AuthCtx, username string, auth string, fname string)
// ------------- End xs-local passwd auth routine(s) ----------- // ------------- End xs-local passwd auth routine(s) -----------
// AuthUserByToken checks user login information against an auth token. // AuthUserByToken checks user login information against an auth token.
// Auth tokens are stored in each user's $HOME/.config/xs/.xs_id and are requested // Auth tokens are stored in each user's $HOME/.xs_id and are requested
// via the -g option. // via the -g option.
// The function also check system /etc/passwd to cross-check the user // The function also check system /etc/passwd to cross-check the user
// actually exists. // actually exists.
@ -173,9 +172,9 @@ func AuthUserByToken(ctx *AuthCtx, username string, connhostname string, auth st
return false return false
} }
b, e := ctx.reader(fmt.Sprintf("%s/%s", u.HomeDir, xsnet.XS_ID_AUTHTOKFILE)) b, e := ctx.reader(fmt.Sprintf("%s/.xs_id", u.HomeDir))
if e != nil { if e != nil {
log.Printf("INFO: Cannot read %s/%s\n", u.HomeDir, xsnet.XS_ID_AUTHTOKFILE) log.Printf("INFO: Cannot read %s/.xs_id\n", u.HomeDir)
return false return false
} }
@ -215,39 +214,18 @@ func AuthUserByToken(ctx *AuthCtx, username string, connhostname string, auth st
return return
} }
func GroomFsPath(path string) (ret string) {
pathRoot := os.Getenv("MINGW_ROOT")
if pathRoot != "" {
ret = path[len(pathRoot):]
ret = strings.ReplaceAll(ret, "\\", "/")
} else {
ret = path
}
//fmt.Printf("groomed fspath:%v\n", ret)
return
}
func GetTool(tool string) (ret string) { func GetTool(tool string) (ret string) {
cmdSuffix := "" ret = "/bin/" + tool
pathRoot := os.Getenv("MINGW_ROOT")
if pathRoot != "" {
cmdSuffix = ".exe"
}
//fmt.Printf("pathRoot:%v cmdSuffix:%v\n", pathRoot, cmdSuffix)
ret = pathRoot + "/bin/" + tool + cmdSuffix
_, err := os.Stat(ret) _, err := os.Stat(ret)
if err == nil { if err == nil {
return ret return ret
} }
ret = pathRoot + "/usr/bin/" + tool + cmdSuffix ret = "/usr/bin/" + tool
_, err = os.Stat(ret) _, err = os.Stat(ret)
if err == nil { if err == nil {
return ret return ret
} }
ret = pathRoot + "/usr/local/bin/" + tool + cmdSuffix ret = "/usr/local/bin/" + tool
_, err = os.Stat(ret) _, err = os.Stat(ret)
if err == nil { if err == nil {
return ret return ret

View File

@ -5,7 +5,7 @@
export GOPATH="${HOME}/go" export GOPATH="${HOME}/go"
export PATH=/usr/local/bin:/usr/bin:/usr/lib/ccache/bin:/bin:$GOPATH/bin export PATH=/usr/local/bin:/usr/bin:/usr/lib/ccache/bin:/bin:$GOPATH/bin
unset GO111MODULE unset GO111MODULE
#export GOPROXY="direct" export GOPROXY="direct"
#!# GOCACHE will be phased out in v1.12. [github.com/golang/go/issues/26809] #!# GOCACHE will be phased out in v1.12. [github.com/golang/go/issues/26809]
#!export GOCACHE="${HOME}/.cache/go-build" #!export GOCACHE="${HOME}/.cache/go-build"
@ -25,16 +25,6 @@ echo "Building most recent push on branch $branch"
git checkout "$branch" git checkout "$branch"
ls ls
#!############
#!stage "GoMod"
#!############
#!go clean -modcache
#!
#!rm -f go.{mod,sum}
#!go mod init blitter.com/go/xs
#!go mod tidy
#!echo "---"
############ ############
stage "Build" stage "Build"
############ ############
@ -42,29 +32,26 @@ echo "Invoking 'make clean' ..."
make clean make clean
echo "Invoking 'make all' ..." echo "Invoking 'make all' ..."
make all make all
echo "---"
############ ############
stage "Lint" stage "Lint"
############ ############
make lint make lint
echo "---"
############ ############
stage "UnitTests" stage "UnitTests"
############ ############
go test -v . go test -v .
echo "---"
############ ############
stage "Test(Authtoken)" stage "Test(Authtoken)"
############ ############
if [ -f ~/.config/xs/.xs_id ]; then if [ -f ~/.xs_id ]; then
echo "Clearing test user $USER .xs_id file ..." echo "Clearing test user $USER ~/.xs_id file ..."
mv ~/.config/xs/.xs_id ~/.config/xs/.xs_id.bak mv ~/.xs_id ~/.xs_id.bak
fi fi
echo "Setting dummy authtoken in .xs_id ..." echo "Setting dummy authtoken in ~/.xs_id ..."
echo "localhost:${USER}:asdfasdfasdf" >~/.config/xs/.xs_id echo "localhost:${USER}:asdfasdfasdf" >~/.xs_id
echo "Performing remote command on @localhost via authtoken login ..." echo "Performing remote command on @localhost via authtoken login ..."
tokentest=$(timeout 10 xs -x "echo -n FOO" @localhost) tokentest=$(timeout 10 xs -x "echo -n FOO" @localhost)
if [ "${tokentest}" != "FOO" ]; then if [ "${tokentest}" != "FOO" ]; then
@ -74,7 +61,6 @@ else
echo "client cmd performed OK." echo "client cmd performed OK."
unset tokentest unset tokentest
fi fi
echo "---"
############ ############
stage "Test(xc S->C)" stage "Test(xc S->C)"
@ -99,25 +85,22 @@ else
echo "FAILED!" echo "FAILED!"
exit $stat exit $stat
fi fi
echo "---"
############ ############
stage "Test(xc C->S)" stage "Test(xc C->S)"
############ ############
echo "TODO ..." echo "TODO ..."
if [ -f ~/.config/xs/.xs_id.bak ]; then if [ -f ~/.xs_id.bak ]; then
echo "Restoring test user $USER .xs_id file ..." echo "Restoring test user $USER ~/.xs_id file ..."
mv ~/.config/xs/.xs_id.bak ~/.config/xs/.xs_id mv ~/.xs_id.bak ~/.xs_id
fi fi
echo "---"
############ ############
stage "Artifacts" stage "Artifacts"
############ ############
echo -n "Creating tarfile ..." echo -n "Creating tarfile ..."
tar -cz --exclude=.git --exclude=cptest -f ${BACILLUS_ARTFDIR}/xs.tgz . tar -cz --exclude=.git --exclude=cptest -f ${BACILLUS_ARTFDIR}/xs.tgz .
echo "---"
############ ############
stage "Cleanup" stage "Cleanup"

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
// Package xs - a secure terminal client/server written from scratch in Go // Package xs - a secure terminal client/server written from scratch in Go
// //
// Copyright (c) 2017-2025 Russell Magee // Copyright (c) 2017-2020 Russell Magee
// Licensed under the terms of the MIT license (see LICENSE.mit in this // Licensed under the terms of the MIT license (see LICENSE.mit in this
// distribution) // distribution)
// //

50
go.mod
View File

@ -1,38 +1,38 @@
module blitter.com/go/xs module blitter.com/go/xs
go 1.24.0 go 1.20
toolchain go1.24.11
require ( require (
blitter.com/go/cryptmt v1.0.3 blitter.com/go/chacha20 v0.0.0-20200130200441-214e4085f54c
blitter.com/go/cryptmt v1.0.2
blitter.com/go/goutmp v1.0.6 blitter.com/go/goutmp v1.0.6
blitter.com/go/herradurakex v1.0.1 blitter.com/go/groestl v0.0.0-20220410000905-c4decbf31d64
blitter.com/go/hopscotch v0.2.0 blitter.com/go/herradurakex v1.0.0
blitter.com/go/kyber v1.0.0 blitter.com/go/hopscotch v0.1.1
blitter.com/go/newhope v1.0.0 blitter.com/go/kyber v0.0.0-20200130200857-6f2021cb88d9
blitter.com/go/mtwist v1.0.1
blitter.com/go/newhope v0.0.0-20200130200750-192fc08a8aae
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da
github.com/creack/pty v1.1.24 github.com/creack/pty v1.1.18
github.com/jameskeane/bcrypt v0.0.0-20120420032655-c3cd44c1e20f github.com/jameskeane/bcrypt v0.0.0-20120420032655-c3cd44c1e20f
github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004 github.com/klauspost/cpuid/v2 v2.2.5
github.com/klauspost/reedsolomon v1.11.8
github.com/kuking/go-frodokem v1.0.2 github.com/kuking/go-frodokem v1.0.2
github.com/mattn/go-isatty v0.0.20 github.com/mattn/go-isatty v0.0.19
github.com/xtaci/kcp-go v4.3.4+incompatible github.com/pkg/errors v0.9.1
golang.org/x/crypto v0.46.0 github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161
golang.org/x/sys v0.39.0 github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b
github.com/tjfoc/gmsm v1.4.1
github.com/xtaci/kcp-go v5.4.20+incompatible
golang.org/x/crypto v0.13.0
golang.org/x/net v0.15.0
golang.org/x/sys v0.12.0
gopkg.in/hlandau/easymetric.v1 v1.0.0
gopkg.in/hlandau/measurable.v1 v1.0.1
gopkg.in/hlandau/passlib.v1 v1.0.11 gopkg.in/hlandau/passlib.v1 v1.0.11
) )
require ( require (
blitter.com/go/chacha20 v0.0.0-20200130200441-214e4085f54c // indirect github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 // indirect
blitter.com/go/mtwist v1.0.2 // indirect golang.org/x/text v0.13.0 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/klauspost/reedsolomon v1.12.6 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b // indirect
github.com/tjfoc/gmsm v1.4.1 // indirect
golang.org/x/net v0.47.0 // indirect
gopkg.in/hlandau/easymetric.v1 v1.0.0 // indirect
gopkg.in/hlandau/measurable.v1 v1.0.1 // indirect
) )

75
go.sum
View File

@ -1,19 +1,21 @@
blitter.com/go/chacha20 v0.0.0-20200130200441-214e4085f54c h1:LcnFFg6MCIJHf26P7eOUST45fNLHJI5erq0gWZaDLCo= blitter.com/go/chacha20 v0.0.0-20200130200441-214e4085f54c h1:LcnFFg6MCIJHf26P7eOUST45fNLHJI5erq0gWZaDLCo=
blitter.com/go/chacha20 v0.0.0-20200130200441-214e4085f54c/go.mod h1:EMJtRcf22WCtHGiXCw+NB/Sb/PYcXtUgUql6LDEwyXo= blitter.com/go/chacha20 v0.0.0-20200130200441-214e4085f54c/go.mod h1:EMJtRcf22WCtHGiXCw+NB/Sb/PYcXtUgUql6LDEwyXo=
blitter.com/go/cryptmt v1.0.3 h1:C1j55/TV8301jROxn83Zlm+qNH3/XUSzBoTrbBGD8gw= blitter.com/go/cryptmt v1.0.2 h1:ZcLhQk7onUssXyQwG3GdXDXctCVnNL+b7aFuvwOdKXc=
blitter.com/go/cryptmt v1.0.3/go.mod h1:otZPP0Vps15DRZNo2zD4RLym+IT6XnbtI1HS412BxHM= blitter.com/go/cryptmt v1.0.2/go.mod h1:tdME2J3O4agaDAYIYNQzzuB28yVGnPSMmV3a/ucSU84=
blitter.com/go/goutmp v1.0.6 h1:jRKRw2WalVBza4T50etAfbvT2xp9G5uykIHTvyB5r0k= blitter.com/go/goutmp v1.0.6 h1:jRKRw2WalVBza4T50etAfbvT2xp9G5uykIHTvyB5r0k=
blitter.com/go/goutmp v1.0.6/go.mod h1:DnK/uLBu1/1yLFiuVlmwvWErzAWVp+pDv7t6ZaQRLNc= blitter.com/go/goutmp v1.0.6/go.mod h1:DnK/uLBu1/1yLFiuVlmwvWErzAWVp+pDv7t6ZaQRLNc=
blitter.com/go/herradurakex v1.0.1 h1:7smv+RiG6PQ2hHebT/uSjIKcisp/lx5PSCBn8fISHWA= blitter.com/go/groestl v0.0.0-20220410000905-c4decbf31d64 h1:SH6cZ4JiOTmWGeVd5hCgt8gsMvfPPHWpEwNdxfsBugM=
blitter.com/go/herradurakex v1.0.1/go.mod h1:m3+vYZX+2dDjdo+n/HDnXEYJX9pwmNeQLgAfJM8mtxw= blitter.com/go/groestl v0.0.0-20220410000905-c4decbf31d64/go.mod h1:YMdIR/gCtFwU/a09jyWAwUu2J9CQejUFwkfD+PyVg+4=
blitter.com/go/hopscotch v0.2.0 h1:zafGbg+wGvnw2IXDZnivNE3RbY13URLV6zCWXlMxST8= blitter.com/go/herradurakex v1.0.0 h1:6XaxY+JLT1HUWPF0gYJnjX3pVjrw4YhYZEzZ1U0wkyc=
blitter.com/go/hopscotch v0.2.0/go.mod h1:hCz7oE31KjaO9M6+s2DcyVNlAA8saE/AaVYKFs7hl1I= blitter.com/go/herradurakex v1.0.0/go.mod h1:m3+vYZX+2dDjdo+n/HDnXEYJX9pwmNeQLgAfJM8mtxw=
blitter.com/go/kyber v1.0.0 h1:xniqw15FUrmR1bTqwH57cIZ0Ko2kYcINnSRE3ESzA9M= blitter.com/go/hopscotch v0.1.1 h1:hh809THr3I52J5G5QozNhDSd+qGwXWGqLh3FJBGrp+o=
blitter.com/go/kyber v1.0.0/go.mod h1:xE277hhExsmBIaVT7oFgNfkXC3ioHaZCTreNJHSCwqw= blitter.com/go/hopscotch v0.1.1/go.mod h1:hCz7oE31KjaO9M6+s2DcyVNlAA8saE/AaVYKFs7hl1I=
blitter.com/go/mtwist v1.0.2 h1:4zmpKNynrRuFF8JAPdhBN8TaJB+quU5d2i7KBgFtVng= blitter.com/go/kyber v0.0.0-20200130200857-6f2021cb88d9 h1:D45AnrNphtvczBXRp5JQicZRTgaK/Is5bgPDDvRKhTc=
blitter.com/go/mtwist v1.0.2/go.mod h1:Y/0x0EsFMUKK1+tdkoCW7H88eF7CTOycUMsTHcfCoZE= blitter.com/go/kyber v0.0.0-20200130200857-6f2021cb88d9/go.mod h1:SK6QfGG72lIfKW1Td0wH7f0wwN5nSIhV3K+wvzGNjrw=
blitter.com/go/newhope v1.0.0 h1:oUn35Ei30AGmLeqjNIG6DA7YNaK7fncBx4ptTnNrzmo= blitter.com/go/mtwist v1.0.1 h1:PxmoWexfMpLmc8neHP/PcRc3s17ct7iz4d5W/qJVt04=
blitter.com/go/newhope v1.0.0/go.mod h1:ywoxfDBqInPsqtnxYsmS4SYMJ5D/kNcrFgpvI+Xcun0= blitter.com/go/mtwist v1.0.1/go.mod h1:aU82Nx8+b1v8oZRNqImfEDzDTPim81rY0ACKAIclV18=
blitter.com/go/newhope v0.0.0-20200130200750-192fc08a8aae h1:YBBaCcdYRrI1btsmcMTv1VMPmaSXXz0RwKOTgMJYSRU=
blitter.com/go/newhope v0.0.0-20200130200750-192fc08a8aae/go.mod h1:ywoxfDBqInPsqtnxYsmS4SYMJ5D/kNcrFgpvI+Xcun0=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
@ -21,11 +23,10 @@ github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSi
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
@ -46,25 +47,22 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/jameskeane/bcrypt v0.0.0-20120420032655-c3cd44c1e20f h1:UWGE8Vi+1Agt0lrvnd7UsmvwqWKRzb9byK9iQmsbY0Y= github.com/jameskeane/bcrypt v0.0.0-20120420032655-c3cd44c1e20f h1:UWGE8Vi+1Agt0lrvnd7UsmvwqWKRzb9byK9iQmsbY0Y=
github.com/jameskeane/bcrypt v0.0.0-20120420032655-c3cd44c1e20f/go.mod h1:u+9Snq0w+ZdYKi8BBoaxnEwWu0fY4Kvu9ByFpM51t1s= github.com/jameskeane/bcrypt v0.0.0-20120420032655-c3cd44c1e20f/go.mod h1:u+9Snq0w+ZdYKi8BBoaxnEwWu0fY4Kvu9ByFpM51t1s=
github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004 h1:G+9t9cEtnC9jFiTxyptEKuNIAbiN5ZCQzX2a74lj3xg= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004/go.mod h1:KmHnJWQrgEvbuy0vcvj00gtMqbvNn1L+3YUZLK/B92c= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= github.com/klauspost/reedsolomon v1.11.8 h1:s8RpUW5TK4hjr+djiOpbZJB4ksx+TdYbRH7vHQpwPOY=
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/klauspost/reedsolomon v1.11.8/go.mod h1:4bXRN+cVzMdml6ti7qLouuYi32KHJ5MGv0Qd8a47h6A=
github.com/klauspost/reedsolomon v1.12.6 h1:8pqE9aECQG/ZFitiUD1xK/E83zwosBAZtE3UbuZM8TQ=
github.com/klauspost/reedsolomon v1.12.6/go.mod h1:ggJT9lc71Vu+cSOPBlxGvBN6TfAS77qB4fp8vJ05NSA=
github.com/kuking/go-frodokem v1.0.2 h1:sxdguENCyr6WnLbJ/cjz0AYCW75H1b+E6zXY2ldZnUU= github.com/kuking/go-frodokem v1.0.2 h1:sxdguENCyr6WnLbJ/cjz0AYCW75H1b+E6zXY2ldZnUU=
github.com/kuking/go-frodokem v1.0.2/go.mod h1:83ZX1kHOd72ouCsvbffCqJIj7Ih83MQTAjH2QbqzLZk= github.com/kuking/go-frodokem v1.0.2/go.mod h1:83ZX1kHOd72ouCsvbffCqJIj7Ih83MQTAjH2QbqzLZk=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU= github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU=
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU= github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU=
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b h1:fj5tQ8acgNUr6O8LEplsxDhUIe2573iLkJc+PqnzZTI= github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b h1:fj5tQ8acgNUr6O8LEplsxDhUIe2573iLkJc+PqnzZTI=
@ -73,15 +71,18 @@ github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE= github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
github.com/ulikunitz/xz v0.5.8 h1:ERv8V6GKqVi23rgu5cj9pVfVzJbOqAY2Ntl88O6c2nQ= github.com/ulikunitz/xz v0.5.8 h1:ERv8V6GKqVi23rgu5cj9pVfVzJbOqAY2Ntl88O6c2nQ=
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/xtaci/kcp-go v4.3.4+incompatible h1:T56s9GLhx+KZUn5T8aO2Didfa4uTYvjeVIRLt6uYdhE= github.com/xtaci/kcp-go v5.4.20+incompatible h1:TN1uey3Raw0sTz0Fg8GkfM0uH3YwzhnZWQ1bABv5xAg=
github.com/xtaci/kcp-go v4.3.4+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE= github.com/xtaci/kcp-go v5.4.20+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 h1:EWU6Pktpas0n8lLQwDsRyZfmkPeRbdgPtW609es+/9E=
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37/go.mod h1:HpMP7DB2CyokmAh4lp0EQnnWhmycP/TvwBGzvuie+H0=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@ -92,8 +93,8 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -103,11 +104,14 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190902133755-9109b7679e13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190902133755-9109b7679e13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@ -135,8 +139,7 @@ gopkg.in/hlandau/measurable.v1 v1.0.1 h1:wH5UZKCRUnRr1iD+xIZfwhtxhmr+bprRJttqA1R
gopkg.in/hlandau/measurable.v1 v1.0.1/go.mod h1:6N+SYJGMTmetsx7wskULP+juuO+++tsHJkAgzvzsbuM= gopkg.in/hlandau/measurable.v1 v1.0.1/go.mod h1:6N+SYJGMTmetsx7wskULP+juuO+++tsHJkAgzvzsbuM=
gopkg.in/hlandau/passlib.v1 v1.0.11 h1:vKeHwGRdWBD9mm4bJ56GAAdBXpFUYvg/BYYkmphjnmA= gopkg.in/hlandau/passlib.v1 v1.0.11 h1:vKeHwGRdWBD9mm4bJ56GAAdBXpFUYvg/BYYkmphjnmA=
gopkg.in/hlandau/passlib.v1 v1.0.11/go.mod h1:wxGAv2CtQHlzWY8NJp+p045yl4WHyX7v2T6XbOcmqjM= gopkg.in/hlandau/passlib.v1 v1.0.11/go.mod h1:wxGAv2CtQHlzWY8NJp+p045yl4WHyX7v2T6XbOcmqjM=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@ -2,7 +2,7 @@ package xs
// Package xs - a secure terminal client/server written from scratch in Go // Package xs - a secure terminal client/server written from scratch in Go
// //
// Copyright (c) 2017-2025 Russell Magee // Copyright (c) 2017-2020 Russell Magee
// Licensed under the terms of the MIT license (see LICENSE.mit in this // Licensed under the terms of the MIT license (see LICENSE.mit in this
// distribution) // distribution)
// //

View File

@ -5,7 +5,6 @@ package xs
import ( import (
"errors" "errors"
"io" "io"
"os"
unix "golang.org/x/sys/unix" unix "golang.org/x/sys/unix"
) )
@ -31,8 +30,7 @@ type State struct {
// MakeRaw put the terminal connected to the given file descriptor into raw // MakeRaw put the terminal connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be // mode and returns the previous state of the terminal so that it can be
// restored. // restored.
func MakeRaw(f *os.File) (*State, error) { func MakeRaw(fd uintptr) (*State, error) {
fd := f.Fd()
termios, err := unix.IoctlGetTermios(int(fd), ioctlReadTermios) termios, err := unix.IoctlGetTermios(int(fd), ioctlReadTermios)
if err != nil { if err != nil {
return nil, err return nil, err
@ -58,8 +56,8 @@ func MakeRaw(f *os.File) (*State, error) {
// GetState returns the current state of a terminal which may be useful to // GetState returns the current state of a terminal which may be useful to
// restore the terminal after a signal. // restore the terminal after a signal.
func GetState(f *os.File) (*State, error) { func GetState(fd uintptr) (*State, error) {
termios, err := unix.IoctlGetTermios(int(f.Fd()), ioctlReadTermios) termios, err := unix.IoctlGetTermios(int(fd), ioctlReadTermios)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -69,9 +67,9 @@ func GetState(f *os.File) (*State, error) {
// Restore restores the terminal connected to the given file descriptor to a // Restore restores the terminal connected to the given file descriptor to a
// previous state. // previous state.
func Restore(f *os.File, state *State) error { func Restore(fd uintptr, state *State) error {
if state != nil { if state != nil {
return unix.IoctlSetTermios(int(f.Fd()), ioctlWriteTermios, &state.termios) return unix.IoctlSetTermios(int(fd), ioctlWriteTermios, &state.termios)
} else { } else {
return errors.New("nil State") return errors.New("nil State")
} }
@ -80,8 +78,7 @@ func Restore(f *os.File, state *State) error {
// ReadPassword reads a line of input from a terminal without local echo. This // ReadPassword reads a line of input from a terminal without local echo. This
// is commonly used for inputting passwords and other sensitive data. The slice // is commonly used for inputting passwords and other sensitive data. The slice
// returned does not include the \n. // returned does not include the \n.
func ReadPassword(f *os.File) ([]byte, error) { func ReadPassword(fd uintptr) ([]byte, error) {
fd := f.Fd()
termios, err := unix.IoctlGetTermios(int(fd), ioctlReadTermios) termios, err := unix.IoctlGetTermios(int(fd), ioctlReadTermios)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -1,4 +1,3 @@
//go:build windows
// +build windows // +build windows
// Note the terminal manipulation functions herein are mostly stubs. They // Note the terminal manipulation functions herein are mostly stubs. They
@ -16,12 +15,10 @@
package xs package xs
import ( import (
"bufio" "io"
"fmt"
"log"
"os"
"os/exec" "os/exec"
"os/signal"
"golang.org/x/sys/windows"
) )
type State struct { type State struct {
@ -30,84 +27,67 @@ type State struct {
// MakeRaw put the terminal connected to the given file descriptor into raw // MakeRaw put the terminal connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be // mode and returns the previous state of the terminal so that it can be
// restored. // restored.
func MakeRaw(f *os.File) (*State, error) { func MakeRaw(fd uintptr) (*State, error) {
cmd := exec.Command("stty", "-echo", "raw") // This doesn't really work. The exec.Command() runs a sub-shell
cmd.Stdin = f // so the stty mods don't affect the client process.
err := cmd.Run() cmd := exec.Command("stty", "-echo raw")
if err != nil { cmd.Run()
log.Fatal(err)
return &State{}, err
}
// MSYS2/CYGWIN: wintty needs CTRL-C caught
// ----------------------------------------
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, os.Kill)
go func() {
for sig := range c {
_ = sig
//fmt.Println(sig)
}
}()
// ----------------------------------------
return &State{}, nil return &State{}, nil
} }
// GetState returns the current state of a terminal which may be useful to // GetState returns the current state of a terminal which may be useful to
// restore the terminal after a signal. // restore the terminal after a signal.
func GetState(f *os.File) (*State, error) { func GetState(fd uintptr) (*State, error) {
return &State{}, nil return &State{}, nil
} }
// Restore restores the terminal connected to the given file descriptor to a // Restore restores the terminal connected to the given file descriptor to a
// previous state. // previous state.
func Restore(f *os.File, state *State) error { func Restore(fd uintptr, state *State) error {
cmd := exec.Command("stty", "sane") cmd := exec.Command("stty", "echo cooked")
cmd.Stdin = f cmd.Run()
err := cmd.Run()
if err != nil {
log.Fatal(err)
return nil
}
return nil return nil
} }
// ReadPassword reads a line of input from a terminal without local echo. This // ReadPassword reads a line of input from a terminal without local echo. This
// is commonly used for inputting passwords and other sensitive data. The slice // is commonly used for inputting passwords and other sensitive data. The slice
// returned does not include the \n. // returned does not include the \n.
func ReadPassword(f *os.File) (pw []byte, err error) { func ReadPassword(fd uintptr) ([]byte, error) {
sttycmd, err := exec.LookPath("stty") return readPasswordLine(passwordReader(fd))
if err != nil {
return nil, err
} else {
//fmt.Printf("stty found at: %v\n", sttycmd)
cmdOff := exec.Command(sttycmd, "-echo")
cmdOff.Stdin = f //os.Stdin
cmdOff.Stdout = nil //os.Stdout
cmdOff.Stderr = nil //os.Stderr
err = cmdOff.Run()
if err != nil {
return nil, err
} }
//fmt.Printf("Enter password:") // passwordReader is an io.Reader that reads from a specific file descriptor.
scanner := bufio.NewScanner(os.Stdin) type passwordReader windows.Handle
scanner.Scan()
err = scanner.Err() func (r passwordReader) Read(buf []byte) (int, error) {
return windows.Read(windows.Handle(r), buf)
}
// readPasswordLine reads from reader until it finds \n or io.EOF.
// The slice returned does not include the \n.
// readPasswordLine also ignores any \r it finds.
func readPasswordLine(reader io.Reader) ([]byte, error) {
var buf [1]byte
var ret []byte
for {
n, err := reader.Read(buf[:])
if n > 0 {
switch buf[0] {
case '\n':
return ret, nil
case '\r':
// remove \r from passwords on Windows
default:
ret = append(ret, buf[0])
}
continue
}
if err != nil { if err != nil {
return nil, err if err == io.EOF && len(ret) > 0 {
return ret, nil
} }
pw = scanner.Bytes() return ret, err
fmt.Println()
cmdOn := exec.Command(sttycmd, "echo")
cmdOn.Stdin = f //os.Stdin
cmdOn.Stdout = nil //os.Stdout
cmdOn.Stderr = nil //os.Stderr
err = cmdOn.Run()
if err != nil {
return nil, err
} }
} }
return
} }

39
xs/mintty_wrapper.sh Executable file
View File

@ -0,0 +1,39 @@
#!/bin/bash
#
## This wrapper may be used within the MSYS/mintty Windows
## shell environment to have a functioning xs client with
## working 'raw' mode and hidden password entry.
##
## mintty uses named pipes and ptys to get a more POSIX-like
## terminal (incl. VT/ANSI codes) rather than the dumb Windows
## console interface; however Go on Windows does not have functioning
## MSYS/mintty code to set raw, echo etc. modes.
##
## Someday it would be preferable to put native Windows term mode
## code into the client build, but this is 'good enough' for now
## (with the exception of tty rows/cols not being set based on
## info from the server).
##
## INSTALLATION
## --
## Build the client, put it somewhere in your $PATH with this
## wrapper and edit the name of the client binary
## eg.,
## $ cp hkexsh.exe /usr/bin/.hkexsh.exe
## $ cp mintty_wrapper.sh /usr/bin/hkexsh
####
trap cleanup EXIT ERR
cleanup() {
stty sane
}
me="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")"
if [ ${1}x == "-hx" ]; then
_${me} -h
else
stty -echo raw icrnl
_${me} $@
fi

View File

@ -1,6 +1,6 @@
// xs client // xs client
// //
// Copyright (c) 2017-2025 Russell Magee // Copyright (c) 2017-2020 Russell Magee
// Licensed under the terms of the MIT license (see LICENSE.mit in this // Licensed under the terms of the MIT license (see LICENSE.mit in this
// distribution) // distribution)
// //
@ -35,8 +35,7 @@ import (
"blitter.com/go/xs/logger" "blitter.com/go/xs/logger"
"blitter.com/go/xs/spinsult" "blitter.com/go/xs/spinsult"
"blitter.com/go/xs/xsnet" "blitter.com/go/xs/xsnet"
"github.com/mattn/go-isatty" isatty "github.com/mattn/go-isatty"
//isatty "github.com/mattn/go-isatty"
) )
var ( var (
@ -103,14 +102,6 @@ type (
escSeqs map[byte]escHandler escSeqs map[byte]escHandler
) )
var (
escs = escSeqs{
'i': func(io.Writer) { os.Stdout.Write([]byte("\x1b[s\x1b[2;1H\x1b[1;31m[HKEXSH]\x1b[39;49m\x1b[u")) },
't': func(io.Writer) { os.Stdout.Write([]byte("\x1b[1;32m[HKEXSH]\x1b[39;49m")) },
'B': func(io.Writer) { os.Stdout.Write([]byte("\x1b[1;32m" + bob + "\x1b[39;49m")) },
}
)
// Copy copies from src to dst until either EOF is reached // Copy copies from src to dst until either EOF is reached
// on src or an error occurs. It returns the number of bytes // on src or an error occurs. It returns the number of bytes
// copied and the first error encountered while copying, if any. // copied and the first error encountered while copying, if any.
@ -158,6 +149,11 @@ func copyBuffer(dst io.Writer, src io.Reader, buf []byte) (written int64, err er
// or tunnel traffic indicator - note we cannot just spawn a goroutine // or tunnel traffic indicator - note we cannot just spawn a goroutine
// here, as copyBuffer() returns after each burst of data. Scope must // here, as copyBuffer() returns after each burst of data. Scope must
// outlive individual copyBuffer calls). // outlive individual copyBuffer calls).
escs := escSeqs{
'i': func(io.Writer) { os.Stdout.Write([]byte("\x1b[s\x1b[2;1H\x1b[1;31m[HKEXSH]\x1b[39;49m\x1b[u")) },
't': func(io.Writer) { os.Stdout.Write([]byte("\x1b[1;32m[HKEXSH]\x1b[39;49m")) },
'B': func(io.Writer) { os.Stdout.Write([]byte("\x1b[1;32m" + bob + "\x1b[39;49m")) },
}
/* /*
// If the reader has a WriteTo method, use it to do the copy. // If the reader has a WriteTo method, use it to do the copy.
@ -294,14 +290,7 @@ func buildCmdLocalToRemote(copyQuiet bool, copyLimitBPS uint, files string) (cap
captureStderr = true captureStderr = true
cmd = xs.GetTool("tar") cmd = xs.GetTool("tar")
//fmt.Printf("GetTool found cmd:%v\n", cmd) args = []string{"-cz", "-f", "/dev/stdout"}
/* Explicit -f /dev/stdout doesn't work in MINGW/MSYS64
* as '/dev/stdout' doesn't actually appear in the /dev/ filesystem...?
* And it appears not to actually be required as without -f stdout is
* implied. -rlm 2025-12-07
*/
//args = []string{"-cz", "-f", "/dev/stdout"}
args = []string{"-cz"}
files = strings.TrimSpace(files) files = strings.TrimSpace(files)
// Awesome fact: tar actually can take multiple -C args, and // Awesome fact: tar actually can take multiple -C args, and
// changes to the dest dir *as it sees each one*. This enables // changes to the dest dir *as it sees each one*. This enables
@ -317,7 +306,6 @@ func buildCmdLocalToRemote(copyQuiet bool, copyLimitBPS uint, files string) (cap
// remote destDir. // remote destDir.
for _, v := range strings.Split(files, " ") { for _, v := range strings.Split(files, " ") {
v, _ = filepath.Abs(v) // #nosec v, _ = filepath.Abs(v) // #nosec
v = xs.GroomFsPath(v)
dirTmp, fileTmp := path.Split(v) dirTmp, fileTmp := path.Split(v)
if dirTmp == "" { if dirTmp == "" {
args = append(args, fileTmp) args = append(args, fileTmp)
@ -330,8 +318,7 @@ func buildCmdLocalToRemote(copyQuiet bool, copyLimitBPS uint, files string) (cap
bandwidthInBytesPerSec := " -L " + fmt.Sprintf("%d", copyLimitBPS) bandwidthInBytesPerSec := " -L " + fmt.Sprintf("%d", copyLimitBPS)
displayOpts := " -pre " //nolint:goconst,nolintlint displayOpts := " -pre " //nolint:goconst,nolintlint
cmd = xs.GetTool("bash") cmd = xs.GetTool("bash")
//args = []string{"-c", xs.GetTool("tar") + " -cz -f /dev/stdout "} args = []string{"-c", xs.GetTool("tar") + " -cz -f /dev/stdout "}
args = []string{"-c", xs.GetTool("tar") + " -cz "}
files = strings.TrimSpace(files) files = strings.TrimSpace(files)
// Awesome fact: tar actually can take multiple -C args, and // Awesome fact: tar actually can take multiple -C args, and
// changes to the dest dir *as it sees each one*. This enables // changes to the dest dir *as it sees each one*. This enables
@ -347,7 +334,6 @@ func buildCmdLocalToRemote(copyQuiet bool, copyLimitBPS uint, files string) (cap
// remote destDir. // remote destDir.
for _, v := range strings.Split(files, " ") { for _, v := range strings.Split(files, " ") {
v, _ = filepath.Abs(v) // #nosec v, _ = filepath.Abs(v) // #nosec
v = xs.GroomFsPath(v)
dirTmp, fileTmp := path.Split(v) dirTmp, fileTmp := path.Split(v)
if dirTmp == "" { if dirTmp == "" {
args[1] = args[1] + fileTmp + " " args[1] = args[1] + fileTmp + " "
@ -396,8 +382,6 @@ func doCopyMode(conn *xsnet.Conn, remoteDest bool, files string, copyQuiet bool,
c.Stderr = os.Stderr c.Stderr = os.Stderr
} }
//fmt.Printf("cmd:%v args:%v\n", cmdName, cmdArgs)
// Start the command (no pty) // Start the command (no pty)
err = c.Start() // returns immediately err = c.Start() // returns immediately
///////////// /////////////
@ -746,8 +730,7 @@ func main() { //nolint: funlen, gocyclo
C_CHACHA20_12`) C_CHACHA20_12`)
flag.StringVar(&hmacAlg, "m", "H_SHA256", "session `HMAC`"+` flag.StringVar(&hmacAlg, "m", "H_SHA256", "session `HMAC`"+`
H_SHA256 H_SHA256
H_SHA512 H_SHA512`)
H_WHIRLPOOL`)
flag.StringVar(&kexAlg, "k", "KEX_HERRADURA512", "KEx `alg`"+` flag.StringVar(&kexAlg, "k", "KEX_HERRADURA512", "KEx `alg`"+`
KEX_HERRADURA256 KEX_HERRADURA256
KEX_HERRADURA512 KEX_HERRADURA512
@ -904,7 +887,7 @@ func main() { //nolint: funlen, gocyclo
if !gopt { if !gopt {
// See if we can log in via an auth token // See if we can log in via an auth token
u, _ := user.Current() u, _ := user.Current()
ab, aerr := os.ReadFile(fmt.Sprintf("%s/%s", u.HomeDir, xsnet.XS_ID_AUTHTOKFILE)) ab, aerr := os.ReadFile(fmt.Sprintf("%s/.xs_id", u.HomeDir))
if aerr == nil { if aerr == nil {
for _, line := range strings.Split(string(ab), "\n") { for _, line := range strings.Split(string(ab), "\n") {
line += "\n" line += "\n"
@ -922,7 +905,7 @@ func main() { //nolint: funlen, gocyclo
_, _ = fmt.Fprintln(os.Stderr, "[no authtoken, use -g to request one from server]") _, _ = fmt.Fprintln(os.Stderr, "[no authtoken, use -g to request one from server]")
} }
} else { } else {
log.Printf("[cannot read %s/%s]\n", u.HomeDir, xsnet.XS_ID_AUTHTOKFILE) log.Printf("[cannot read %s/.xs_id]\n", u.HomeDir)
} }
} }
runtime.GC() runtime.GC()
@ -1003,13 +986,29 @@ func main() { //nolint: funlen, gocyclo
// === Shell terminal mode (Shell vs. Copy) setup // === Shell terminal mode (Shell vs. Copy) setup
// Set stdin in raw mode if it's an interactive session
// TODO: send flag to server side indicating this
// affects shell command used
var oldState *xs.State
defer conn.Close() defer conn.Close()
// === From this point on, conn is a secure encrypted channel // === From this point on, conn is a secure encrypted channel
// === BEGIN Login phase if shellMode {
if isatty.IsTerminal(os.Stdin.Fd()) {
oldState, err = xs.MakeRaw(os.Stdin.Fd())
if err != nil {
panic(err)
}
// #gv:s/label=\"main\$1\"/label=\"deferRestore\"/
// TODO:.gv:main:1:deferRestore
defer restoreTermState(oldState)
} else {
log.Println("NOT A TTY")
}
}
var oldState *xs.State // === Login phase
// Start login timeout here and disconnect if user/pass phase stalls // Start login timeout here and disconnect if user/pass phase stalls
// iloginImpatience := time.AfterFunc(20*time.Second, func() { // iloginImpatience := time.AfterFunc(20*time.Second, func() {
@ -1026,7 +1025,7 @@ func main() { //nolint: funlen, gocyclo
// No auth token, prompt for password // No auth token, prompt for password
fmt.Printf("Gimme cookie:") fmt.Printf("Gimme cookie:")
} }
ab, e := xs.ReadPassword(os.Stdin) ab, e := xs.ReadPassword(os.Stdin.Fd())
if !gopt { if !gopt {
fmt.Printf("\r\n") fmt.Printf("\r\n")
} }
@ -1041,25 +1040,6 @@ func main() { //nolint: funlen, gocyclo
// Security scrub // Security scrub
runtime.GC() runtime.GC()
// === END Login phase
// === Terminal mode adjustment for session
if shellMode {
if isatty.IsTerminal(os.Stdin.Fd()) ||
isatty.IsCygwinTerminal(os.Stdin.Fd()) {
oldState, err = xs.MakeRaw(os.Stdin)
if err != nil {
panic(err)
}
// #gv:s/label=\"main\$1\"/label=\"deferRestore\"/
// TODO:.gv:main:1:deferRestore
defer restoreTermState(oldState)
} else {
log.Println("NOT A TTY")
}
}
// === Session param and TERM setup // === Session param and TERM setup
// Set up session params and send over to server // Set up session params and send over to server
@ -1091,6 +1071,10 @@ func main() { //nolint: funlen, gocyclo
fmt.Fprintln(os.Stderr, rejectUserMsg()) fmt.Fprintln(os.Stderr, rejectUserMsg())
rec.SetStatus(GeneralProtocolErr) rec.SetStatus(GeneralProtocolErr)
} else { } else {
// === Set up connection keepalive to server
conn.StartupKeepAlive() // goroutine, returns immediately
defer conn.ShutdownKeepAlive()
// === Set up chaffing to server // === Set up chaffing to server
conn.SetupChaff(chaffFreqMin, chaffFreqMax, chaffBytesMax) // enable client->server chaffing conn.SetupChaff(chaffFreqMin, chaffFreqMax, chaffBytesMax) // enable client->server chaffing
if chaffEnabled { if chaffEnabled {
@ -1121,10 +1105,6 @@ func main() { //nolint: funlen, gocyclo
// === Session entry (shellMode or copyMode) // === Session entry (shellMode or copyMode)
if shellMode { if shellMode {
// === Set up connection keepalive to server
conn.StartupKeepAlive() // goroutine, returns immediately
defer conn.ShutdownKeepAlive()
// === (shell) launch tunnels // === (shell) launch tunnels
launchTuns(&conn /*remoteHost,*/, tunSpecStr) launchTuns(&conn /*remoteHost,*/, tunSpecStr)
doShellMode(isInteractive, &conn, oldState, rec) doShellMode(isInteractive, &conn, oldState, rec)
@ -1163,7 +1143,7 @@ func localUserName(u *user.User) string {
} }
func restoreTermState(oldState *xs.State) { func restoreTermState(oldState *xs.State) {
_ = xs.Restore(os.Stdin, oldState) _ = xs.Restore(os.Stdin.Fd(), oldState)
} }
// exitWithStatus wraps os.Exit() plus does any required pprof housekeeping // exitWithStatus wraps os.Exit() plus does any required pprof housekeeping

View File

@ -1,6 +1,6 @@
// xsd server // xsd server
// //
// Copyright (c) 2017-2025 Russell Magee // Copyright (c) 2017-2020 Russell Magee
// Licensed under the terms of the MIT license (see LICENSE.mit in this // Licensed under the terms of the MIT license (see LICENSE.mit in this
// distribution) // distribution)
// //
@ -121,6 +121,10 @@ func runClientToServerCopyAs(who, ttype string, conn *xsnet.Conn, fpath string,
c.Stdout = os.Stdout c.Stdout = os.Stdout
c.Stderr = os.Stderr c.Stderr = os.Stderr
// === Set up connection keepalive to client
conn.StartupKeepAlive() // goroutine, returns immediately
defer conn.ShutdownKeepAlive()
if chaffing { if chaffing {
conn.StartupChaff() conn.StartupChaff()
} }
@ -217,6 +221,10 @@ func runServerToClientCopyAs(who, ttype string, conn *xsnet.Conn, srcPath string
c.Stderr = stdErrBuffer c.Stderr = stdErrBuffer
//c.Stderr = nil //c.Stderr = nil
// === Set up connection keepalive to client
conn.StartupKeepAlive() // goroutine, returns immediately
defer conn.ShutdownKeepAlive()
if chaffing { if chaffing {
conn.StartupChaff() conn.StartupChaff()
} }
@ -372,11 +380,11 @@ func runShellAs(who, hname, ttype, cmd string, interactive bool, //nolint:funlen
if chaffing { if chaffing {
conn.StartupChaff() conn.StartupChaff()
}
// #gv:s/label=\"runShellAs\$4\"/label=\"deferChaffShutdown\"/ // #gv:s/label=\"runShellAs\$4\"/label=\"deferChaffShutdown\"/
defer func() { defer func() {
conn.ShutdownChaff() conn.ShutdownChaff()
}() }()
}
// ..and the pty to stdout. // ..and the pty to stdout.
// This may take some time exceeding that of the // This may take some time exceeding that of the
@ -564,8 +572,7 @@ func main() { //nolint:funlen,gocyclo
flag.Var(&aHMACAlgs, "aH", "Allowed `HMAC`s (eg. '-aH HMACAlgA -aH HMACAlgB ...')"+` flag.Var(&aHMACAlgs, "aH", "Allowed `HMAC`s (eg. '-aH HMACAlgA -aH HMACAlgB ...')"+`
H_all H_all
H_SHA256 H_SHA256
H_SHA512 H_SHA512`)
H_WHIRLPOOL`)
flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to <`file`>") flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to <`file`>")
flag.StringVar(&memprofile, "memprofile", "", "write memory profile to <`file`>") flag.StringVar(&memprofile, "memprofile", "", "write memory profile to <`file`>")
@ -834,7 +841,7 @@ func main() { //nolint:funlen,gocyclo
hname := goutmp.GetHost(addr.String()) hname := goutmp.GetHost(addr.String())
logger.LogNotice(fmt.Sprintf("[Generating autologin token for [%s@%s]]\n", rec.Who(), hname)) //nolint:errcheck logger.LogNotice(fmt.Sprintf("[Generating autologin token for [%s@%s]]\n", rec.Who(), hname)) //nolint:errcheck
token := GenAuthToken(string(rec.Who()), string(rec.ConnHost())) token := GenAuthToken(string(rec.Who()), string(rec.ConnHost()))
tokenCmd := fmt.Sprintf("echo %q | tee -a ~/%s", token, xsnet.XS_ID_AUTHTOKFILE) tokenCmd := fmt.Sprintf("echo %q | tee -a ~/.xs_id", token)
cmdStatus, runErr := runShellAs(string(rec.Who()), hname, string(rec.TermType()), tokenCmd, false, hc, chaffEnabled) cmdStatus, runErr := runShellAs(string(rec.Who()), hname, string(rec.TermType()), tokenCmd, false, hc, chaffEnabled)
// Returned hopefully via an EOF or exit/logout; // Returned hopefully via an EOF or exit/logout;
// Clear current op so user can enter next, or EOF // Clear current op so user can enter next, or EOF

8
xsnet/chan.go Executable file → Normal file
View File

@ -22,8 +22,8 @@ import (
"blitter.com/go/cryptmt" "blitter.com/go/cryptmt"
"blitter.com/go/hopscotch" "blitter.com/go/hopscotch"
"blitter.com/go/xs/logger"
"github.com/aead/chacha20/chacha" "github.com/aead/chacha20/chacha"
whirlpool "github.com/jzelinskie/whirlpool"
"golang.org/x/crypto/blowfish" "golang.org/x/crypto/blowfish"
"golang.org/x/crypto/twofish" "golang.org/x/crypto/twofish"
@ -64,7 +64,8 @@ func getNewStreamAlgs(cb uint8, hb uint8) (config uint32) {
// the input rekeying data // the input rekeying data
c := (cb % CAlgNoneDisallowed) c := (cb % CAlgNoneDisallowed)
h := (hb % HmacNoneDisallowed) h := (hb % HmacNoneDisallowed)
config = uint32(h)<<8 | uint32(c) config = uint32(h<<8) | uint32(c)
logger.LogDebug(fmt.Sprintf("[Chose new algs [%d:%d]", h, c))
return return
} }
@ -156,9 +157,6 @@ func (hc *Conn) getStream(keymat []byte) (rc cipher.Stream, mc hash.Hash, err er
if !halg.Available() { if !halg.Available() {
log.Fatal("hash not available!") log.Fatal("hash not available!")
} }
case HmacWHIRLPOOL:
log.Printf("[hash HmacWHIRLPOOL (%d)]\n", hopts)
mc = whirlpool.New()
default: default:
log.Printf("[invalid hmac (%d)]\n", hopts) log.Printf("[invalid hmac (%d)]\n", hopts)
fmt.Printf("DOOFUS SET A VALID HMAC ALG (%d)\n", hopts) fmt.Printf("DOOFUS SET A VALID HMAC ALG (%d)\n", hopts)

3
xsnet/consts.go Executable file → Normal file
View File

@ -119,7 +119,6 @@ type CSCipherAlg uint32
const ( const (
HmacSHA256 = iota HmacSHA256 = iota
HmacSHA512 HmacSHA512
HmacWHIRLPOOL
HmacNoneDisallowed HmacNoneDisallowed
) )
@ -141,5 +140,3 @@ const (
CHAFF_FREQ_MSECS_MIN = 1 CHAFF_FREQ_MSECS_MIN = 1
CHAFF_FREQ_MSECS_MAX = 300000 // 5 minutes CHAFF_FREQ_MSECS_MAX = 300000 // 5 minutes
) )
const XS_ID_AUTHTOKFILE = ".config/xs/.xs_id"

0
xsnet/kcp.go Executable file → Normal file
View File

13
xsnet/net.go Executable file → Normal file
View File

@ -39,6 +39,7 @@ import (
"net" "net"
"strings" "strings"
"sync" "sync"
"syscall"
"time" "time"
hkex "blitter.com/go/herradurakex" hkex "blitter.com/go/herradurakex"
@ -176,8 +177,6 @@ func (h *CSHmacAlg) String() string {
return "H_SHA256" return "H_SHA256"
case HmacSHA512: case HmacSHA512:
return "H_SHA512" return "H_SHA512"
case HmacWHIRLPOOL:
return "H_WHIRLPOOL"
default: default:
return "H_ERR_UNK" return "H_ERR_UNK"
} }
@ -364,10 +363,6 @@ func (hc *Conn) applyConnExtensions(extensions ...string) {
log.Println("[extension arg = H_SHA512]") log.Println("[extension arg = H_SHA512]")
hc.cipheropts &= (0xFFFF00FF) hc.cipheropts &= (0xFFFF00FF)
hc.cipheropts |= (HmacSHA512 << 8) hc.cipheropts |= (HmacSHA512 << 8)
case "H_WHIRLPOOL":
log.Println("[extension arg = H_WHIRLPOOL]")
hc.cipheropts &= (0xFFFF00FF)
hc.cipheropts |= (HmacWHIRLPOOL << 8)
case "OPT_REMOD": case "OPT_REMOD":
log.Println("[extension arg = OPT_REMOD]") log.Println("[extension arg = OPT_REMOD]")
hc.opts |= CORemodulateShields hc.opts |= CORemodulateShields
@ -1120,7 +1115,7 @@ func (hl *HKExListener) Accept() (hc Conn, err error) {
return Conn{}, err return Conn{}, err
} }
logger.LogDebug(fmt.Sprintf("[net.Listener Accepted %v]\n", c.RemoteAddr())) logger.LogDebug(fmt.Sprintln("[net.Listener Accepted]"))
} }
// Read KEx alg proposed by client // Read KEx alg proposed by client
var kexAlg KEXAlg var kexAlg KEXAlg
@ -1761,9 +1756,7 @@ func (hc *Conn) keepaliveHelper() {
hc.ShutdownKeepAlive() hc.ShutdownKeepAlive()
if hc.Pproc != 0 { if hc.Pproc != 0 {
//fmt.Printf("[pid %d needs to be killed]\n", hc.Pproc) //fmt.Printf("[pid %d needs to be killed]\n", hc.Pproc)
//syscall.Kill(hc.Pproc, syscall.SIGABRT) //nolint:errcheck syscall.Kill(hc.Pproc, syscall.SIGABRT) //nolint:errcheck
//exec.Command("taskkill", "/f", "/pid", strconv.Itoa(hc.Pproc)).Run()
hc.kill()
} }
break break
} }

View File

@ -1,13 +0,0 @@
//go:build linux
// +build linux
package xsnet
import (
"syscall"
)
func (hc *Conn) kill() {
syscall.Kill(hc.Pproc, syscall.SIGABRT) //nolint:errcheck
}

View File

@ -1,13 +0,0 @@
//go:build windows
// +build windows
package xsnet
import (
"os/exec"
"strconv"
)
func (hc *Conn) kill() {
exec.Command("taskkill", "/f", "/pid", strconv.Itoa(hc.Pproc)).Run()
}

0
xsnet/tun.go Executable file → Normal file
View File

View File

@ -1,7 +1,7 @@
// Util to generate/store passwords for users in a file akin to /etc/passwd // Util to generate/store passwords for users in a file akin to /etc/passwd
// suitable for the xs server, using bcrypt. // suitable for the xs server, using bcrypt.
// //
// Copyright (c) 2017-2025 Russell Magee // Copyright (c) 2017-2020 Russell Magee
// Licensed under the terms of the MIT license (see LICENSE.mit in this // Licensed under the terms of the MIT license (see LICENSE.mit in this
// distribution) // distribution)
// //