Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix long non-ambiguous passwords (and insertion of numerals/symbols if forced) #14

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

MichiK
Copy link

@MichiK MichiK commented Jul 28, 2018

I noticed that the creation of passwords could take a long time if no_ambiguous is set to True and the password length is increased sufficiently (this becomes really noticable at around 30 characters). Generation of non-ambiguous short passwords, while it already takes a lot longer than the genration of passwords that may contain ambiguous characters, is generally quite fast:

In [1]: from pwgen import pwgen

In [2]: %timeit pwgen(10)
16.7 µs ± 102 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [3]: %timeit pwgen(10, no_ambiguous=True)
266 µs ± 18.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

However, the longer the password becomes, the higher the chance that it contains an ambiguous character. In this case, the algorithm would throw away the password entirely and generate a new one (again with a high chance of containing an ambiguous character):

In [4]: %timeit pwgen(35)
53.7 µs ± 158 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [5]: %timeit pwgen(35, no_ambiguous=True)
The slowest run took 31.82 times longer than the fastest. This could mean that an intermediate result is being cached.
645 ms ± 610 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In case of 10 characters, generating non-ambiguous passwords took around 16 times longer than generating normal ones. At 35 characters, this factor already increased to 12000 times longer (and it gets worse, the longer the passwords get). After this point, generating non-ambiguous is no longer practical.

Therefore I changed the password generation so that in case no_ambiguous is set, it does not regenerate the password entirely but instead just replaces the ambiguous characters by a new, random one until all of them have been eliminated. Therefore, non-ambiguous password generation gets a lot faster and even the generation of extremely long passwords is possible:

In [2]: %timeit pwgen(35, no_ambiguous=True)
10000 loops, best of 3: 139 µs per loop

In [3]: %timeit pwgen(1000, no_ambiguous=True)
100 loops, best of 3: 16.3 ms per loop

As replaceRandomChar() now can be fed a list of positions where it should insert a new character, I also changed the mechanism that enforces caps, numerals or symbols so that it will only replace a random lowercase letter instead of any letter in the password. Therefore, if the user enforces multiple classes of characters, the chance is smaller that they will cancel each other out (see #13). Theoretically, this might still happen though, if the password does not contain lowercase letters at all that can be replaced. In that case, the algorithm falls back to replacing a random character.

If no_ambiguous is set, the ambiguous characters are now replaced one
by one instead of throwing away the password and trying to generate
a new one. This was a problem when generating long, non-ambiguous
passwords.

In addition, when symbols, numerals or capital letters are enforced,
these characters will no longer be inserted at random positions in
the password. Instead, they will only replace lowercase letters, if
available. Otherwise, it was possible to e.g. overwrite the single
numeral with a symbol if numerals and symbols are set and only one
numeral but no symbols were present in the password (closes vinces1979#13).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant