Google+ Pieces o' Eight: A random password generator in Python

Saturday 24 September 2011

A random password generator in Python

For a recent project I needed to create a lot of random passwords. There are plenty of websites out there that can do this for you, but as I'm learning Python I thought I'd have a go at rolling my own solution.

My requirements were that each password be of a specified length and constructed from a random pick of the letters A-Z and a-z and the digits 0-9. I also wanted the function to return a phonetic spelling of each password. Here's what I came up with:


import random

def randomPasswordGenerator(length):
    upperCase = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
    lowerCase = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
    numbers =   ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "1", "3", "5", "2", "4", "6"]
    phoneticDictionary = {"A" : "ALPHA",
                          "B" : "BRAVO",
                          "C" : "CHARLIE",
                          "D" : "DELTA",
                          "E" : "ECHO",
                          "F" : "FOXTROT",
                          "G" : "GOLF",
                          "H" : "HOTEL",
                          "I" : "INDIA",
                          "J" : "JULIET",
                          "K" : "KILO",
                          "L" : "LIMA",
                          "M" : "MIKE",
                          "N" : "NOVEMBER",
                          "O" : "OSCAR",
                          "P" : "PAPA",
                          "Q" : "QUEBEC",
                          "R" : "ROMEO",
                          "S" : "SIERRA",
                          "T" : "TANGO",
                          "U" : "UNIFORM",
                          "V" : "VICTOR",
                          "W" : "WHISKEY",
                          "X" : "XRAY",
                          "Y" : "YANKEE",
                          "Z" : "ZULU",
                          "a" : "alpha",
                          "b" : "bravo",
                          "c" : "charlie",
                          "d" : "delta",
                          "e" : "echo",
                          "f" : "foxtrot",
                          "g" : "golf",
                          "h" : "hotel",
                          "i" : "india",
                          "j" : "juliet",
                          "k" : "kilo",
                          "l" : "lima",
                          "m" : "mike",
                          "n" : "november",
                          "o" : "oscar",
                          "p" : "papa",
                          "q" : "quebec",
                          "r" : "romeo",
                          "s" : "sierra",
                          "t" : "tango",
                          "u" : "uniform",
                          "v" : "victor",
                          "w" : "whiskey",
                          "x" : "xray",
                          "y" : "yankee",
                          "z" : "zulu",
                          "0" : "Zero",
                          "1" : "One",
                          "2" : "Two",
                          "3" : "Three",
                          "4" : "Four",
                          "5" : "Five",
                          "6" : "Six",
                          "7" : "Seven",
                          "8" : "Eight",
                          "9" : "Nine"}
                          
    all = [upperCase, lowerCase, numbers]
    password = []
    phoneticPassword = []
    
    for i in range(length):
        character = all[random.randint(0,2)][random.randint(0,25)]
        password.append(character)
        phoneticPassword.append(phoneticDictionary[character])

    return ''.join(password), '-'.join(phoneticPassword)

It's pretty simple. The function takes a length n and then loops n times randomly picking one of three lists (A-Z, a-z or 0-9) and then picks a random entry from that list.

The chosen character is then appended to the "password" list and also passed to the phonetic dictionary, which returns the phonetic spelling of the character and appends it to the "phoneticPassword" list. Finally the function returns the password and phonetic password by joining the arrays into strings.

Here's the output of the function run 10 times specifying a password length of 8:

FAhFh0fy FOXTROT-ALPHA-hotel-FOXTROT-hotel-Zero-foxtrot-yankee
46Ne3XNu Four-Six-NOVEMBER-echo-Three-XRAY-NOVEMBER-uniform
1PcCnBX2 One-PAPA-charlie-CHARLIE-november-BRAVO-XRAY-Two
qAYVAB75 quebec-ALPHA-YANKEE-VICTOR-ALPHA-BRAVO-Seven-Five
y41Q3w7l yankee-Four-One-QUEBEC-Three-whiskey-Seven-lima
4NW55yYH Four-NOVEMBER-WHISKEY-Five-Five-yankee-YANKEE-HOTEL
bjihtPPk bravo-juliet-india-hotel-tango-PAPA-PAPA-kilo
H56a0Ydf HOTEL-Five-Six-alpha-Zero-YANKEE-delta-foxtrot
KaQkrlk8 KILO-alpha-QUEBEC-kilo-romeo-lima-kilo-Eight
77m302O1 Seven-Seven-mike-Three-Zero-Two-OSCAR-One

You might have noticed that the numeric character list contains some repetition to get the list length up to 26. I did this largely for expediency, but it does create some bias in that the numbers 1-6 have a slightly higher chance of being picked than 0,7-9. I'm not sure if this makes much of a difference, but it's as well to aware that this could be a potential weakness of the algorithm.

Without a doubt you could achieve the same in practically any programming language. What I particularly liked about Python for this, however, was the immediacy of the scripting environment and the built-in methods - such as "join" - which negate having to write tedious boiler-plate code to stitch strings together.

No comments:

Post a Comment