From b86e733f6bfeeb9b7fcf7616be61bcaf42684659 Mon Sep 17 00:00:00 2001 From: Sam Anthony Date: Mon, 14 Apr 2025 20:06:14 -0400 Subject: load public signature verification key from disc --- key/box.go | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++ key/boxgen.go | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++ key/generate.go | 78 ----------------------------------------------------- key/key.go | 84 --------------------------------------------------------- key/sig.go | 54 +++++++++++++++++++++++++++++++++++++ 5 files changed, 209 insertions(+), 162 deletions(-) create mode 100644 key/box.go create mode 100644 key/boxgen.go delete mode 100644 key/generate.go delete mode 100644 key/key.go create mode 100644 key/sig.go diff --git a/key/box.go b/key/box.go new file mode 100644 index 0000000..05d8991 --- /dev/null +++ b/key/box.go @@ -0,0 +1,77 @@ +package key + +import ( + "bytes" + "encoding/hex" + "fmt" + "io" + "os" +) + +// BoxPublicKey is a public NaCl box key. +type BoxPublicKey [32]byte + +// BoxPrivateKey is a private NaCl box key. +type BoxPrivateKey [32]byte + +// LoadBoxKeypair reads the public and private NaCl box keys from disc, +// or generates a new keypair if it does not already exist. +// These keys can be used for NaCl box (encryption/decryption) operations. +func LoadBoxKeypair() (pub BoxPublicKey, priv BoxPrivateKey, err error) { + err = generateBoxKeypairIfNotExist() + if err != nil { + return + } + + pub, err = loadBoxKey(boxPubKeyFile) + if err != nil { + return + } + + priv, err = loadBoxKey(boxPrivKeyFile) + + return +} + +// LoadBoxPublicKey reads the public NaCl box key from disc, +// or generates a new keypair if it does not already exist. +func LoadBoxPublicKey() (BoxPublicKey, error) { + err := generateBoxKeypairIfNotExist() + if err != nil { + return BoxPublicKey{}, err + } + key, err := loadBoxKey(boxPubKeyFile) + return BoxPublicKey(key), err +} + +// loadBoxKey reads a NaCl box key (public or private) from the specified file. +func loadBoxKey(filename string) ([32]byte, error) { + // Open file. + f, err := os.Open(filename) + if err != nil { + return [32]byte{}, err + } + defer f.Close() + + // Read key from file. + buf, err := io.ReadAll(f) + if err != nil { + return [32]byte{}, err + } + + // Decode key. + var key [32]byte + if hex.DecodedLen(len(buf)) != len(key) { + return [32]byte{}, fmt.Errorf("malformed key: expected %d bytes; got %d", + len(key), hex.DecodedLen(len(buf))) + } + if _, err := hex.Decode(key[:], buf); err != nil { + return [32]byte{}, err + } + + return key, nil +} + +func (bpk1 BoxPublicKey) Compare(bpk2 BoxPublicKey) int { + return bytes.Compare(bpk1[:], bpk2[:]) +} diff --git a/key/boxgen.go b/key/boxgen.go new file mode 100644 index 0000000..bb4a61e --- /dev/null +++ b/key/boxgen.go @@ -0,0 +1,78 @@ +package key + +import ( + crypto_rand "crypto/rand" + "encoding/hex" + "fmt" + "golang.org/x/crypto/nacl/box" + "os" + + "git.samanthony.xyz/hose/util" +) + +// generateBoxKeypair generates a new public/private keypair for NaCl box +// (encryption/decryption) operations. It stores the private key in the private box +// key file and the public box key in the public key file. If either of the key files +// already exist, they will not be overwritten; instead an error will be returned. +func generateBoxKeypair() error { + util.Logf("generating new encryption/decryption keypair...") + + // Create public key file. + pubFile, err := createFile(boxPubKeyFile, pubFileMode) + if err != nil { + return err + } + defer pubFile.Close() + + // Create private key file. + privFile, err := createFile(boxPrivKeyFile, privFileMode) + if err != nil { + pubFile.Close() + _ = os.Remove(boxPubKeyFile) + return err + } + defer privFile.Close() + + // Generate keypair. + pubkey, privkey, err := box.GenerateKey(crypto_rand.Reader) + if err != nil { + return err + } + + // Write keypair to files. + buf := make([]byte, hex.EncodedLen(len(*pubkey))) + hex.Encode(buf, (*pubkey)[:]) + if _, err := pubFile.Write(buf); err != nil { + return err + } + buf = make([]byte, hex.EncodedLen(len(*privkey))) + hex.Encode(buf, (*privkey)[:]) + if _, err := privFile.Write(buf); err != nil { + return err + } + + return nil +} + +// generateBoxKeypairIfNotExist generates a NaCal box keypair if it doesn't already exist. +func generateBoxKeypairIfNotExist() error { + pubExists, err := fileExists(boxPubKeyFile) + if err != nil { + return err + } + privExists, err := fileExists(boxPrivKeyFile) + if err != nil { + return 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") + } + // Neither public nor private key file exists; generate new keypair. + return generateBoxKeypair() +} diff --git a/key/generate.go b/key/generate.go deleted file mode 100644 index bb4a61e..0000000 --- a/key/generate.go +++ /dev/null @@ -1,78 +0,0 @@ -package key - -import ( - crypto_rand "crypto/rand" - "encoding/hex" - "fmt" - "golang.org/x/crypto/nacl/box" - "os" - - "git.samanthony.xyz/hose/util" -) - -// generateBoxKeypair generates a new public/private keypair for NaCl box -// (encryption/decryption) operations. It stores the private key in the private box -// key file and the public box key in the public key file. If either of the key files -// already exist, they will not be overwritten; instead an error will be returned. -func generateBoxKeypair() error { - util.Logf("generating new encryption/decryption keypair...") - - // Create public key file. - pubFile, err := createFile(boxPubKeyFile, pubFileMode) - if err != nil { - return err - } - defer pubFile.Close() - - // Create private key file. - privFile, err := createFile(boxPrivKeyFile, privFileMode) - if err != nil { - pubFile.Close() - _ = os.Remove(boxPubKeyFile) - return err - } - defer privFile.Close() - - // Generate keypair. - pubkey, privkey, err := box.GenerateKey(crypto_rand.Reader) - if err != nil { - return err - } - - // Write keypair to files. - buf := make([]byte, hex.EncodedLen(len(*pubkey))) - hex.Encode(buf, (*pubkey)[:]) - if _, err := pubFile.Write(buf); err != nil { - return err - } - buf = make([]byte, hex.EncodedLen(len(*privkey))) - hex.Encode(buf, (*privkey)[:]) - if _, err := privFile.Write(buf); err != nil { - return err - } - - return nil -} - -// generateBoxKeypairIfNotExist generates a NaCal box keypair if it doesn't already exist. -func generateBoxKeypairIfNotExist() error { - pubExists, err := fileExists(boxPubKeyFile) - if err != nil { - return err - } - privExists, err := fileExists(boxPrivKeyFile) - if err != nil { - return 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") - } - // Neither public nor private key file exists; generate new keypair. - return generateBoxKeypair() -} diff --git a/key/key.go b/key/key.go deleted file mode 100644 index b3dd393..0000000 --- a/key/key.go +++ /dev/null @@ -1,84 +0,0 @@ -package key - -import ( - "bytes" - "encoding/hex" - "fmt" - "io" - "os" -) - -// BoxPublicKey is a public NaCl box key. -type BoxPublicKey [32]byte - -// BoxPrivateKey is a private NaCl box key. -type BoxPrivateKey [32]byte - -// SigPublicKey is a public NaCl signature verification key. -type SigPublicKey [32]byte - -// SigPrivateKey is a private NaCl signing key. -type SigPrivateKey [64]byte - -// LoadBoxKeypair reads the public and private NaCl box keys from disc, -// or generates a new keypair if it does not already exist. -// These keys can be used for NaCl box (encryption/decryption) operations. -func LoadBoxKeypair() (pub BoxPublicKey, priv BoxPrivateKey, err error) { - // Generate a keypair if it doesn't already exist. - err = generateBoxKeypairIfNotExist() - if err != nil { - return - } - - pub, err = loadBoxKey(boxPubKeyFile) - if err != nil { - return - } - - priv, err = loadBoxKey(boxPrivKeyFile) - - return -} - -// LoadBoxPublicKey reads the public NaCl box key from disc, -// or generates a new keypair if it does not already exist. -func LoadBoxPublicKey() (BoxPublicKey, error) { - key, err := loadBoxKey(boxPubKeyFile) - return BoxPublicKey(key), err -} - -// loadBoxKey reads a NaCl box key (public or private) from the specified file. -func loadBoxKey(filename string) ([32]byte, error) { - // Open file. - f, err := os.Open(filename) - if err != nil { - return [32]byte{}, err - } - defer f.Close() - - // Read key from file. - buf, err := io.ReadAll(f) - if err != nil { - return [32]byte{}, err - } - - // Decode key. - var key [32]byte - if hex.DecodedLen(len(buf)) != len(key) { - return [32]byte{}, fmt.Errorf("malformed key: expected %d bytes; got %d", - len(key), hex.DecodedLen(len(buf))) - } - if _, err := hex.Decode(key[:], buf); err != nil { - return [32]byte{}, err - } - - return key, nil -} - -func (bpk1 BoxPublicKey) Compare(bpk2 BoxPublicKey) int { - return bytes.Compare(bpk1[:], bpk2[:]) -} - -func (spk1 SigPublicKey) Compare(spk2 SigPublicKey) int { - return bytes.Compare(spk1[:], spk2[:]) -} diff --git a/key/sig.go b/key/sig.go new file mode 100644 index 0000000..c0bc515 --- /dev/null +++ b/key/sig.go @@ -0,0 +1,54 @@ +package key + +import ( + "bytes" + "encoding/hex" + "fmt" + "io" + "os" +) + +// SigPublicKey is a public NaCl signature verification key. +type SigPublicKey [32]byte + +// SigPrivateKey is a private NaCl signing key. +type SigPrivateKey [64]byte + +// LoadSigPublicKey reads the public signature verification key from disc, +// or generates a new keypair if it does not already exist. +func LoadSigPublicKey() (SigPublicKey, error) { + // Generate keypair if it doesn't already exist. + err := generateSigKeypairIfNotExist() + if err != nil { + return SigPublicKey{}, err + } + + // Open public key file. + f, err := os.Open(sigPubKeyFile) + if err != nil { + return SigPublicKey{}, err + } + defer f.Close() + + // Read key from file. + buf, err := io.ReadAll(f) + if err != nil { + return SigPublicKey{}, err + } + + // Decode key. + var key SigPublicKey + if hex.DecodedLen(len(buf)) != len(key) { + return SigPublicKey{}, fmt.Errorf("malformed key: expected %d bytes; got %d", + len(key), hex.DecodedLen(len(buf))) + } + if _, err := hex.Decode(key[:], buf); err != nil { + return SigPublicKey{}, err + } + + return key, nil +} + +func (spk1 SigPublicKey) Compare(spk2 SigPublicKey) int { + return bytes.Compare(spk1[:], spk2[:]) +} -- cgit v1.2.3