Merge pull request #26 from wneessen/v0.3.2

V0.3.2
This commit is contained in:
Winni Neessen 2021-04-29 14:10:14 +02:00 committed by GitHub
commit 913f79c634
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 208 additions and 9 deletions

105
README.md
View file

@ -89,6 +89,106 @@ It is recommed to install apg in a directory of your ```$PATH``` environment. To
```sh ```sh
$ sudo cp apg /usr/local/bin/apg $ sudo cp apg /usr/local/bin/apg
``` ```
## Usage examples
### Default behaviour
By default apg-go will generate 6 passwords, with a minimum length of 12 characters and a
maxiumum length of 20 characters. The generated password will use a character set constructed
from lower case, upper case and numeric characters.
```shell
$ ./apg-go
R8rCC8bw5NvJmTUK2g
cHB9qogTbfdzFgnH
hoHfpWAHHSNa4Q
QyjscIsZkQGh
904YqsU5SnoqLo2w
utdFKXdeiXFzM
```
### Modifying the character sets
#### Old style
Let's assume you want to generate a single password, constructed out of upper case, numeric
and special characters. Since lower case is part of the default set, you would need to disable them
by setting the `-L` parameter. In addition you would set the `-S` parameter to enable special
characters. Finally the parameter `-n 1` is needed to keep apg-go from generating more than one
password:
```shell
$ ./apg-go -n 1 -L -S
XY7>}H@5U40&_A1*9I$
```
#### New/modern style
Since the old style switches can be kind of confusing, it is recommended to use the "new style"
parameters instead. The new style is all combined in the `-M` parameter. Using the upper case
version of a parameter argument enables a feature, while the lower case version disabled it. The
previous example could be represented like this in new style:
```shell
$ ./apg-go -n 1 -M lUSN
$</K?*|M)%8\U$5JA5~
```
#### Human readability
Generated passwords can sometimes be a bit hard to read for humans, especially when ambiguous
characters are part of the password. Some characters in the ASCII character set look similar to
each other. In example it can be hard to differentiate an upper case I from a lower case l.
Same applies to the number zero (0) and the upper case O. To not run into issues with human
readability, you can set the `-H` parameter to toggle on the "human readable" feature. When the
option is set, apg-go will avoid using any of the typical ambiguous characters in the generated
passwords.
```shell
$ ./apg-go -n 1 -M LUSN -H
YpranThY3b6b5%\6ARx
```
#### Character exclusion
Let's assume, that for whatever reason, your generated password can never include a colon (:) sign. For
this specific case, you can use the `-E` parameter to specify a list of characters that are to be excluded
from the password generation character set:
```shell
$ ./apg-go -n 1 -M lUSN -H -E :
~B2\%E_|\VV|/5C7EF=
```
#### Complex passwords
If you want to generate complex passwords, there is a shortcut for this as well. By setting the `-C`
parameter, apg-go will automatically default to the most secure settings. The complex parameter
basically implies that the password will use all available characters (lower case, upper case,
numeric and special) and will make sure that human readability is disabled.
```shell
$ ./apg-go -n 1 -C
{q6cvz9le5_fo"X7
```
### Password length
By default, apg-go will generate a password with a random length between 12 and 20 characters. If you
want to be more specific, you can use the `-m` and `-x` parameters to override the defaults. Let's
assume you want a single complex password with a length of exactly 32 characters, you can do so by
running:
```shell
$ ./apg-go -n 1 -C -m 32 -x 32
5lc&HBvx=!EUY*;'/t&>B|~sudhtyDBu
```
### Password spelling
If you need to read out a password, it can be helpful to know the corresponding word for that character in
the phonetic alphabet. By setting the `-l` parameter, agp-go will provide you with the phonetic spelling
(english language) of your newly created password:
```shell
$ ./apg-go -n 1 -M LUSN -H -E : -l
fUTDKeFsU+zn3r= (foxtrot/Uniform/Tango/Delta/Kilo/echo/Foxtrot/sierra/Uniform/PLUS_SIGN/zulu/november/THREE/romeo/EQUAL_SIGN)
```
### Have I Been Pwned
Even though, the passwords that apg-go generated for you, are secure, there is a minimal chance, that
someone on the planet used exactly the same password before and that this person was part of an
internet leak or hack, which exposed the password to the public. Such passwords are not considered
secure anymore as they usually land on public available password lists, that are used by crackers.
To be on the safe side, you can use the `-p` parameter, to enable a HIBP check. When the feature is
enabled, apg-go will check the HIBP database at https://haveibeenpwned.com if that password has been
leaked before and provide you with a warning if that is the case.
Please be aware, that this is a live check against the HIBP API, which not only requires internet
connectivity, but also might take between 500ms to 1s to complete. When you generating a bigger list
of password `-n 100`, the process could take much longer than without the `-p` feature enabled.
## CLI parameters ## CLI parameters
_apg-go_ replicates some of the parameters of the original APG. Some parameters are different though: _apg-go_ replicates some of the parameters of the original APG. Some parameters are different though:
@ -105,5 +205,10 @@ _apg-go_ replicates some of the parameters of the original APG. Some parameters
- ```-H```: Avoid ambiguous characters in passwords (i. e.: 1, l, I, o, O, 0) (Default: off) - ```-H```: Avoid ambiguous characters in passwords (i. e.: 1, l, I, o, O, 0) (Default: off)
- ```-C```: Generate complex passwords (implies -L -U -N -S and disables -H) (Default: off) - ```-C```: Generate complex passwords (implies -L -U -N -S and disables -H) (Default: off)
- ```-l```: Spell generated passwords (Default: off) - ```-l```: Spell generated passwords (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 a CLI help text - ```-h```: Show a CLI help text
- ```-v```: Show the version number - ```-v```: Show the version number
## Contributors
Thanks to the following people for contributing to the apg-go codebase:
* [Romain Tartière](https://github.com/smortex)

15
apg.go
View file

@ -10,7 +10,7 @@ import (
// Constants // Constants
const DefaultMinLenght int = 12 const DefaultMinLenght int = 12
const DefaultMaxLenght int = 20 const DefaultMaxLenght int = 20
const VersionString string = "0.3.1" const VersionString string = "0.3.2"
type Config struct { type Config struct {
minPassLen int minPassLen int
@ -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

@ -7,16 +7,33 @@ import (
// Parse the CLI flags // Parse the CLI flags
func parseFlags() Config { func parseFlags() Config {
var config Config var switchConf Config
defaultSwitches := Config{
useLowerCase: true,
useUpperCase: true,
useNumber: true,
useSpecial: false,
useComplex: false,
humanReadable: false,
}
config := Config{
useLowerCase: defaultSwitches.useLowerCase,
useUpperCase: defaultSwitches.useUpperCase,
useNumber: defaultSwitches.useNumber,
useSpecial: defaultSwitches.useSpecial,
useComplex: defaultSwitches.useComplex,
humanReadable: defaultSwitches.humanReadable,
}
// Read and set all flags // Read and set all flags
flag.BoolVar(&config.useLowerCase, "L", true, "Use lower case characters in passwords") flag.BoolVar(&switchConf.useLowerCase, "L", false, "Use lower case characters in passwords")
flag.BoolVar(&config.useUpperCase, "U", true, "Use upper case characters in passwords") flag.BoolVar(&switchConf.useUpperCase, "U", false, "Use upper case characters in passwords")
flag.BoolVar(&config.useNumber, "N", true, "Use numbers in passwords") flag.BoolVar(&switchConf.useNumber, "N", false, "Use numerich characters in passwords")
flag.BoolVar(&config.useSpecial, "S", false, "Use special characters in passwords") flag.BoolVar(&switchConf.useSpecial, "S", false, "Use special characters in passwords")
flag.BoolVar(&config.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(&config.spellPassword, "l", false, "Spell generated password") flag.BoolVar(&config.spellPassword, "l", false, "Spell generated password")
flag.BoolVar(&config.humanReadable, "H", false, "Generate human-readable passwords") 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")
@ -26,7 +43,27 @@ func parseFlags() Config {
"New style password parameters (higher priority than single parameters)") "New style password parameters (higher priority than single parameters)")
flag.Parse() flag.Parse()
// Parse additional parameters // Invert-switch the defaults
if switchConf.useLowerCase {
config.useLowerCase = !defaultSwitches.useLowerCase
}
if switchConf.useUpperCase {
config.useUpperCase = !defaultSwitches.useUpperCase
}
if switchConf.useNumber {
config.useNumber = !defaultSwitches.useNumber
}
if switchConf.useSpecial {
config.useSpecial = !defaultSwitches.useSpecial
}
if switchConf.useComplex {
config.useComplex = !defaultSwitches.useComplex
}
if switchConf.humanReadable {
config.humanReadable = !defaultSwitches.humanReadable
}
// Parse additional parameters and new-style switches
parseParams(&config) parseParams(&config)
return config return config

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\n", 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
}