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
castorio
  • 95
  • 5
  • 1
    Might throw some non alpha-numeric characters in there. – Abe Miessler Aug 29 '13 at 20:39
  • 2
    What do **you** know about randomness? Specifically, start with learning what the algorithm inside python really is. – Deer Hunter Aug 29 '13 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 '13 at 21:11
  • dear hunter, i dont known much about randomness, thats why i use pythons random-functions – castorio Aug 29 '13 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 '16 at 00:42

2 Answers2

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.

Brendan Long
  • 2,898
  • 1
  • 19
  • 27
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.

AardvarkSoup
  • 577
  • 2
  • 10
  • so you are able to guess the passwords if i tell you: i created one 5 minutes ago? – castorio Aug 29 '13 at 21:21
  • > It would be easy to brute-force the passwords for each millisecond : ist this just theroretical? – that guy from over there Aug 30 '13 at 08: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 '13 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. – AardvarkSoup Aug 30 '13 at 19:49
  • @AardvarkSoup: challenge accepted. i'll post a time.time() timestamp (and maybe a hash too?) a password was generated and you'll have 15 minutes to post, lets say, 1.000 passwords onto pastebin. just tell me a time on monday (or within the next 2/3 hours) – that guy from over there Aug 30 '13 at 21:44
  • 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. – AardvarkSoup Sep 01 '13 at 22:03
  • thanx for your efforts. – that guy from over there Sep 02 '13 at 05:57