Home > other >  Random Password Generator quality
Random Password Generator quality

Time:06-20

I have been asked to develop a random password generator based on different character sets, like 'abcd.....wxyz', '0123456789' and '!$()?=^_;:,.-'.

I have now in mind two different implementations:

  1. In this case, all characters set are copied into a single string, then each character that composes the password is taken randomly from it.
    import os, random, string

    length = 13
    chars = string.ascii_letters   string.digits   '!$()?=^_;:,.-'
    random.seed = (os.urandom(1024))

    print ''.join(random.choice(chars) for i in range(length))
  1. The character sets are divided and a random value is used to select among the sets and then, from that selected set, a random character is taken
    import os, random, string

    length = 13
    set = [string.ascii_letters, string.digits, '!$()?=^_;:,.-']

    random.seed = (os.urandom(1024))

    print ''.join(random.choice(random.choice(set)) for i in range(length))

From multiple tests it seems that the second solution generates passwords that contain more symbols and numbers, this is due to the fact that the probability to use a symbol is exactly 1/3 (33%). While in the first algorithm only 13/(10 13 26) = 26%.

Which one is the correct implementation? I think that the first algorithm has a non-uniform probability with the respect to the set selection, making more probable to find ascii_letters with the respect to the symbols. Any hints would be appreciated.

Edit: I did this implementation only for explaining the two different implementations in a fast way. Surely I'll select the best suitable module, but for now I'm not interested in this evaluation.

CodePudding user response:

The first solution is better, because a single character from the password has an equal probability of being any of the possible characters. The second solution introduces biases (with some characters more likely to be selected than others), which reduces the entropy (randomness) of the password. If an attacker knows this is how you're generating passwords, this means them easier to crack.


However, both of these are bad ways to generate passwords, because this type of password is very difficult for users to remember and use. Organisations like NCSC and NIST (and of course, the famous XKCD) have been recommending the use of passphrases for years.

So rather than trying to generate password from character sets, you should be generating them from multiple words (possibly with randomly selected symbols or numbers between them if you want to increase the strength).

CodePudding user response:

The recommended approach from the Recipes and best practices section of the official Python secrets documentation is closer to your first implementation:

import string
import secrets
alphabet = string.ascii_letters   string.digits
password = ''.join(secrets.choice(alphabet) for i in range(8))

You can also explicitly specify a minimum numbers of character types (e.g. digits, punctuation):

import string
import secrets
alphabet = string.ascii_letters   string.digits
while True:
    password = ''.join(secrets.choice(alphabet) for i in range(10))
    if (any(c.islower() for c in password)
            and any(c.isupper() for c in password)
            and sum(c.isdigit() for c in password) >= 3):
        break

Also, as an FYI, you can use string.punctuation to add punctuation characters to your character string.

  • Related