args... still needs charset minimums (how?)

This commit is contained in:
2022-03-03 04:26:44 -05:00
parent 1cb6879786
commit 480dcd7e24
11 changed files with 254 additions and 2 deletions

View File

@@ -1,5 +1,12 @@
package pwgenerator
// Defaults.
const (
DefCount uint = 1
DefMaxLen uint = 256
DefMinLin uint = 1
)
// Pre-defined charsets.
var (
// upper contains the characters from 0x41 to 0x5a ([A-Z]).

View File

@@ -5,5 +5,7 @@ import (
)
var (
ErrBadType error = errors.New("cannot typeswitch; unsupported type")
ErrBadType error = errors.New("cannot typeswitch; unsupported type")
ErrTooSmall error = errors.New("password max length too short for specified required chars")
ErrSwitchedLenLimits error = errors.New("the max password length is shorter than the minimum password length")
)

View File

@@ -1,6 +1,9 @@
package pwgenerator
import (
"bytes"
"crypto/rand"
"math/big"
"sort"
)
@@ -31,3 +34,26 @@ func sortDedupe(charset *CharSet) {
return
}
/*
saferRandInt uses crypto/rand instead of math/rand to get a random number.
While this is cryptographically safer, I guarantee it's a much bigger pain to do.
*/
func saferRandInt(max int) (randInt int, err error) {
var max64 int64 = int64(max)
var cryptoInt *big.Int = big.NewInt(max64)
var cryptoReader *bytes.Buffer = new(bytes.Buffer)
var randInt64 int64
if cryptoInt, err = rand.Int(cryptoReader, cryptoInt); err != nil {
return
}
randInt64 = cryptoInt.Int64()
randInt = int(randInt64)
return
}

View File

@@ -18,6 +18,20 @@ func (c *CharSet) Less(i, j int) (isBefore bool) {
return
}
// RandChar returns a random character from a CharSet.
func (c *CharSet) RandChar() (char Char, err error) {
var selectIdx int
if selectIdx, err = saferRandInt(len(*c) - 1); err != nil {
return
}
char = (*c)[selectIdx]
return
}
// String returns a string from a CharSet.
func (c *CharSet) String() (s string) {

View File

@@ -2,12 +2,86 @@ package pwgenerator
import (
"strings"
"r00t2.io/goutils/multierr"
)
// Generate generates a list of passwords for a GenOpts.
func (o *GenOpts) Generate() (passwords []string, err error) {
// TODO
var passwds []string = make([]string, o.Count)
var charset CharSet = o.Chars()
var errs *multierr.MultiError = multierr.NewMultiError(nil)
if o.Count == 0 {
o.Count = DefCount
}
if o.LengthMax == 0 {
o.LengthMax = DefMaxLen
}
for idx, _ := range passwds {
if passwds[idx], err = o.generatePassword(charset); err != nil {
errs.AddError(err)
err = nil
}
}
passwords = passwds
if !errs.IsEmpty() {
err = errs
}
return
}
// generatePassword generates a single password from CharSet c.
func (o *GenOpts) generatePassword(c CharSet) (password string, err error) {
var maxMin uint
var trueMinLen uint
var passLenGap uint
var passLen int
var passAlloc []rune
// Sanity checks/error conditions.
maxMin = o.CountUpper + o.CountLower + o.CountSymbols + o.CountExtended
if maxMin > o.LengthMax {
err = ErrTooSmall
return
}
if o.LengthMin > o.LengthMax {
err = ErrSwitchedLenLimits
return
}
// Defaults.
trueMinLen = o.LengthMin
if trueMinLen == 0 {
trueMinLen = DefMinLin
}
// Get a fixed password length...
passLenGap = o.LengthMax - trueMinLen
if passLen, err = saferRandInt(int(passLenGap)); err != nil {
return
}
passLen = passLen + int(trueMinLen) // (We need to re-add; it was subtracted above to get a zero-shifted number for start in saferRandInt.)
// And make the rune slice of that length.
passAlloc = make([]rune, passLen)
for _, idx := range passAlloc {
var char Char
if char, err = c.RandChar(); err != nil {
return
}
passAlloc[idx] = rune(char)
}
password = string(passAlloc)
return
}
@@ -35,6 +109,8 @@ func (o *GenOpts) Chars() (chars CharSet) {
chars = append(chars, extendedSymbols...)
}
// TODO: Count* fields
return
}