mirror of
https://github.com/wneessen/apg-go.git
synced 2024-11-22 13:50:49 +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" />
|
<option name="autoReloadType" value="ALL" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="e32960c0-29e5-4669-9fc2-ef12314486ce" name="Changes" comment="">
|
<list default="true" id="e32960c0-29e5-4669-9fc2-ef12314486ce" name="Changes" comment="Added pronounceable passwords #27">
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/cmd/apg/apg.go" beforeDir="false" afterPath="$PROJECT_DIR$/cmd/apg/apg.go" afterDir="false" />
|
||||||
</list>
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||||
</component>
|
</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="GOROOT" url="file://$PROJECT_DIR$/../../go1.17.1" />
|
||||||
<component name="Git.Settings">
|
<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$" />
|
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||||
</component>
|
</component>
|
||||||
<component name="GoLibraries">
|
<component name="GoLibraries">
|
||||||
|
@ -25,6 +37,7 @@
|
||||||
<option name="showLibraryContents" value="true" />
|
<option name="showLibraryContents" value="true" />
|
||||||
</component>
|
</component>
|
||||||
<component name="PropertiesComponent">
|
<component name="PropertiesComponent">
|
||||||
|
<property name="DefaultGoTemplateProperty" value="Go File" />
|
||||||
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
|
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
|
||||||
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
|
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
|
||||||
<property name="WebServerToolWindowFactoryState" value="true" />
|
<property name="WebServerToolWindowFactoryState" value="true" />
|
||||||
|
@ -66,6 +79,11 @@
|
||||||
</option>
|
</option>
|
||||||
<option name="oldMeFiltersMigrated" value="true" />
|
<option name="oldMeFiltersMigrated" value="true" />
|
||||||
</component>
|
</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">
|
<component name="VgoProject">
|
||||||
<integration-enabled>true</integration-enabled>
|
<integration-enabled>true</integration-enabled>
|
||||||
</component>
|
</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"
|
"github.com/wneessen/go-hibp"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"time"
|
"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]
|
[-l] [-M mode] [-E char_string] [-n num_of_pass] [-v] [-h]
|
||||||
|
|
||||||
Options:
|
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)
|
-m LENGTH Minimum length of the password to be generated (Default: 12)
|
||||||
-x LENGTH Maximum length of the password to be generated (Default: 20)
|
-x LENGTH Maximum length of the password to be generated (Default: 20)
|
||||||
-n NUMBER Amount of password to be generated (Default: 6)
|
-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)
|
-C Enable complex password mode (implies -L -U -N -S and disables -H) (Default: off)
|
||||||
-l Spell generated passwords in phonetic alphabet (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)
|
-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
|
-h Show this help text
|
||||||
-v Show version string`
|
-v Show version string`
|
||||||
|
|
||||||
|
@ -56,37 +60,80 @@ func main() {
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set PW length and available characterset
|
pwList := make([]string, 0)
|
||||||
charRange := chars.GetRange(&cfgObj)
|
sylList := map[string][]string{}
|
||||||
|
|
||||||
// Generate passwords
|
// Choose the type of password generation based on the selected algo
|
||||||
for i := 1; i <= cfgObj.NumOfPass; i++ {
|
for i := 0; i < cfgObj.NumOfPass; i++ {
|
||||||
pwLength := config.GetPwLengthFromParams(&cfgObj)
|
pwLength := config.GetPwLengthFromParams(&cfgObj)
|
||||||
|
|
||||||
|
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)
|
pwString, err := random.GetChar(&charRange, pwLength)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("error generating random character range: %s\n", err)
|
log.Fatalf("error generating random character range: %s\n", err)
|
||||||
}
|
}
|
||||||
|
pwList = append(pwList, pwString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range pwList {
|
||||||
switch cfgObj.OutputMode {
|
switch cfgObj.OutputMode {
|
||||||
case 1:
|
case 1:
|
||||||
{
|
spelledPw, err := spelling.String(p)
|
||||||
spelledPw, err := spelling.String(pwString)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("error spelling out password: %s\n", err)
|
log.Fatalf("error spelling out password: %s\n", err)
|
||||||
}
|
}
|
||||||
fmt.Printf("%v (%v)\n", pwString, spelledPw)
|
fmt.Printf("%v (%v)\n", p, spelledPw)
|
||||||
break
|
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", err)
|
||||||
}
|
}
|
||||||
|
fmt.Printf(" (%s)", spelledPw)
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
default:
|
default:
|
||||||
{
|
fmt.Println(p)
|
||||||
fmt.Println(pwString)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfgObj.CheckHibp {
|
if cfgObj.CheckHibp {
|
||||||
hc := hibp.New(hibp.WithHttpTimeout(time.Second*2), hibp.WithPwnedPadding())
|
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 {
|
if err != nil {
|
||||||
log.Printf("unable to check HIBP database: %v", err)
|
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
|
// Config is a struct that holds the different config parameters for the apg-go
|
||||||
// application
|
// application
|
||||||
type Config struct {
|
type Config struct {
|
||||||
MinPassLen int
|
MinPassLen int // Minimum password length
|
||||||
MaxPassLen int
|
MaxPassLen int // Maximum password length
|
||||||
NumOfPass int
|
NumOfPass int // Number of passwords to be generated
|
||||||
UseComplex bool
|
UseComplex bool // Force complex password generation (implies all other Use* Options to be true)
|
||||||
UseLowerCase bool
|
UseLowerCase bool // Allow lower-case chars in passwords
|
||||||
UseUpperCase bool
|
UseUpperCase bool // Allow upper-case chars in password
|
||||||
UseNumber bool
|
UseNumber bool // Allow numbers in passwords
|
||||||
UseSpecial bool
|
UseSpecial bool // Allow special chars in passwords
|
||||||
HumanReadable bool
|
HumanReadable bool // Generated passwords use the "human readable" character set
|
||||||
CheckHibp bool
|
CheckHibp bool // Check generated are validated against the HIBP API for possible leaks
|
||||||
ExcludeChars string
|
ExcludeChars string // List of characters to be excluded from the PW generation charset
|
||||||
NewStyleModes string
|
NewStyleModes string // Use the "new style" parameters instead of the single params
|
||||||
SpellPassword bool
|
SpellPassword bool // Spell out passwords in the output
|
||||||
ShowHelp bool
|
ShowHelp bool // Display the help message in the CLI
|
||||||
ShowVersion bool
|
ShowVersion bool // Display the version string in the CLI
|
||||||
OutputMode int
|
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
|
// 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
|
// DefaultMaxLength reflects the default maximum length of a generated password
|
||||||
const DefaultMaxLength int = 20
|
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
|
// New parses the CLI flags and returns a new config object
|
||||||
func New() Config {
|
func New() Config {
|
||||||
var switchConf 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.ExcludeChars, "E", "", "Exclude list of characters from generated password")
|
||||||
flag.StringVar(&config.NewStyleModes, "M", "",
|
flag.StringVar(&config.NewStyleModes, "M", "",
|
||||||
"New style password parameters (higher priority than single parameters)")
|
"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()
|
flag.Parse()
|
||||||
|
|
||||||
// Invert-switch the defaults
|
// Invert-switch the defaults
|
||||||
|
@ -118,9 +125,15 @@ func parseParams(config *Config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set output mode
|
// Set output mode
|
||||||
|
switch config.PwAlgo {
|
||||||
|
case 0:
|
||||||
|
config.OutputMode = 2
|
||||||
|
default:
|
||||||
|
config.OutputMode = 0
|
||||||
if config.SpellPassword {
|
if config.SpellPassword {
|
||||||
config.OutputMode = 1
|
config.OutputMode = 1
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the new style parameters
|
// Parse the new style parameters
|
||||||
|
|
|
@ -48,3 +48,11 @@ func GetNum(maxNum int) (int, error) {
|
||||||
}
|
}
|
||||||
return randNum, nil
|
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 (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/wneessen/apg-go/chars"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -93,6 +94,32 @@ func String(pwString string) (string, error) {
|
||||||
return strings.Join(returnString, "/"), nil
|
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
|
// ConvertCharToName converts a given ascii byte into the corresponding english spelled
|
||||||
// name
|
// name
|
||||||
func ConvertCharToName(charByte byte) (string, error) {
|
func ConvertCharToName(charByte byte) (string, error) {
|
||||||
|
|
Loading…
Reference in a new issue