Files
smt/models/key.go
Nathan Coad b4355ee913
All checks were successful
continuous-integration/drone/push Build is passing
more logging
2024-01-09 21:30:14 +11:00

111 lines
2.8 KiB
Go

package models
import (
"errors"
"fmt"
"log"
"os"
"path/filepath"
"golang.org/x/crypto/bcrypt"
)
const hashFileName = "verify.hash"
// TODO: Look at using shamir's secret sharing to distribute components of the secret key
var secretKey []byte
var secretReceived bool
func getHashFilePath() (string, error) {
dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
if err != nil {
return "", err
}
filePath := filepath.Join(dir, hashFileName)
return filePath, nil
}
func storeKeyHash(plaintext string, filePath string) error {
hash, err := bcrypt.GenerateFromPassword([]byte(plaintext), bcrypt.DefaultCost)
if err != nil {
log.Printf("storeKeyHash error generating hash : '%s'\n", err)
return err
}
err = os.WriteFile(filePath, hash, 0600)
if err != nil {
log.Printf("storeKeyHash error writing file : '%s'\n", err)
return err
}
log.Println("Bcrypt hash stored in file:", filePath)
return nil
}
func compareHashWithPlaintext(plaintext string, filePath string) (bool, error) {
hashBytes, err := os.ReadFile(filePath)
if err != nil {
log.Printf("compareHashWithPlaintext error reading hashfile : '%s'\n", err)
return false, err
}
err = bcrypt.CompareHashAndPassword(hashBytes, []byte(plaintext))
if err != nil {
if err == bcrypt.ErrMismatchedHashAndPassword {
log.Printf("compareHashWithPlaintext provided key is incorrect")
return false, nil // Passwords don't match
}
log.Printf("compareHashWithPlaintext error comparing provided key : '%s'\n", err)
return false, err // Other error occurred
}
return true, nil // Passwords match
}
func ReceiveKey(key string) error {
// confirm that the key is 32 bytes long exactly
if len(key) != 32 {
return errors.New("secret key provided is not exactly 32 bytes long")
}
// TODO hash the secret key and store it on disk so we can verify if correct secret key is received
filePath, _ := getHashFilePath()
if filePath != "" {
log.Printf("ReceiveKey detected hash file at '%s'\n", filePath)
// File already exists, compare received key with hash in file
compare, err := compareHashWithPlaintext(key, filePath)
if err != nil {
return fmt.Errorf("unable to verify secret key: '%s'", err.Error())
}
if !compare {
return errors.New("secret key is not correct")
}
} else {
log.Printf("ReceiveKey storing key into file '%s'\n", filePath)
storeKeyHash(key, filePath)
}
// Store the secret key in memory so that we can access it when encrypting/decrypting
secretKey = []byte(key)
secretReceived = true
return nil
}
func ProvideKey() ([]byte, error) {
// Provide the key when needed to decrypt/encrypt stored secrets
if secretReceived {
return secretKey, nil
} else {
return nil, errors.New("secret key has not been received")
}
}
func CheckKeyProvided() bool {
return secretReceived
}