Cryptographically secure, easy-to-use, password generator
Project description
Python Password Utility
Cryptographically secure, easy-to-use, password generator
Most password generators written in Python make use of Python's secrets module to generate random values. Python Password Utility goes a step further: it chains together a keyed version of the SHA-512 (or SHA3-512) hash function to create a password which is computationally infeasible to guess, even for someone who knows the internal state of the secrets module.
Python Password Utility can be run directly from the command line, or called through a Python API.
This software requires Python 3.6 or later. Major versions of Python after Python 3 are not supported.
Index
Description
The algorithm operates in a loop; at each iteration of the loop one character is added to the password. The program takes the "output state" of the previous iteration, and hashes it alongside the current time, 64 random bytes from Python's secrets module, a unique counter value, and the key. The result of this operation is the "output state" that will be used by the next iteration of the loop.
Each of the "output states" is then hashed again along with the time, a different 64 random bytes, and a different unique counter value. One byte is selected randomly from each of the resulting "candidate states" and is transformed into a password character.
The power of this technique comes from the keyed hash functions. For an attacker to have any hope of guessing a password generated in this way, they must first know the key which was used. If the user creates a new somewhat-random key for each password, and then removes all record of the key, it eliminates any chance of retroactively recovering the password. This holds true even in the absurdly unlikely case that an attacker knows both the time when the password was generated and the internal state of Python's secrets module.
Drawing randomness from multiple sources, and passing it through a SHA hash, guarantees that the resulting passwords will be patternless: knowing any part of the password will not give an attacker any information about the rest of the password. Passwords generated from Python Password Utility will have the maximum possible entropy for a password of their length and character set.
Installation
pip install passutil
Note: This software requires Python 3.6 or later. Major versions of Python after Python 3 are not supported.
Running from the Command Line
python -m passutil <valid_chars> <length> <random keyboard smashing, optional>
<valid_chars>
tells the program which characters are permitted in your password.
The format of this parameter is described below.
z
is generally the best option, unless there are restrictions on which
characters may appear in the password.
This parameter may not correspond to an empty set;
to be able to generate a password, at least one character must be
allowed to exist in the password.
This parameter is case sensitive.
<length>
is the desired length of the password. This can be any nonnegative integer.
<random keyboard smashing>
is an optional parameter. The entire command is taken as the key
for the hash function, so going wild on the keyboard after the <length>
will
increase the randomness of the generated password.
Character Sets
The basic character sets include:
u
orc
-> uppercase/capital: A-Z (26 characters)l
-> lowercase: a-z (26 characters)n
-> numeral: 0-9 (10 characters)p
-> ASCII punctuation: `~!@#$%^&*()-_=+[]{}\|;:'",<.>/? (32 characters)r
-> subset ofp
, some systems prohibit which punctuation characters may be used in a password,r
omits those characters which are most likely to be banned, leaving: !@#$%&*()-_+[]{};:,.? (21 characters)s
-> the space character (1 character)H
-> uppercase hexadecimal characters: 0123456789ABCDEF (16 characters)h
-> lowercase hexadecimal characters: 0123456789abcdef (16 characters)
The names of the basic character sets are case sensitive;
they must all be lowercase, other than H
.
Example:
The command below will generate a password of length 4,
only containing the numerals 0-9.
It does this by specifying the character set n
for numerals,
and the length 4
.
The output might look like: 7014
.
python -m passutil n 4
Example:
The command below will generate a password of length 25,
only containing ASCII punctuation characters.
It does this by specifying the character set p
for punctuation,
and the length 25
.
The output might look like: $/:<"/\~(+#/=";-:^(*)+'?-
.
python -m passutil p 25
If we want to use characters from multiple character sets, we can perform a union on the sets simply by concatenating their names in the command.
Example:
The command below will generate a password of length 10,
only containing numerals, spaces, and lowercase letters.
It does this by combining the n
, s
, and l
sets,
to get the nsl
set.
The output might look like: p ltaj0k3p
.
python -m passutil nsl 10
It is also possible to combine many character sets at once using shorthands:
a
=ulnps
, all the characters (95 characters)ar
=ulnrs
, all the characters, except those which are likely to be banned (84 characters)z
=ulnp
, all the characters, except spaces (94 characters)zr
=ulnr
, all the characters, except spaces, and those which are likely to be banned (83 characters)
The shorthands are case sensitive; they must all be lowercase.
Example:
The command below will generate a password of length 16,
containing any of the ASCII printable characters. It does this by using the a
shorthand. The output may look like: ~VJ &FhC[_K8wu:+
.
python -m passutil a 16
Note that the above command is fully equivalent to:
python -m passutil ulnps 16
Example:
The command below will generate a password of length 7,
only containing uppercase letters, lowercase letters, numerals,
restricted punctuation characters, and spaces.
It does this by combining the zr
shorthand with the s
character set.
The output may look like: 1A #T-x
.
python -m passutil zrs 7
Note: zrs
= szr
= ulnrs
= ar
(zr
is expanded to its definition, and then merged with s
)
However: zsr
= ulnpsr
= a
(z
is expanded to its definition, the last r
is ignored because it is already included in p
)
Individual characters may be included with i
or excluded with e
.
Example:
The command below will generate a password of length 20,
only containing numerals, A
characters and b
characters.
It does this by first declaring the base set: n
,
indicating numerals, then modifying it
with i
. The Ab
after the i
signals that A
characters
and b
characters are allowed in the password.
The output may look like: 24b749b71A1669586098
.
python -m passutil niAb 20
This feature is case sensitive;
using uppercase I
would not work here.
Example:
The command below will generate a password of length 18,
only containing capital letters and ASCII punctuation.
However, it will not contain the characters C
,
A
, T
, .
, or /
.
It does this by first declaring the base set: cp
,
indicating capitals and punctuation, then modifying it
with e
. The CAT./
after the e
signals that these
characters may not appear in the password.
The output may look like: [W*[*;{(UM@QL,_$XR
.
python -m passutil cpeCAT./ 18
This feature is case sensitive;
using uppercase E
would not work here.
Some characters may need to be enclosed in parenthesis or prefixed with an escape backslash. See: https://www.shellscript.sh/escape.html
To include/exclude lowercase i
or e
, escape them with a ..
prefix.
Example:
The command below will generate a password of length 14,
only containing consonants in the English alphabet.
It does this by first declaring the base set: l
,
indicating lowercase letters, then modifying it
with e
to exclude the vowel characters.
Notice that in the exclusion, e
and i
are prefixed with ..
to prevent them
from being interpreted as the beginning
of an exclusion or inclusion.
The output may look like: hgydslgfzpsqft
.
python -m passutil lea..e..iou 14
i
and e
may be used together
Example:
The command below will generate a password of length 26,
only containing even numerals, a
characters, and m
characters.
It does this by first declaring the base set: n
,
indicating numerals, then modifying it
with i
to include a
and m
characters.
The following e
will then exclude
the 1
, 3
, 5
, 7
, and 9
characters from
the password.
The output may look like: m6am6a264m6m4m884m40aa6ma2
.
python -m passutil niame13579 26
Example:
The command below will generate a password of length 7,
only containing numerals, e
characters,
and excluding the numeral 5
.
It does this by first declaring the base set: n
,
indicating numerals, then modifying it with i
to include e
. Note that the first e
is escaped with a ..
,
and is therefore included by the preceding i
, while the second e
is not escaped, and so signals the start of an exclusion.
5
is excluded by the second e
.
The output may look like: 97739e8
.
python -m passutil ni..ee5 7
Advanced Examples
Example:
IN: python -m passutil li234 30
OUT: ppkksclllnihfghmrmxqklvcleiroe
Where's the 234
in the output?
The <valid_chars>
parameter controls which
characters may appear in the password,
not which characters will appear in the password.
Example:
IN: python -m passutil aen 30
OUT: x&deJD.PHG\]-5]0d\&!CX\wRwHyNl
I wanted to generate a password using
all the characters, except for numerals.
What's that 5
doing in there?
After an i
or e
starts an inclusion or exclusion,
all subsequent characters (except for i
and e
)
are interpreted literally.
Before any inclusions or exclusions, u
, c
,
l
, n
, p
, r
, s
, H
, and h
refer to sets of characters.
(Definitions given above)
Within inclusions and exclusions, these same characters are interpreted as individual Latin alphabet letters to be included or excluded.
So, aen
will generate a password using all available characters
except for the lowercase letter n
, which will be excluded.
To generate a password using all the available characters
except numerals, use ulps
or more inconveniently ae0123456789
.
Example:
IN: python -m passutil iATCG 12
OUT: CACCCCCGTCTG
Declaring a base set is not required.
The <valid_chars>
parameter may begin with an i
,
followed by the characters to include.
Example:
IN: python -m passutil ipeck 10
OUT: pppppppppp
What's going on here?
I wanted a password using the letters p
,
e
, c
, and k
, but I only get a bunch of p
characters.
Because the e
is not escaped, it is treated as the beginning
of an exclusion. c
and k
are excluded, leaving only p
in the character set.
To create a character set with the characters
p
, e
, c
, and k
, the e
needs to be
escaped: ip..eck
.
Example:
IN: python -m passutil lebig 10
OUT: wdaozsgput
Why is there a g
in the output? I wanted to exclude
the characters b
, i
, and g
.
Same thing as the previous example.
i
is not escaped.
The correct character set will be produced with: leb..ig
.
Example:
IN: python -m passutil i..i 10
OUT: iiiiiiiiii
Wait, what?
The first i
starts an inclusion.
The escaped second i
is the sole character
that is included into the set.
Example:
IN: python -m passutil e..e 10
OUT: valid_chars parameter has minimum size 1
Wait, what?
The first e
starts an exclusion.
No characters are added into the character set.
The program needs at least one valid character
to be able to produce a password.
Example:
IN: python -m passutil ixiyey 10
OUT: xxxxxxxxxx
IN: python -m passutil ixeyiy 10
OUT: xyyyxyyyxy
What's going on here? Why do such similar inputs produce such different outputs?
The generation of the character set operates from left to right.
In the first case: ix
will add x
to the set.
iy
will add y
to the set.
But then, ey
will remove y
from the set,
leaving only x
.
In the second case: ix
will add x
to the set.
ey
will try to remove y
from the set, but as
there is no y
in the set, it will do nothing.
Then, the program reaches iy
, adding y
to the set,
resulting in a set containing both x
and y
.
Example:
Adding pseudorandomly generated keystrokes (e.g. pretending to type without actually making words) after the core of the command can help increase the randomness of the generated password. It is recommended that users make use of this feature to fully utilize the capacities of this software.
IN: python -m passutil n 30 ju2ikntu i g rhtuirehtui3wh8r73hfsdnrrhtrthui
OUT: 834040642994017327433140007821
IN: python -m passutil Hixyz 20 njfkern 4tio54n28r4 gmfd dginrekngtiosei8ufh
OUT: 18C29C2A9Az472BC1D27
IN: python -m passutil zeI..i 5 min3w 12ji44tnf 4hNUFIWE 3U4ITR8H4RH283W7 fhu
OUT: Ss#oL
Getting the Size of a Character Set
Sometimes it is useful to know how many characters are in a character set before the character set is used. Python Password Utility allows one to do this from the command line.
python -m passutil --size <valid_chars>
<valid_chars>
has the same format as above.
However, unlike when generating a password,
valid_chars
may correspond to an empty set.
In such a case, 0
is returned.
Example:
IN: python -m passutil --size une5
OUT: 35
u
has 26 characters. n
has 10.
e5
removes one character, leaving 35.
Hashing Algorithms
Python Password Utility generates passwords using either the SHA-2 512 algorithm or the SHA-3 512 algorithm.
To determine which algorithm is being used:
python -m passutil --hash
Calling from Python
Python Password Utility provides three publicly accessible objects.
generate_password
generate_password
is a function. As the name suggests,
it generates passwords in the same way that the
command line interface does.
import passutil
password = passutil.generate_password(length, key, valid_chars)
length
is a nonnegative int
representing the desired number of characters in the password.
key
is of type bytes
or str
. Its length cannot be zero. This value will be used to key the
SHA hash function.
For best results, use a different key
value on each call to generate_password
.
valid_chars
indicates which characters may appear in the output password. It may be a str
of the same
format as the <valid_chars>
parameter in the command line interface.
Alternatively, valid_chars
may be a set
, list
, or tuple
containing permitted
characters, encoded as single-character strings.
Alternatively, valid_chars
may be a set
, list
, or tuple
containing
codepoints for permitted characters. Only ASCII printable characters,
or their codepoints, may exist in valid_chars
. valid_chars
may not correspond to
an empty set.
The function will output a str
containing the password.
Raises TypeError
if length
is not an int
.
Or if key
is not a bytes
or str
object.
Or if valid_chars
is not a str
, set
,
list
, or tuple
. Or if the contained elements are neither
str
nor int
.
Raises ValueError
if length
is negative.
Or if key
has length zero.
Or if the format is incorrect.
Or if non-ASCII-printable
characters are given in valid_chars
.
Example:
import passutil
password = passutil.generate_password(4, "hello world", "n")
print(type(password)) # str
print(password) # 7014
This is analogous to the very first example given in this document.
Example:
import passutil
password = passutil.generate_password(12, b'\xf0\x9f\x98\x84', {"A","T",67,71})
# ASCII value 67 is "C", ASCII value 71 is "G"
print(password) # CACCCCCGTCTG
This is analogous to one of the advanced examples above.
charset_size
charset_size
is the analog of --size
in the command line interface.
It is a function called in the following way:
import passutil
size = passutil.charset_size(valid_chars)
It returns an int
.
valid_chars
has the same format as in generate_password
.
Unlike in generate_password
, an input corresponding to an
empty character set will not cause an exception; instead, the function
will simply return 0
, indicating a character set of size zero.
Raises TypeError
if valid_chars
is not a str
, set
,
list
, or tuple
. Or if the contained elements are neither
str
nor int
.
Raises ValueError
if the format is incorrect or if non-ASCII-printable
characters are given in valid_chars
.
SHA512_number
SHA512_number
is the analog of --hash
in the command line interface.
It is an int
constant.
A value of 2
indicates that SHA-2 512 will be used for hashing.
A value of 3
indicates that SHA-3 512 will be used for hashing.
import passutil
algorithm_version = passutil.SHA512_number
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.