Welcome, guest | Sign In | My Account | Store | Cart

I have written a generator that churns out really strong passwords. I have checked with a few password testers online which consistently rate the generated passwords with top marks.

Python, 42 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from os import urandom
from random import choice

char_set = {'small': 'abcdefghijklmnopqrstuvwxyz',
             'nums': '0123456789',
             'big': 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
             'special': '^!\$%&/()=?{[]}+~#-_.:,;<>|\\'
            }


def generate_pass(length=21):
    """Function to generate a password"""

    password = []

    while len(password) < length:
        key = choice(char_set.keys())
        a_char = urandom(1)
        if a_char in char_set[key]:
            if check_prev_char(password, char_set[key]):
                continue
            else:
                password.append(a_char)
    return ''.join(password)


def check_prev_char(password, current_char_set):
    """Function to ensure that there are no consecutive 
    UPPERCASE/lowercase/numbers/special-characters."""

    index = len(password)
    if index == 0:
        return False
    else:
        prev_char = password[index - 1]
        if prev_char in current_char_set:
            return True
        else:
            return False

if __name__ == '__main__':
    print generate_pass()

This is an pretty improved version of the generator written by Isendrak Skatasmid - simple-password-generator. I have introduced few changes in the algorithm. Also, the entire set of special characters is not being used. Sometimes passwords that start with special-characters or numbers are generated. I am not sure whether that is a bad thing.A few links that I had used to test the password strength are:

  1. How Secure Is My Password
  2. Password Meter
  3. Password Strength Checker

You are welcome to comment/criticize/suggest improvements for the implementation.

5 comments

Matt Hubbard 11 years, 10 months ago  # | flag

You've missed out the import statement:

from os import urandom

I'm not sure why you'd make repeated calls to "urandom" and check that the result is in your target character set instead of choosing a random character from the set. E.g.

from random import choice
a_char = choice('abcdefghijklmnopqrstuvwxyz')

os.urandom is not platform independent. Using random.choice would allow this to work on non-posix systems.

By constraining the password to never contain consecutive characters from the same set you are limiting the complexity of the password, perhaps not by much, but you would be making someone's life easier at some point reducing the search space for a brute force attack.

But, if you did want to do this then just picking the next character's set at random out of the other character sets would be more efficient. E.g.:

from random import choice

charsets = [
    'abcdefghijklmnopqrstuvwxyz',
    'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
    '0123456789',
    '^!\$%&/()=?{[]}+~#-_.:,;<>|\\',
    ]

def mkpassword(length=16):
    pwd = []
    charset = choice(charsets)
    while len(pwd) < length:
        pwd.append(choice(charset))
        charset = choice(list(set(charsets) - set([charset])))
    return "".join(pwd)
ajaymenon.k (author) 11 years, 10 months ago  # | flag

Matt:

Thanks a lot for the comments. I did cut short the code a lot to achieve almost the same result.

  1. I changed the urandom function. Now it uses choice from random. (thanks for the tip about platform independance.)

  2. Removed the unnecessary variables.

  3. Also the string appending operation was expensive. Now it uses an array.

The design choice of not wanting 2 consecutive characters was a conscious one. But, now I randomly choose a character set to generate a character from instead of using a predictable flow of iterating over all the character sets sequentially. Maybe there is more room for improvement ?

ajaymenon.k (author) 11 years, 10 months ago  # | flag

I decided to keep urandom because the entropy introduced by it is more reliable than the one used by random. But I use random to choose a key among all the char set keys. Also I introduce duplicate characters to widen the search space a bit. Maybe the constraint of not having characters from the same character set narrows the search space further.

Matt Hubbard 11 years, 10 months ago  # | flag

You can use the urandom in the random library. E.g.

from random import SystemRandom
choice = SystemRandom().choice
Captain DeadBones 11 years, 3 months ago  # | flag

I have done something slimier but straight forward. Check it out Generating And Checking Passwords In Python