mirror of
https://github.com/wneessen/apg-go.git
synced 2024-12-23 11:40:38 +01:00
Merge pull request #32 from wneessen/issue27_pronouncable
Issue 27 -> pronouncable passwords
This commit is contained in:
commit
9d3417738d
6 changed files with 174 additions and 39 deletions
|
@ -4,16 +4,28 @@
|
|||
<option name="autoReloadType" value="ALL" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="e32960c0-29e5-4669-9fc2-ef12314486ce" name="Changes" comment="">
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<list default="true" id="e32960c0-29e5-4669-9fc2-ef12314486ce" name="Changes" comment="Added pronounceable passwords #27">
|
||||
<change beforePath="$PROJECT_DIR$/cmd/apg/apg.go" beforeDir="false" afterPath="$PROJECT_DIR$/cmd/apg/apg.go" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="FileTemplateManagerImpl">
|
||||
<option name="RECENT_TEMPLATES">
|
||||
<list>
|
||||
<option value="Go File" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="GOROOT" url="file://$PROJECT_DIR$/../../go1.17.1" />
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_BRANCH_BY_REPOSITORY">
|
||||
<map>
|
||||
<entry key="$PROJECT_DIR$" value="main" />
|
||||
</map>
|
||||
</option>
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="GoLibraries">
|
||||
|
@ -25,6 +37,7 @@
|
|||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent">
|
||||
<property name="DefaultGoTemplateProperty" value="Go File" />
|
||||
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
|
||||
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
|
||||
<property name="WebServerToolWindowFactoryState" value="true" />
|
||||
|
@ -66,6 +79,11 @@
|
|||
</option>
|
||||
<option name="oldMeFiltersMigrated" value="true" />
|
||||
</component>
|
||||
<component name="VcsManagerConfiguration">
|
||||
<MESSAGE value="IDE settings..." />
|
||||
<MESSAGE value="Added pronounceable passwords #27" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="Added pronounceable passwords #27" />
|
||||
</component>
|
||||
<component name="VgoProject">
|
||||
<integration-enabled>true</integration-enabled>
|
||||
</component>
|
||||
|
|
22
chars/koremutake.go
Normal file
22
chars/koremutake.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
package chars
|
||||
|
||||
// KoremutakeSyllables is a slightly modified Koremutake syllabels list based on
|
||||
// the mechanism described on https://shorl.com/koremutake.php
|
||||
var KoremutakeSyllables = []string{"ba", "be", "bi", "bo", "bu", "by", "da", "de", "di",
|
||||
"do", "du", "dy", "fe", "fi", "fo", "fu", "fy", "ga", "ge", "gi", "go", "gu",
|
||||
"gy", "ha", "he", "hi", "ho", "hu", "hy", "ja", "je", "ji", "jo", "ju", "jy",
|
||||
"ka", "ke", "ko", "ku", "ky", "la", "le", "li", "lo", "lu", "ly", "ma",
|
||||
"me", "mi", "mo", "mu", "my", "na", "ne", "ni", "no", "nu", "ny", "pa", "pe",
|
||||
"pi", "po", "pu", "py", "ra", "re", "ri", "ro", "ru", "ry", "sa", "se",
|
||||
"si", "so", "su", "sy", "ta", "te", "ti", "to", "tu", "ty", "va", "ve", "vi",
|
||||
"vo", "vu", "vy", "bra", "bre", "bri", "bro", "bru", "bry", "dra", "dre",
|
||||
"dri", "dro", "dru", "dry", "fra", "fre", "fri", "fro", "fru", "fry", "gra",
|
||||
"gre", "gri", "gro", "gru", "gry", "pra", "pre", "pri", "pro", "pru",
|
||||
"pry", "sta", "ste", "sti", "sto", "stu", "sty", "tra", "tre", "er", "ed",
|
||||
"in", "ex", "al", "en", "an", "ad", "or", "at", "ca", "ap", "el", "ci", "an",
|
||||
"et", "it", "ob", "of", "af", "au", "cy", "im", "op", "co", "up", "ing",
|
||||
"con", "ter", "com", "per", "ble", "der", "cal", "man", "est", "for", "mer",
|
||||
"col", "ful", "get", "low", "son", "tle", "day", "pen", "pre", "ten",
|
||||
"tor", "ver", "ber", "can", "ple", "fer", "gen", "den", "mag", "sub", "sur",
|
||||
"men", "min", "out", "tal", "but", "cit", "cle", "cov", "dif", "ern",
|
||||
"eve", "hap", "ket", "nal", "sup", "ted", "tem", "tin", "tro", "tro"}
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/wneessen/go-hibp"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -23,6 +24,9 @@ apg [-m <length>] [-x <length>] [-L] [-U] [-N] [-S] [-H] [-C]
|
|||
[-l] [-M mode] [-E char_string] [-n num_of_pass] [-v] [-h]
|
||||
|
||||
Options:
|
||||
-a ALGORITH Choose the password generation algorithm (Default: 1)
|
||||
- 0: pronounceable password generation (koremutake syllables)
|
||||
- 1: random password generation according to password modes/flags
|
||||
-m LENGTH Minimum length of the password to be generated (Default: 12)
|
||||
-x LENGTH Maximum length of the password to be generated (Default: 20)
|
||||
-n NUMBER Amount of password to be generated (Default: 6)
|
||||
|
@ -36,7 +40,7 @@ Options:
|
|||
-C Enable complex password mode (implies -L -U -N -S and disables -H) (Default: off)
|
||||
-l Spell generated passwords in phonetic alphabet (Default: off)
|
||||
-p Check the HIBP database if the generated passwords was found in a leak before (Default: off)
|
||||
'--> this feature requires internet connectivity
|
||||
- Note: this feature requires internet connectivity
|
||||
-h Show this help text
|
||||
-v Show version string`
|
||||
|
||||
|
@ -56,37 +60,80 @@ func main() {
|
|||
os.Exit(0)
|
||||
}
|
||||
|
||||
// Set PW length and available characterset
|
||||
charRange := chars.GetRange(&cfgObj)
|
||||
pwList := make([]string, 0)
|
||||
sylList := map[string][]string{}
|
||||
|
||||
// Generate passwords
|
||||
for i := 1; i <= cfgObj.NumOfPass; i++ {
|
||||
// Choose the type of password generation based on the selected algo
|
||||
for i := 0; i < cfgObj.NumOfPass; i++ {
|
||||
pwLength := config.GetPwLengthFromParams(&cfgObj)
|
||||
pwString, err := random.GetChar(&charRange, pwLength)
|
||||
if err != nil {
|
||||
log.Fatalf("error generating random character range: %s\n", err)
|
||||
}
|
||||
|
||||
switch cfgObj.PwAlgo {
|
||||
case 0:
|
||||
pwString := ""
|
||||
pwSyls := make([]string, 0)
|
||||
|
||||
charSylSet := chars.KoremutakeSyllables
|
||||
charSylSet = append(charSylSet,
|
||||
strings.Split(chars.PwNumbersHuman, "")...)
|
||||
charSylSet = append(charSylSet,
|
||||
strings.Split(chars.PwSpecialCharsHuman, "")...)
|
||||
charSylSetLen := len(charSylSet)
|
||||
for len(pwString) < pwLength {
|
||||
randNum, err := random.GetNum(charSylSetLen)
|
||||
if err != nil {
|
||||
log.Fatalf("error generating Koremutake syllable: %s", err)
|
||||
}
|
||||
nextSyl := charSylSet[randNum]
|
||||
if random.CoinFlip() {
|
||||
sylLen := len(nextSyl)
|
||||
charPos, err := random.GetNum(sylLen)
|
||||
if err != nil {
|
||||
log.Fatalf("error generating random number: %s", err)
|
||||
}
|
||||
ucChar := string(nextSyl[charPos])
|
||||
nextSyl = strings.ReplaceAll(nextSyl, ucChar, strings.ToUpper(ucChar))
|
||||
}
|
||||
|
||||
pwString += nextSyl
|
||||
pwSyls = append(pwSyls, nextSyl)
|
||||
}
|
||||
pwList = append(pwList, pwString)
|
||||
sylList[pwString] = pwSyls
|
||||
default:
|
||||
charRange := chars.GetRange(&cfgObj)
|
||||
pwString, err := random.GetChar(&charRange, pwLength)
|
||||
if err != nil {
|
||||
log.Fatalf("error generating random character range: %s\n", err)
|
||||
}
|
||||
pwList = append(pwList, pwString)
|
||||
}
|
||||
}
|
||||
|
||||
for _, p := range pwList {
|
||||
switch cfgObj.OutputMode {
|
||||
case 1:
|
||||
{
|
||||
spelledPw, err := spelling.String(pwString)
|
||||
spelledPw, err := spelling.String(p)
|
||||
if err != nil {
|
||||
log.Fatalf("error spelling out password: %s\n", err)
|
||||
}
|
||||
fmt.Printf("%v (%v)\n", p, spelledPw)
|
||||
case 2:
|
||||
fmt.Printf("%s", p)
|
||||
if cfgObj.SpellPron {
|
||||
spelledPw, err := spelling.Koremutake(sylList[p])
|
||||
if err != nil {
|
||||
log.Fatalf("error spelling out password: %s\n", err)
|
||||
log.Fatalf("error spelling out password: %s", err)
|
||||
}
|
||||
fmt.Printf("%v (%v)\n", pwString, spelledPw)
|
||||
break
|
||||
fmt.Printf(" (%s)", spelledPw)
|
||||
}
|
||||
fmt.Println()
|
||||
default:
|
||||
{
|
||||
fmt.Println(pwString)
|
||||
break
|
||||
}
|
||||
fmt.Println(p)
|
||||
}
|
||||
|
||||
if cfgObj.CheckHibp {
|
||||
hc := hibp.New(hibp.WithHttpTimeout(time.Second*2), hibp.WithPwnedPadding())
|
||||
pwnObj, _, err := hc.PwnedPassApi.CheckPassword(pwString)
|
||||
pwnObj, _, err := hc.PwnedPassApi.CheckPassword(p)
|
||||
if err != nil {
|
||||
log.Printf("unable to check HIBP database: %v", err)
|
||||
}
|
||||
|
|
|
@ -9,22 +9,24 @@ import (
|
|||
// Config is a struct that holds the different config parameters for the apg-go
|
||||
// application
|
||||
type Config struct {
|
||||
MinPassLen int
|
||||
MaxPassLen int
|
||||
NumOfPass int
|
||||
UseComplex bool
|
||||
UseLowerCase bool
|
||||
UseUpperCase bool
|
||||
UseNumber bool
|
||||
UseSpecial bool
|
||||
HumanReadable bool
|
||||
CheckHibp bool
|
||||
ExcludeChars string
|
||||
NewStyleModes string
|
||||
SpellPassword bool
|
||||
ShowHelp bool
|
||||
ShowVersion bool
|
||||
OutputMode int
|
||||
MinPassLen int // Minimum password length
|
||||
MaxPassLen int // Maximum password length
|
||||
NumOfPass int // Number of passwords to be generated
|
||||
UseComplex bool // Force complex password generation (implies all other Use* Options to be true)
|
||||
UseLowerCase bool // Allow lower-case chars in passwords
|
||||
UseUpperCase bool // Allow upper-case chars in password
|
||||
UseNumber bool // Allow numbers in passwords
|
||||
UseSpecial bool // Allow special chars in passwords
|
||||
HumanReadable bool // Generated passwords use the "human readable" character set
|
||||
CheckHibp bool // Check generated are validated against the HIBP API for possible leaks
|
||||
ExcludeChars string // List of characters to be excluded from the PW generation charset
|
||||
NewStyleModes string // Use the "new style" parameters instead of the single params
|
||||
SpellPassword bool // Spell out passwords in the output
|
||||
ShowHelp bool // Display the help message in the CLI
|
||||
ShowVersion bool // Display the version string in the CLI
|
||||
OutputMode int // Interal parameter to control the output mode of the CLI
|
||||
PwAlgo int // PW generation algorithm to use (0: random PW based on flags, 1: pronouncable)
|
||||
SpellPron bool // Spell out the pronouncable password
|
||||
}
|
||||
|
||||
// DefaultMinLength reflects the default minimum length of a generated password
|
||||
|
@ -33,6 +35,9 @@ const DefaultMinLength int = 12
|
|||
// DefaultMaxLength reflects the default maximum length of a generated password
|
||||
const DefaultMaxLength int = 20
|
||||
|
||||
// DefaultPwAlgo reflects the default password generation algorithm
|
||||
const DefaultPwAlgo int = 1
|
||||
|
||||
// New parses the CLI flags and returns a new config object
|
||||
func New() Config {
|
||||
var switchConf Config
|
||||
|
@ -69,6 +74,8 @@ func New() Config {
|
|||
flag.StringVar(&config.ExcludeChars, "E", "", "Exclude list of characters from generated password")
|
||||
flag.StringVar(&config.NewStyleModes, "M", "",
|
||||
"New style password parameters (higher priority than single parameters)")
|
||||
flag.IntVar(&config.PwAlgo, "a", DefaultPwAlgo, "Password generation algorithm")
|
||||
flag.BoolVar(&config.SpellPron, "t", false, "In pronouncable password mode, spell out the password")
|
||||
flag.Parse()
|
||||
|
||||
// Invert-switch the defaults
|
||||
|
@ -118,8 +125,14 @@ func parseParams(config *Config) {
|
|||
}
|
||||
|
||||
// Set output mode
|
||||
if config.SpellPassword {
|
||||
config.OutputMode = 1
|
||||
switch config.PwAlgo {
|
||||
case 0:
|
||||
config.OutputMode = 2
|
||||
default:
|
||||
config.OutputMode = 0
|
||||
if config.SpellPassword {
|
||||
config.OutputMode = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,3 +48,11 @@ func GetNum(maxNum int) (int, error) {
|
|||
}
|
||||
return randNum, nil
|
||||
}
|
||||
|
||||
// CoinFlip performs a simple coinflip based on the rand library and returns true or false
|
||||
func CoinFlip() bool {
|
||||
num := big.NewInt(2)
|
||||
cf, _ := rand.Int(rand.Reader, num)
|
||||
r := int(cf.Int64())
|
||||
return r == 1
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package spelling
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/wneessen/apg-go/chars"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
@ -93,6 +94,32 @@ func String(pwString string) (string, error) {
|
|||
return strings.Join(returnString, "/"), nil
|
||||
}
|
||||
|
||||
// Koremutake returns the spelling of the Koremutake password with numbers and special
|
||||
// chars spelled out in english language
|
||||
func Koremutake(sylList []string) (string, error) {
|
||||
var returnString []string
|
||||
for _, curSyl := range sylList {
|
||||
isKore := false
|
||||
for _, x := range chars.KoremutakeSyllables {
|
||||
if x == strings.ToLower(curSyl) {
|
||||
isKore = true
|
||||
}
|
||||
}
|
||||
|
||||
if isKore {
|
||||
returnString = append(returnString, curSyl)
|
||||
continue
|
||||
}
|
||||
|
||||
curSpellString, err := ConvertCharToName(curSyl[0])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
returnString = append(returnString, curSpellString)
|
||||
}
|
||||
return strings.Join(returnString, "-"), nil
|
||||
}
|
||||
|
||||
// ConvertCharToName converts a given ascii byte into the corresponding english spelled
|
||||
// name
|
||||
func ConvertCharToName(charByte byte) (string, error) {
|
||||
|
|
Loading…
Reference in a new issue