diff --git a/back/cmd.go b/back/cmd.go index cb15c49..16be1eb 100644 --- a/back/cmd.go +++ b/back/cmd.go @@ -6,10 +6,12 @@ import ( "io" "os" "os/exec" + + "github.com/rwinkhart/go-boilerplate/security" ) -// WriteToStdin is a utility function that writes a string to a command's stdin. -func WriteToStdin(cmd *exec.Cmd, input string) error { +// WriteToStdin is a utility function that writes a byte slice to a command's stdin. +func WriteToStdinAndZeroizeInput(cmd *exec.Cmd, input []byte) error { stdin, err := cmd.StdinPipe() if err != nil { return errors.New("unable to access stdin for system command: " + err.Error()) @@ -18,16 +20,17 @@ func WriteToStdin(cmd *exec.Cmd, input string) error { defer func(stdin io.WriteCloser) { _ = stdin.Close() // error ignored; if stdin could be accessed, it can probably be closed }(stdin) - _, _ = io.WriteString(stdin, input) + _, _ = stdin.Write(input) + security.ZeroizeBytes(input) }() return nil } -// ReadFromStdin is a utility function that reads a string from stdin. -func ReadFromStdin() string { +// ReadFromStdin is a utility function that reads a byte slice from stdin. +func ReadFromStdin() []byte { scanner := bufio.NewScanner(os.Stdin) if scanner.Scan() { - return scanner.Text() + return scanner.Bytes() } - return "" + return nil } diff --git a/back/security.go b/back/security.go deleted file mode 100644 index 49bd416..0000000 --- a/back/security.go +++ /dev/null @@ -1,9 +0,0 @@ -package back - -// EraseBytesSecurely overwrites all -// bytes in a slice with zeros. -func EraseBytesSecurely(input []byte) { - for i := range input { - input[i] = 0 - } -} diff --git a/go.mod b/go.mod index 3583b19..52263bc 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,7 @@ module github.com/rwinkhart/go-boilerplate -go 1.25.6 +go 1.25.7 -require golang.org/x/term v0.39.0 +require golang.org/x/term v0.40.0 -require golang.org/x/sys v0.40.0 // indirect +require golang.org/x/sys v0.41.0 // indirect diff --git a/go.sum b/go.sum index a4e0649..64c0afa 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,4 @@ -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= -golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= +golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= diff --git a/stringy/gen.go b/security/gen.go similarity index 70% rename from stringy/gen.go rename to security/gen.go index fee0e93..9d1410d 100644 --- a/stringy/gen.go +++ b/security/gen.go @@ -1,20 +1,20 @@ -package stringy +package security import ( + "bytes" "crypto/rand" "fmt" "math" "math/big" - "strings" ) -// StringGen generates a random string of a specified length and complexity. -// Requires: complexity (minimum percentage of special characters to be returned in the generated string; set to 0 to generate a simple string), +// BytesGen generates a random byte slice of a specified length and complexity. +// Requires: complexity (minimum percentage of special characters to be returned in the generated output; set to 0 for a "simple" result), // complexCharsetLevel (1 = safe for filenames, 2 = safe for most password entries, 3 = safe only for well-made password entries) -func StringGen(length int, complexity float64, complexCharsetLevel uint8) string { - var actualSpecialChars int // track the number of special characters in the generated string +func BytesGen(length int, complexity float64, complexCharsetLevel uint8) []byte { + var actualSpecialChars int // track the number of special characters in the generated output var minSpecialChars int // track the minimum number of special characters to accept - var extendedCharset string // additions to character set used for complex strings + var extendedCharset string // additions to character set used for complex outputs charset := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" // default character set used for all strings const extendedCharsetFiles = "!#$%&+,-.;=@_~^()[]{}`'" // additional special characters for complex strings (safe in file names) @@ -34,34 +34,34 @@ func StringGen(length int, complexity float64, complexCharsetLevel uint8) string charset += extendedCharset } - // loop until a string of the desired complexity is generated + // loop until a byte slice of the desired complexity is generated for { - // generate a random string + // generate a random output result := make([]byte, length) for i := range result { val, _ := rand.Int(rand.Reader, big.NewInt(int64(len(charset)))) result[i] = charset[val.Int64()] } - // return early if the string is not complex + // return early if the desired output is not complex if complexity <= 0 { - return string(result) + return result } - // count the number of special characters in the generated string - for _, char := range string(result) { - if strings.ContainsRune(extendedCharset, char) { + // count the number of special characters in the generated output + for i := range result { + if bytes.Contains([]byte(extendedCharset), []byte{result[i]}) { actualSpecialChars++ } } - // return the generated string if it contains enough special characters + // return the generated output if it contains enough special characters if actualSpecialChars >= minSpecialChars { - return string(result) + return result } // reset special character counter - fmt.Println("Regenerating string until desired complexity is achieved...") + fmt.Println("Regenerating output until desired complexity is achieved...") actualSpecialChars = 0 } } diff --git a/security/security.go b/security/security.go new file mode 100644 index 0000000..b1d4b04 --- /dev/null +++ b/security/security.go @@ -0,0 +1,9 @@ +package security + +// ZeroizeBytes overwrites all +// bytes in a slice with zeros. +func ZeroizeBytes(input []byte) { + for i := range input { + input[i] = 0 + } +}