diff options
| author | Sam Anthony <sam@samanthony.xyz> | 2025-04-16 16:30:29 -0400 |
|---|---|---|
| committer | Sam Anthony <sam@samanthony.xyz> | 2025-04-16 16:30:29 -0400 |
| commit | 87fe785ef685a150891413dbb71a3f0e903e3645 (patch) | |
| tree | 28030356ed9390b46df7aeba08c9f4ff853f55b8 /key/generate.go | |
| parent | da12ad5b7b725c44aa3ef56163953cb9c57b7c04 (diff) | |
| download | hose-87fe785ef685a150891413dbb71a3f0e903e3645.zip | |
refactor key generation
Diffstat (limited to 'key/generate.go')
| -rw-r--r-- | key/generate.go | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/key/generate.go b/key/generate.go new file mode 100644 index 0000000..d7480c9 --- /dev/null +++ b/key/generate.go @@ -0,0 +1,126 @@ +package key + +import ( + crypto_rand "crypto/rand" + "encoding/hex" + "fmt" + "golang.org/x/crypto/nacl/box" + "golang.org/x/crypto/nacl/sign" + "io" + + "git.samanthony.xyz/hose/util" +) + +// A keyGenerator generates a new keypair from a random bitstream. +type keyGenerator func(rand io.Reader) (publicKey, privateKey []byte, err error) + +// generateKeypair uses a key generator function to create a new public/private keypair. +// The public key is saved to the public file, and the private key is saved to the private file. +// If either of the files already exist, an error is returned. +func generateKeypair(generate keyGenerator, pubFileName, privFileName string) error { + // Create public key file. + pubFile, err := createFileIfNotExist(pubFileName, pubFileMode) + if err != nil { + return err + } + defer pubFile.Close() + + // Create private key file. + privFile, err := createFileIfNotExist(privFileName, privFileMode) + if err != nil { + return err + } + defer privFile.Close() + + // Generate keypair. + pubkey, privkey, err := generate(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 +} + +// If neither the public file nor private file exist, generateKeypair uses the key generator +// function to create a new keypair. The public key is saved to the public key file, +// and the private key is saved to the private key file. +func generateKeypairIfNotExist(generate keyGenerator, pubFile, privFile string) error { + pubExists, err := fileExists(pubFile) + if err != nil { + return err + } + privExists, err := fileExists(privFile) + 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 generateKeypair(generate, pubFile, privFile) +} + +// 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 { + return generateKeypair(boxKeyGenerator, boxPubKeyFile, boxPrivKeyFile) +} + +// generateBoxKeypairIfNotExist generates a NaCal box keypair if it doesn't already exist. +func generateBoxKeypairIfNotExist() error { + return generateKeypairIfNotExist(boxKeyGenerator, boxPubKeyFile, boxPrivKeyFile) +} + +// NaCl box (encrypt/decrypt) keypair generator for use with generateKeypair(). +func boxKeyGenerator(rand io.Reader) (publicKey, privateKey []byte, err error) { + util.Logf("generating new encryption/decryption keypair...") + pub, priv, err := box.GenerateKey(rand) + if err != nil { + return []byte{}, []byte{}, err + } + return (*pub)[:], (*priv)[:], nil +} + +// generateSigKeypair generates a new NaCl sign/verify keypair. +// It stores the private signing key in the private signing key file +// and the public verification key in the public verification key file. +// If either of the key files already exist, they will not be overwritten; +// instead an error will be returned. +func generateSigKeypair() error { + util.Logf("generating new sign/verify keypair...") + return generateKeypair(sigKeyGenerator, sigPubKeyFile, sigPrivKeyFile) +} + +// generateSigKeypairIfNotExist generates a NaCl sign/verify keypair if it doesn't already exist. +func generateSigKeypairIfNotExist() error { + return generateKeypairIfNotExist(sigKeyGenerator, sigPubKeyFile, sigPrivKeyFile) +} + +// NaCl sign/verify keypair generator for use with generateKeypair(). +func sigKeyGenerator(rand io.Reader) (publicKey, privateKey []byte, err error) { + pub, priv, err := sign.GenerateKey(rand) + if err != nil { + return []byte{}, []byte{}, err + } + return (*pub)[:], (*priv)[:], nil +} |