2

i use the following password-generator (python) and would like to ask if the generated passwords (usually 32 characters and more) are random enough.

def pwgen(l=32):
    from random import Random
    rng = Random()

    a = "qwertzuiopasdfghjklyxcvbnm"
    n = "1234567890"
    r = "23456qwertasdfgzxcvbQWERTASDFGZXCVOB"
    l = "78901yuiophjklnmYUIPHJKLNM"

    all = a + n + r  + l

    pwl = 32
    try:
        pwl = int(l)
    except:
        pass    
    if pwl < 8  or pwl > 128:
        pwl = 32

    pw = []
    for j in range(pwl):
        pw.append(rng.choice(all))

    return("".join(pw))

the password produced look the following way:

cwVPBgYt5seoO97sg8fszNptAhnb60Jg
W3mkuLMH0HCiJ8L040pmMys8yvhncwI8
kro01d2Z2ft51WG8lmy9d5el50aZ7CUg
10QfutP1fvKdR8oVhdTt0xR0r5k7w7Md
OxRjsqs2rCjyVbalvhuw3nrjTu9096XF
6jjvkIvyeoei3YIz84XAgdsDRjIGjyRu
2bjnHvubpv2z2DOF9fjFDfLtdnf4mL3T
UhbhNvwdSKOj14hmbca7t2UiwRaJNwrC
5
  • 1
    Might throw some non alpha-numeric characters in there. Aug 29, 2013 at 20:39
  • 2
    What do you know about randomness? Specifically, start with learning what the algorithm inside python really is. Aug 29, 2013 at 20:39
  • about the non-alphanumeric: it happens from time to time that i have to connect to a client's machine (sun) via a java-webstart-app that is connected to a kvm-console that is connected to the serial port where you dont have anything except alphanumeric characters. sad but true.
    – castorio
    Aug 29, 2013 at 21:11
  • dear hunter, i dont known much about randomness, thats why i use pythons random-functions
    – castorio
    Aug 29, 2013 at 21:12
  • Random enough for what? Random() is not cryptographically secure if that's the question, but that may not be what you are after. Why are you generating them and where will they be used. Also, the characters you're using won't have a normal distribution with this algorithm, but if you're not running a statistical simulation that probably isn't what you need either.
    – Octopus
    Jan 28, 2016 at 0:42

2 Answers 2

16
a = "qwertzuiopasdfghjklyxcvbnm"
n = "1234567890"
r = "23456qwertasdfgzxcvbQWERTASDFGZXCVOB"
l = "78901yuiophjklnmYUIPHJKLNM"

all = a + n + r  + l

Why is this so complicated? By including some characters multiple times, you make those characters more likely to appear in passwords, which weakens the password. By making your password string so complicated, you make it hard to determine how secure the passwords are.

To get an even chance of any character, just list all of them once. Also, you can dramatically simplify this using the string module.

import string

all = string.ascii_letters + string.digits

Another problem is that the random module's documentation says it shouldn't be used for cryptography:

Python uses the Mersenne Twister as the core generator. It produces 53-bit precision floats and has a period of 2**19937-1. The underlying implementation in C is both fast and threadsafe. The Mersenne Twister is one of the most extensively tested random number generators in existence. However, being completely deterministic, it is not suitable for all purposes, and is completely unsuitable for cryptographic purposes.

[...]

Warning: The pseudo-random generators of this module should not be used for security purposes. Use os.urandom() or SystemRandom if you require a cryptographically secure pseudo-random number generator.**

So, use random.SystemRandom() instead:

import random
import string

# Consider adding string.punctuation
possible_characters = string.ascii_letters + string.digits

def generate_password(length=32):
    rng = random.SystemRandom()
    return "".join([rng.choice(possible_characters) for i in range(length)])

Since we know exactly how many possible characters there are (62), and we know that they should be randomly distributed, we can say with fairly high confidence that a password generated by this scheme will on average require (62^32) / 2 (about 10^57) attempts to guess.

That said, a 32 character password is probably secure enough, even if it's not optimally random.

3
  • nice, thanx for the snippet and also random.SystemRandom()
    – castorio
    Aug 29, 2013 at 21:18
  • brendan, do you mind if i "credit" your solution?
    – castorio
    Aug 29, 2013 at 21:31
  • @castorio You can use the contents of this answer however you want. Credit is always nice though. Aug 29, 2013 at 22:10
5

Python's Random class is not a cryptographically secure random number generator, so it is probably too predictable for attackers. Furthermore, it is seeded by a timestamp (I guess in milliseconds), severely limiting the number of potential random streams and therefore the number of passwords. It would be very easy to brute-force the passwords for each possible millisecond at which the algorithm could have run, especially when the attacker can estimate around which time it happened.

Edit: after taking a closer look at the Python documentation, it seems that Python seeds the random generator with entropy from /dev/urandom (or a Windows equivalent thereof) rather than the system time, if available. So it is not nearly as insecure as I previously implied. However, you still definately should not rely on Python's default random number generator for password generation. I'd recommend using os.urandom or random.SystemRandom instead, as indicated by the previous poster.

7
  • so you are able to guess the passwords if i tell you: i created one 5 minutes ago?
    – castorio
    Aug 29, 2013 at 21:21
  • > It would be easy to brute-force the passwords for each millisecond : ist this just theroretical? Aug 30, 2013 at 8:01
  • @castorio - Its not about being able to guess a 5 month old password is about its not random enough because the seed value itself isn't unique enough. It means you have to avoid calling in the wrong way, because in theory the random number generated, becaused of the timestamp.
    – Ramhound
    Aug 30, 2013 at 12:01
  • 1
    @that guy from over there: there are less than 2^42 milliseconds in a century. My laptop could check each possible password generated somewhere in the past 100 years in half a day. If I'd know in what year the password was generated, it would be a matter of minutes. Aug 30, 2013 at 19:49
  • 1
    @that guy from over there: sounds fun:P. Unfortunately, it seems that I was wrong and that the RNG is seeded by 16 bytes from /dev/urandom on most platforms rather than bt the timestamp (I updated my answer accordingly). This means a simple brute-force of seeds won't do the trick after all. Sep 1, 2013 at 22:03

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .