mirror of https://github.com/schollz/croc.git
use relay public key and password to connect
This commit is contained in:
parent
675f896d61
commit
fffdf39bea
2
go.sum
2
go.sum
|
@ -15,8 +15,6 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
|||
github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ=
|
||||
github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI=
|
||||
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
|
||||
github.com/kalafut/imohash v1.0.0 h1:LgCJ+p/BwM2HKpOxFopkeddpzVCfm15EtXMroXD1SYE=
|
||||
github.com/kalafut/imohash v1.0.0/go.mod h1:c3RHT80ZAp5C/aYgQI92ZlrOymqkZnRDprU87kg75HI=
|
||||
github.com/kalafut/imohash v1.0.2 h1:j/cUPa15YvXv7abJlM+kdJIycbBMpmO7WqhPl4YB76I=
|
||||
github.com/kalafut/imohash v1.0.2/go.mod h1:PjHBF0vpo1q7zMqiTn0qwSTQU2wDn5QIe8S8sFQuZS8=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
"github.com/schollz/cli/v2"
|
||||
"github.com/schollz/croc/v9/src/comm"
|
||||
"github.com/schollz/croc/v9/src/croc"
|
||||
"github.com/schollz/croc/v9/src/crypt"
|
||||
"github.com/schollz/croc/v9/src/models"
|
||||
"github.com/schollz/croc/v9/src/tcp"
|
||||
"github.com/schollz/croc/v9/src/utils"
|
||||
|
@ -75,6 +76,7 @@ func Run() (err error) {
|
|||
},
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{Name: "ports", Value: "9009,9010,9011,9012,9013", Usage: "ports of the relay"},
|
||||
&cli.StringFlag{Name: "identity", Value: "", Usage: "identity file with credentials"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -93,7 +95,8 @@ func Run() (err error) {
|
|||
&cli.StringFlag{Name: "relay", Value: models.DEFAULT_RELAY, Usage: "address of the relay", EnvVars: []string{"CROC_RELAY"}},
|
||||
&cli.StringFlag{Name: "relay6", Value: models.DEFAULT_RELAY6, Usage: "ipv6 address of the relay", EnvVars: []string{"CROC_RELAY6"}},
|
||||
&cli.StringFlag{Name: "out", Value: ".", Usage: "specify an output folder to receive the file"},
|
||||
&cli.StringFlag{Name: "pass", Value: models.DEFAULT_PASSPHRASE, Usage: "password for the relay", EnvVars: []string{"CROC_PASS"}},
|
||||
&cli.StringFlag{Name: "relay-pass", Value: models.DEFAULT_RELAY_PASSWORD, Usage: "password for the relay (defaults to public relay)", EnvVars: []string{"CROC_PASS"}},
|
||||
&cli.StringFlag{Name: "relay-key", Value: models.DEFAULT_RELAY_KEYPUBLIC, Usage: "public key for the relay (defaults to public relay)", EnvVars: []string{"CROC_KEY"}},
|
||||
&cli.StringFlag{Name: "socks5", Value: "", Usage: "add a socks5 proxy", EnvVars: []string{"SOCKS5_PROXY"}},
|
||||
}
|
||||
app.EnableBashCompletion = true
|
||||
|
@ -167,15 +170,6 @@ func getConfigFile() string {
|
|||
return path.Join(configFile, "send.json")
|
||||
}
|
||||
|
||||
func determinePass(c *cli.Context) (pass string) {
|
||||
pass = c.String("pass")
|
||||
b, err := ioutil.ReadFile(pass)
|
||||
if err == nil {
|
||||
pass = strings.TrimSpace(string(b))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func send(c *cli.Context) (err error) {
|
||||
setDebugLevel(c)
|
||||
comm.Socks5Proxy = c.String("socks5")
|
||||
|
@ -193,7 +187,8 @@ func send(c *cli.Context) (err error) {
|
|||
RelayPorts: strings.Split(c.String("ports"), ","),
|
||||
Ask: c.Bool("ask"),
|
||||
NoMultiplexing: c.Bool("no-multi"),
|
||||
RelayPassword: determinePass(c),
|
||||
RelayPassword: c.String("relay-pass"),
|
||||
RelayKeyPublic: c.String("relay-key"),
|
||||
SendingText: c.String("text") != "",
|
||||
NoCompress: c.Bool("no-compress"),
|
||||
Overwrite: c.Bool("overwrite"),
|
||||
|
@ -226,9 +221,12 @@ func send(c *cli.Context) (err error) {
|
|||
if !c.IsSet("code") {
|
||||
crocOptions.SharedSecret = rememberedOptions.SharedSecret
|
||||
}
|
||||
if !c.IsSet("pass") {
|
||||
if !c.IsSet("relay-pass") {
|
||||
crocOptions.RelayPassword = rememberedOptions.RelayPassword
|
||||
}
|
||||
if !c.IsSet("relay-key") {
|
||||
crocOptions.RelayKeyPublic = rememberedOptions.RelayKeyPublic
|
||||
}
|
||||
}
|
||||
|
||||
var fnames []string
|
||||
|
@ -383,20 +381,21 @@ func saveConfig(c *cli.Context, crocOptions croc.Options) {
|
|||
func receive(c *cli.Context) (err error) {
|
||||
comm.Socks5Proxy = c.String("socks5")
|
||||
crocOptions := croc.Options{
|
||||
SharedSecret: c.String("code"),
|
||||
IsSender: false,
|
||||
Debug: c.Bool("debug"),
|
||||
NoPrompt: c.Bool("yes"),
|
||||
RelayAddress: c.String("relay"),
|
||||
RelayAddress6: c.String("relay6"),
|
||||
Stdout: c.Bool("stdout"),
|
||||
Ask: c.Bool("ask"),
|
||||
RelayPassword: determinePass(c),
|
||||
OnlyLocal: c.Bool("local"),
|
||||
IP: c.String("ip"),
|
||||
Overwrite: c.Bool("overwrite"),
|
||||
Curve: c.String("curve"),
|
||||
HashAlgorithm: "xxhash",
|
||||
SharedSecret: c.String("code"),
|
||||
IsSender: false,
|
||||
Debug: c.Bool("debug"),
|
||||
NoPrompt: c.Bool("yes"),
|
||||
RelayAddress: c.String("relay"),
|
||||
RelayAddress6: c.String("relay6"),
|
||||
Stdout: c.Bool("stdout"),
|
||||
Ask: c.Bool("ask"),
|
||||
RelayPassword: c.String("relay-pass"),
|
||||
RelayKeyPublic: c.String("relay-key"),
|
||||
OnlyLocal: c.Bool("local"),
|
||||
IP: c.String("ip"),
|
||||
Overwrite: c.Bool("overwrite"),
|
||||
Curve: c.String("curve"),
|
||||
HashAlgorithm: "xxhash",
|
||||
}
|
||||
if crocOptions.RelayAddress != models.DEFAULT_RELAY {
|
||||
crocOptions.RelayAddress6 = ""
|
||||
|
@ -481,23 +480,40 @@ func receive(c *cli.Context) (err error) {
|
|||
}
|
||||
|
||||
func relay(c *cli.Context) (err error) {
|
||||
log.Infof("starting croc relay version %v", Version)
|
||||
identityFile := "identity.croc"
|
||||
if c.String("identity") != "" {
|
||||
identityFile = c.String("identity")
|
||||
}
|
||||
if !utils.Exists(identityFile) {
|
||||
err = crypt.GenerateIdentityAndPassword(identityFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
keyPrivate, keyPublic, password, err := crypt.LoadIdentityAndPassword(identityFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ports := strings.Split(c.String("ports"), ",")
|
||||
tcpPorts := strings.Join(ports[1:], ",")
|
||||
fmt.Printf("starting croc relay version %v\n", Version)
|
||||
identityFileAbs, _ := filepath.Abs(identityFile)
|
||||
fmt.Printf("identity file = %s\n", identityFileAbs)
|
||||
fmt.Printf("\n\nexample to send files:\n\n croc --relay localhost:%s --relay-pass %s --relay-key %s send file.txt", ports[0], password, keyPublic)
|
||||
debugString := "info"
|
||||
if c.Bool("debug") {
|
||||
debugString = "debug"
|
||||
}
|
||||
ports := strings.Split(c.String("ports"), ",")
|
||||
tcpPorts := strings.Join(ports[1:], ",")
|
||||
for i, port := range ports {
|
||||
if i == 0 {
|
||||
continue
|
||||
}
|
||||
go func(portStr string) {
|
||||
err = tcp.Run(debugString, portStr, determinePass(c))
|
||||
err = tcp.Run(debugString, portStr, password, keyPublic, keyPrivate)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}(port)
|
||||
}
|
||||
return tcp.Run(debugString, ports[0], determinePass(c), tcpPorts)
|
||||
return tcp.Run(debugString, ports[0], password, keyPublic, keyPrivate, tcpPorts)
|
||||
}
|
||||
|
|
|
@ -48,26 +48,31 @@ func Debug(debug bool) {
|
|||
|
||||
// Options specifies user specific options
|
||||
type Options struct {
|
||||
IsSender bool
|
||||
SharedSecret string
|
||||
Debug bool
|
||||
RelayAddress string
|
||||
RelayAddress6 string
|
||||
RelayPorts []string
|
||||
RelayPassword string
|
||||
Stdout bool
|
||||
NoPrompt bool
|
||||
NoMultiplexing bool
|
||||
DisableLocal bool
|
||||
OnlyLocal bool
|
||||
IgnoreStdin bool
|
||||
Ask bool
|
||||
SendingText bool
|
||||
NoCompress bool
|
||||
IP string
|
||||
Overwrite bool
|
||||
Curve string
|
||||
HashAlgorithm string
|
||||
IsSender bool
|
||||
SharedSecret string
|
||||
Debug bool
|
||||
RelayAddress string
|
||||
RelayAddress6 string
|
||||
RelayPorts []string
|
||||
RelayPassword string
|
||||
RelayKeyPrivate string
|
||||
RelayKeyPublic string
|
||||
LocalRelayPassword string
|
||||
LocalRelayKeyPrivate string
|
||||
LocalRelayKeyPublic string
|
||||
Stdout bool
|
||||
NoPrompt bool
|
||||
NoMultiplexing bool
|
||||
DisableLocal bool
|
||||
OnlyLocal bool
|
||||
IgnoreStdin bool
|
||||
Ask bool
|
||||
SendingText bool
|
||||
NoCompress bool
|
||||
IP string
|
||||
Overwrite bool
|
||||
Curve string
|
||||
HashAlgorithm string
|
||||
}
|
||||
|
||||
// Client holds the state of the croc transfer
|
||||
|
@ -288,7 +293,7 @@ func (c *Client) setupLocalRelay() {
|
|||
if c.Options.Debug {
|
||||
debugString = "debug"
|
||||
}
|
||||
err := tcp.Run(debugString, portStr, c.Options.RelayPassword, strings.Join(c.Options.RelayPorts[1:], ","))
|
||||
err := tcp.Run(debugString, portStr, c.Options.LocalRelayPassword, c.Options.LocalRelayKeyPublic, c.Options.LocalRelayKeyPrivate, strings.Join(c.Options.RelayPorts[1:], ","))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -320,7 +325,7 @@ func (c *Client) transferOverLocalRelay(options TransferOptions, errchan chan<-
|
|||
time.Sleep(500 * time.Millisecond)
|
||||
log.Debug("establishing connection")
|
||||
var banner string
|
||||
conn, banner, ipaddr, err := tcp.ConnectToTCPServer("localhost:"+c.Options.RelayPorts[0], c.Options.RelayPassword, c.Options.SharedSecret[:3])
|
||||
conn, banner, ipaddr, err := tcp.ConnectToTCPServer("localhost:"+c.Options.RelayPorts[0], c.Options.LocalRelayPassword, c.Options.LocalRelayKeyPublic, c.Options.SharedSecret[:3])
|
||||
log.Debugf("banner: %s", banner)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("could not connect to localhost:%s: %w", c.Options.RelayPorts[0], err)
|
||||
|
@ -361,8 +366,9 @@ func (c *Client) Send(options TransferOptions) (err error) {
|
|||
if c.Options.RelayAddress != models.DEFAULT_RELAY {
|
||||
flags.WriteString("--relay " + c.Options.RelayAddress + " ")
|
||||
}
|
||||
if c.Options.RelayPassword != models.DEFAULT_PASSPHRASE {
|
||||
flags.WriteString("--pass " + c.Options.RelayPassword + " ")
|
||||
if c.Options.RelayPassword != models.DEFAULT_RELAY_PASSWORD || c.Options.RelayKeyPublic != models.DEFAULT_RELAY_KEYPUBLIC {
|
||||
flags.WriteString("--relay-pass " + c.Options.RelayPassword + " ")
|
||||
flags.WriteString("--relay-key " + c.Options.RelayKeyPublic + " ")
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "Code is: %[1]s\nOn the other computer run\n\ncroc %[2]s%[1]s\n", c.Options.SharedSecret, flags.String())
|
||||
if c.Options.Ask {
|
||||
|
@ -376,6 +382,8 @@ func (c *Client) Send(options TransferOptions) (err error) {
|
|||
errchan := make(chan error, 1)
|
||||
|
||||
if !c.Options.DisableLocal {
|
||||
c.Options.LocalRelayKeyPublic, c.Options.LocalRelayKeyPrivate, _ = crypt.NewAge()
|
||||
c.Options.LocalRelayPassword, _ = crypt.GenerateRandomString(6)
|
||||
// add two things to the error channel
|
||||
errchan = make(chan error, 2)
|
||||
c.setupLocalRelay()
|
||||
|
@ -405,7 +413,7 @@ func (c *Client) Send(options TransferOptions) (err error) {
|
|||
log.Debugf("got host '%v' and port '%v'", host, port)
|
||||
address = net.JoinHostPort(host, port)
|
||||
log.Debugf("trying connection to %s", address)
|
||||
conn, banner, ipaddr, err = tcp.ConnectToTCPServer(address, c.Options.RelayPassword, c.Options.SharedSecret[:3], durations[i])
|
||||
conn, banner, ipaddr, err = tcp.ConnectToTCPServer(address, c.Options.RelayPassword, c.Options.RelayKeyPublic, c.Options.SharedSecret[:3], durations[i])
|
||||
if err == nil {
|
||||
c.Options.RelayAddress = address
|
||||
break
|
||||
|
@ -599,7 +607,7 @@ func (c *Client) Receive() (err error) {
|
|||
log.Debugf("got host '%v' and port '%v'", host, port)
|
||||
address = net.JoinHostPort(host, port)
|
||||
log.Debugf("trying connection to %s", address)
|
||||
c.conn[0], banner, c.ExternalIP, err = tcp.ConnectToTCPServer(address, c.Options.RelayPassword, c.Options.SharedSecret[:3], durations[i])
|
||||
c.conn[0], banner, c.ExternalIP, err = tcp.ConnectToTCPServer(address, c.Options.RelayPassword, c.Options.RelayKeyPublic, c.Options.SharedSecret[:3], durations[i])
|
||||
if err == nil {
|
||||
c.Options.RelayAddress = address
|
||||
break
|
||||
|
@ -652,7 +660,7 @@ func (c *Client) Receive() (err error) {
|
|||
}
|
||||
|
||||
serverTry := fmt.Sprintf("%s:%s", ip, port)
|
||||
conn, banner2, externalIP, errConn := tcp.ConnectToTCPServer(serverTry, c.Options.RelayPassword, c.Options.SharedSecret[:3], 50*time.Millisecond)
|
||||
conn, banner2, externalIP, errConn := tcp.ConnectToTCPServer(serverTry, c.Options.RelayPassword, c.Options.RelayKeyPublic, c.Options.SharedSecret[:3], 50*time.Millisecond)
|
||||
if errConn != nil {
|
||||
log.Debugf("could not connect to " + serverTry)
|
||||
continue
|
||||
|
@ -909,6 +917,7 @@ func (c *Client) processMessagePake(m message.Message) (err error) {
|
|||
c.conn[j+1], _, _, err = tcp.ConnectToTCPServer(
|
||||
server,
|
||||
c.Options.RelayPassword,
|
||||
c.Options.RelayKeyPublic,
|
||||
fmt.Sprintf("%s-%d", utils.SHA256(c.Options.SharedSecret[:5])[:6], j),
|
||||
)
|
||||
if err != nil {
|
||||
|
|
|
@ -8,7 +8,10 @@ import (
|
|||
"crypto/sha256"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"filippo.io/age"
|
||||
"golang.org/x/crypto/argon2"
|
||||
|
@ -76,6 +79,64 @@ func Decrypt(encrypted []byte, key []byte) (plaintext []byte, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// GenerateIdentityAndPassword will generate a file with a public age identity and password
|
||||
func GenerateIdentityAndPassword(fname string) (err error) {
|
||||
keyPublic, keyPrivate, err := NewAge()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
password, err := GenerateRandomString(6)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = ioutil.WriteFile(fname, []byte(fmt.Sprintf("%s\n%s\n%s", keyPrivate, keyPublic, password)), 0644)
|
||||
return
|
||||
}
|
||||
|
||||
// LoadIdentityAndPassword will load a file with a public age identity and password
|
||||
func LoadIdentityAndPassword(fname string) (keyPrivate string, keyPublic string, password string, err error) {
|
||||
b, err := ioutil.ReadFile(fname)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
foo := strings.Fields(string(b))
|
||||
if len(foo) < 3 {
|
||||
err = fmt.Errorf("malformed file")
|
||||
return
|
||||
}
|
||||
keyPrivate = foo[0]
|
||||
keyPublic = foo[1]
|
||||
password = foo[2]
|
||||
|
||||
_, err = age.ParseX25519Identity(keyPrivate)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = age.ParseX25519Recipient(keyPublic)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GenerateRandomString returns a securely generated random string.
|
||||
// It will return an error if the system's secure random
|
||||
// number generator fails to function correctly, in which
|
||||
// case the caller should not continue.
|
||||
func GenerateRandomString(n int) (string, error) {
|
||||
const letters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||
ret := make([]byte, n)
|
||||
for i := 0; i < n; i++ {
|
||||
num, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters))))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
ret[i] = letters[num.Int64()]
|
||||
}
|
||||
|
||||
return string(ret), nil
|
||||
}
|
||||
|
||||
func NewAge() (pubkey string, privkey string, err error) {
|
||||
identity, err := age.GenerateX25519Identity()
|
||||
if err != nil {
|
||||
|
|
|
@ -2,8 +2,10 @@ package crypt
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/schollz/croc/v9/src/utils"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
@ -115,3 +117,19 @@ func TestEncryptionAge(t *testing.T) {
|
|||
assert.Nil(t, err)
|
||||
assert.Equal(t, msg, dec)
|
||||
}
|
||||
|
||||
func TestGenerate(t *testing.T) {
|
||||
err := GenerateIdentityAndPassword("test")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, utils.Exists("test"))
|
||||
keyPrivate, keyPublic, password, err := LoadIdentityAndPassword("test")
|
||||
assert.Nil(t, err)
|
||||
fmt.Println(keyPrivate)
|
||||
fmt.Println(keyPublic)
|
||||
fmt.Println(password)
|
||||
_, _, _, err = LoadIdentityAndPassword("crypt.go")
|
||||
assert.NotNil(t, err)
|
||||
_, _, _, err = LoadIdentityAndPassword("doesntexist")
|
||||
assert.NotNil(t, err)
|
||||
os.Remove("test")
|
||||
}
|
||||
|
|
|
@ -9,12 +9,13 @@ import (
|
|||
// TCP_BUFFER_SIZE is the maximum packet size
|
||||
const TCP_BUFFER_SIZE = 1024 * 64
|
||||
|
||||
// DEFAULT_RELAY is the default relay used (can be set using --relay)
|
||||
// DEFAULT_RELAY is the default relay used (can be set using --relay-pass)
|
||||
var (
|
||||
DEFAULT_RELAY = "croc.schollz.com"
|
||||
DEFAULT_RELAY6 = "croc6.schollz.com"
|
||||
DEFAULT_PORT = "9009"
|
||||
DEFAULT_PASSPHRASE = "pass123"
|
||||
DEFAULT_RELAY = "croc.schollz.com"
|
||||
DEFAULT_RELAY6 = "croc6.schollz.com"
|
||||
DEFAULT_PORT = "9009"
|
||||
DEFAULT_RELAY_PASSWORD = "ZiNO9Y"
|
||||
DEFAULT_RELAY_KEYPUBLIC = "age10yrxthzjrcr0e59nucg0epgnn0qpjv9rhsxqs90rdn335edgnueqrtdnyh"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
|
|
@ -90,7 +90,7 @@ func (s *server) start() (err error) {
|
|||
}
|
||||
|
||||
func (s *server) run() (err error) {
|
||||
log.Infof("starting TCP server on " + s.port)
|
||||
log.Debugf("starting TCP server on " + s.port)
|
||||
server, err := net.Listen("tcp", ":"+s.port)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error listening on %s: %w", s.port, err)
|
||||
|
|
Loading…
Reference in New Issue