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, strin
There are some problems with your implementation:
random.seed = (os.urandom(1024))
This does not seed the random number generator; it replaces the seed function with a bytestring. You need to call seed, like, random.seed(…).
print ''.join(random.choice(chars) for i in range(length))
Python's default PRNG is a Mersenne Twister, which is not a cryptographically strong PRNG, so I'm wary of using it for cryptographic purposes. The random module includes random.SystemRandom, which on at least most *nix systems, should use a CSPRNG. However,
random.choice(chars)
…is implemented as…
def choice(self, seq):
"""Choose a random element from a non-empty sequence."""
return seq[int(self.random() * len(seq))] # raises IndexError if seq is empty
…in Python 2. Unfortunately, self.random here is a C function, so this gets hard to see; the code smell here is that this code almost certainly doesn't choose uniformly. The code has completely changed in Python 3, and does a much better job of ensuring uniformity. The Python 3 docs for randrange note,
Changed in version 3.2:
randrange()is more sophisticated about producing equally distributed values. Formerly it used a style likeint(random()*n)which could produce slightly uneven distributions.
randrange and choice both call the same method (_randbelow) under the hood.
In Python 3, choice is fine; in Python 2, it only comes close to a uniform distribution, but does not guarantee it. Since this is crypto, I lean on the "take no chances" side of the fence, and would like to have that guarantee.