diff options
| author | Sam Anthony <sam@samanthony.xyz> | 2025-04-11 14:19:12 -0400 |
|---|---|---|
| committer | Sam Anthony <sam@samanthony.xyz> | 2025-04-11 14:19:12 -0400 |
| commit | b5901aa3caddd987c5f4b6bc1ab7f62249580fcc (patch) | |
| tree | 2555d5c7bc15979d7e363a6ef97587a70eff0844 | |
| parent | 434434f6fa361daf599f6e7a35aa3b85a664a17f (diff) | |
| download | hose-b5901aa3caddd987c5f4b6bc1ab7f62249580fcc.zip | |
load public key from file
| -rw-r--r-- | handshake.go | 5 | ||||
| -rw-r--r-- | key/file.go | 59 | ||||
| -rw-r--r-- | key/key.go | 29 | ||||
| -rw-r--r-- | key/keygen.go | 63 | ||||
| -rw-r--r-- | main.go | 9 |
5 files changed, 112 insertions, 53 deletions
diff --git a/handshake.go b/handshake.go index 9c7f1b2..e47813f 100644 --- a/handshake.go +++ b/handshake.go @@ -2,6 +2,7 @@ package main import ( "golang.org/x/sync/errgroup" + "net" "git.samanthony.xyz/hose/key" ) @@ -12,8 +13,8 @@ import ( func handshake(rhost string) error { logf("initiating handshake with %s...", rhost) var group errgroup.Group - group.Go(handshakeSend(rhost)) - group.Go(handshakeRecv(rhost)) + group.Go(func() error { return handshakeSend(rhost) }) + group.Go(func() error { return handshakeRecv(rhost) }) return group.Wait() } diff --git a/key/file.go b/key/file.go new file mode 100644 index 0000000..f96190a --- /dev/null +++ b/key/file.go @@ -0,0 +1,59 @@ +package key + +import ( + "errors" + "fmt" + "github.com/adrg/xdg" + "os" + "path/filepath" +) + +var ( + pubKeyFile = filepath.Join(xdg.DataHome, "hose", "pubkey") + pubKeyFileMode os.FileMode = 0644 + + privKeyFile = filepath.Join(xdg.DataHome, "hose", "privkey") + privKeyFileMode os.FileMode = 0600 +) + +// createFile creates a file with the specified permissions and returns it for writing. +// It does not truncate an existing file. If the file already exists, an error is returned. +func createFile(name string, mode os.FileMode) (*os.File, error) { + exists, err := fileExists(name) + if err != nil { + return nil, err // unexpected error. + } else if exists { + return nil, errFileExists(name) // file exists; do not overwrite. + } + // Does not exist; continue; + + f, err := os.Create(name) + if err != nil { + return nil, err + } + + if err := f.Chmod(mode); err != nil { + f.Close() + _ = os.Remove(name) + return nil, err + } + + return f, nil +} + +// fileExists returns a nil error and true/false if a file does/doesn't exist. +// If an error is encountered, a non-nil error is returned. +func fileExists(path string) (bool, error) { + _, err := os.Stat(path) + if errors.Is(err, os.ErrNotExist) { + return false, nil // file doesn't exist. + } else if err != nil { + return false, err // unexpected error. + } + return true, nil // file exists. +} + +// errFileExists constructs a 'file already exists' error message. +func errFileExists(path string) error { + return fmt.Errorf("%s: %s", os.ErrExist, path) +} diff --git a/key/key.go b/key/key.go new file mode 100644 index 0000000..a427769 --- /dev/null +++ b/key/key.go @@ -0,0 +1,29 @@ +package key + +import ( + "io" + "os" +) + +// LoadPublicKey reads the public key from disc, or generates a new keypair +// if it does not already exist. +func LoadPublicKey() ([32]byte, error) { + // Generate a keypair if it doesn't already exist. + if err := generateIfNoExist(); err != nil { + return [32]byte{}, err + } + + // Open key file. + f, err := os.Open(pubKeyFile) + if err != nil { + return [32]byte{}, err + } + defer f.Close() + + // Read key. + var pubkey [32]byte + if _, err := io.ReadFull(f, pubkey[:]); err != nil { + return [32]byte{}, err + } + return pubkey, nil +} diff --git a/key/keygen.go b/key/keygen.go index 9857b76..813df31 100644 --- a/key/keygen.go +++ b/key/keygen.go @@ -2,21 +2,9 @@ package key import ( crypto_rand "crypto/rand" - "errors" "fmt" - "os" - "path/filepath" - - "github.com/adrg/xdg" "golang.org/x/crypto/nacl/box" -) - -var ( - pubKeyFile = filepath.Join(xdg.DataHome, "hose", "pubkey") - pubKeyFileMode os.FileMode = 0644 - - privKeyFile = filepath.Join(xdg.DataHome, "hose", "privkey") - privKeyFileMode os.FileMode = 0600 + "os" ) // Generate generates a new public/private keypair. It stores the private key in the @@ -56,44 +44,25 @@ func Generate() error { return nil } -// createFile creates a file with the specified permissions and returns it for writing. -// It does not truncate an existing file. If the file already exists, an error is returned. -func createFile(name string, mode os.FileMode) (*os.File, error) { - exists, err := fileExists(name) +// Generate a keypair if it doesn't already exist. +func generateIfNoExist() error { + pubExists, err := fileExists(pubKeyFile) if err != nil { - return nil, err // unexpected error. - } else if exists { - return nil, errFileExists(name) // file exists; do not overwrite. + return err } - // Does not exist; continue; - - f, err := os.Create(name) + privExists, err := fileExists(privKeyFile) if err != nil { - return nil, err + return err } - if err := f.Chmod(mode); err != nil { - f.Close() - _ = os.Remove(name) - return nil, err + if pubExists && privExists { + // Keypair already exists. + return nil + } else if pubExists && !privExists { + return fmt.Errorf("found public key file but not private key file") + } else if privExists && !pubExists { + return fmt.Errorf("found private key file but not public key file") } - - return f, nil -} - -// fileExists returns a nil error and true/false if a file does/doesn't exist. -// If an error is encountered, a non-nil error is returned. -func fileExists(path string) (bool, error) { - _, err := os.Stat(path) - if errors.Is(err, os.ErrNotExist) { - return false, nil // file doesn't exist. - } else if err != nil { - return false, err // unexpected error. - } - return true, nil // file exists. -} - -// errFileExists constructs a 'file already exists' error message. -func errFileExists(path string) error { - return fmt.Errorf("%s: %s", os.ErrExist, path) + // Neither public nor private key file exists; generate new keypair. + return Generate() } @@ -12,17 +12,18 @@ import ( const ( port = "60321" network = "tcp" - usage = "Usage: hose <-r | -s <rhost>>" + usage = "Usage: hose <-handshake <rhost> | -r | -s <rhost>>" ) var ( - recvFlag = flag.Bool("r", false, "receive") - sendHost = flag.String("s", "", "send to remote host") + handshakeHost = flag.String("handshake", "", "exchange public keys with remote host") + recvFlag = flag.Bool("r", false, "receive") + sendHost = flag.String("s", "", "send to remote host") ) func main() { flag.Parse() - if *handshakeHost { + if *handshakeHost != "" { if err := handshake(*handshakeHost); err != nil { eprintf("%v\n", err) } |