Added optional HIBP database check

Even though the generated passwords are generated in a secure
way, there is a minimal chance, that the same password was used
by someone before and this password was part of a leak.

If you want to be on the safe side, you can now use the "-p"
parameter, to have your newly generated password against the
HIBP (https://haveibeenpwned.com) database. This feature is
disabled by default, since it requires internet access and also
the API call might take ~500ms to 1sec.
This commit is contained in:
Winni Neessen 2021-04-29 12:22:10 +02:00
parent 0badd56291
commit 5a29d4bc19
Signed by: wneessen
GPG key ID: 385AC9889632126E
3 changed files with 58 additions and 0 deletions

13
apg.go
View file

@ -22,6 +22,7 @@ type Config struct {
useNumber bool useNumber bool
useSpecial bool useSpecial bool
humanReadable bool humanReadable bool
checkHibp bool
excludeChars string excludeChars string
newStyleModes string newStyleModes string
spellPassword bool spellPassword bool
@ -50,6 +51,8 @@ Options:
-H Avoid ambiguous characters in passwords (i. e.: 1, l, I, O, 0) (Default: off) -H Avoid ambiguous characters in passwords (i. e.: 1, l, I, O, 0) (Default: off)
-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)
'--> this feature requires internet connectivity
-h Show this help text -h Show this help text
-v Show version string` -v Show version string`
@ -96,5 +99,15 @@ func main() {
break break
} }
} }
if config.checkHibp {
isPwned, err := checkHibp(pwString)
if err != nil {
log.Printf("unable to check HIBP database: %v", err)
}
if isPwned {
fmt.Print("^-- !!WARNING: The previously generated password was found in HIPB database. Do not use it!!\n")
}
}
} }
} }

View file

@ -33,6 +33,7 @@ func parseFlags() Config {
flag.BoolVar(&switchConf.useComplex, "C", false, "Generate complex passwords (implies -L -U -N -S, disables -H)") flag.BoolVar(&switchConf.useComplex, "C", false, "Generate complex passwords (implies -L -U -N -S, disables -H)")
flag.BoolVar(&switchConf.humanReadable, "H", false, "Generate human-readable passwords") flag.BoolVar(&switchConf.humanReadable, "H", false, "Generate human-readable passwords")
flag.BoolVar(&config.spellPassword, "l", false, "Spell generated password") flag.BoolVar(&config.spellPassword, "l", false, "Spell generated password")
flag.BoolVar(&config.checkHibp, "p", false, "Check the HIBP database if the generated password was leaked before")
flag.BoolVar(&config.showVersion, "v", false, "Show version") flag.BoolVar(&config.showVersion, "v", false, "Show version")
flag.IntVar(&config.minPassLen, "m", DefaultMinLenght, "Minimum password length") flag.IntVar(&config.minPassLen, "m", DefaultMinLenght, "Minimum password length")
flag.IntVar(&config.maxPassLen, "x", DefaultMaxLenght, "Maxiumum password length") flag.IntVar(&config.maxPassLen, "x", DefaultMaxLenght, "Maxiumum password length")

44
hibp.go Normal file
View file

@ -0,0 +1,44 @@
package main
import (
"bufio"
"crypto/sha1"
"fmt"
"log"
"net/http"
"strings"
"time"
)
func checkHibp(p string) (bool, error) {
shaSum := fmt.Sprintf("%x", sha1.Sum([]byte(p)))
firstPart := shaSum[0:5]
secondPart := shaSum[5:]
isPwned := false
httpClient := &http.Client{Timeout: time.Second * 2}
httpRes, err := httpClient.Get("https://api.pwnedpasswords.com/range/" + firstPart)
if err != nil {
return false, err
}
defer func() {
err := httpRes.Body.Close()
if err != nil {
log.Printf("error while closing HTTP response body: %v", err)
}
}()
scanObj := bufio.NewScanner(httpRes.Body)
for scanObj.Scan() {
scanLine := strings.SplitN(scanObj.Text(), ":", 2)
if strings.ToLower(scanLine[0]) == secondPart {
isPwned = true
break
}
}
if err := scanObj.Err(); err != nil {
return isPwned, err
}
return isPwned, nil
}