High quality, simple random password generator

Mike R. picture Mike R. · Sep 20, 2011 · Viewed 86.6k times · Source

I'm interested in creating a very simple, high (cryptographic) quality random password generator. Is there a better way to do this?

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))

Answer

Thomas Pornin picture Thomas Pornin · Sep 20, 2011

The difficult thing with passwords is to make them strong enough and still be able to remember them. If the password is not meant to be remembered by a human being, then it is not really a password.

You use Python's os.urandom(): that's good. For any practical purpose (even cryptography), the output of os.urandom() is indistinguishable from true alea. Then you use it as seed in random, which is less good: that one is a non-cryptographic PRNG, and its output may exhibit some structure which will not register in a statistical measurement tool, but might be exploited by an intelligent attacker. You should work with os.urandom() all along. To make things simple: choose an alphabet of length 64, e.g. letters (uppercase and lowercase), digits, and two extra punctuation characters (such as '+' and '/'). Then, for each password character, get one byte from os.urandom(), reduce the value modulo 64 (this is unbiased because 64 divides 256) and use the result as index in your chars array.

With an alphabet of length 64, you get 6 bits of entropy per character (because 26 = 64). Thus, with 13 characters, you get 78 bits of entropy. This is not ultimately strong in all cases, but already very strong (it could be defeated with a budget which will be counted in months and billions of dollars, not mere millions).