[Tutor] Clunky Password maker
Martin A. Brown
martin at linux-ip.net
Wed May 25 20:34:34 CEST 2011
Hello,
: Is there a less clunky way to do this?
Yes. There are probably many ways to do this, and this is just
something I cooked up at a moment's notice in reply to your
question, and probably could be significantly improved upon.
: def new_pass():
Your function takes no arguments. Maybe this is something to
reconsider. Keep reading.
: series = ['`', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', \
: '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', \
: 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\\', \
: 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '|', \
: 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', "'", \
: 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', \
: 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', \
: 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?']
So, if I were staring at my keyboard and starting to type in the
characters (not a QWERTZ or AZERTY keyboard, it seems), I would ask
myself the question--is there any module that has the complete set
of characters that are available to me already, so I don't have to
type them all in?
Indeed, there is? I found the module called 'string'. In that
module, the following are available to you:
ascii_letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
ascii_lowercase = 'abcdefghijklmnopqrstuvwxyz'
ascii_uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
digits = '0123456789'
hexdigits = '0123456789abcdefABCDEF'
letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
lowercase = 'abcdefghijklmnopqrstuvwxyz'
octdigits = '01234567'
printable = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTU...
punctuation = '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
whitespace = '\t\n\x0b\x0c\r '
OK, so because I believe in strong (or, at least, reasonably strong)
passwords, I'll concatenate a few of these to make the set of
characters that I would like to produce in a password. To me, the
'printable' set seems a bit, well, difficult for the person typing a
password, so I'll stick with the following:
validchars = string.ascii_letters + string.digits + string.punctuation
series = list( validchars )
: passwd = []
: p = input("Enter the length you want your password to be: ")
: # length of password
Maybe you could make the function 'new_pass' take as an argument the
number of characters. That way, your function would not need to
read input from anyplace else (the console). It could generate
passwords of any length regardless of whether it was called from a
CGI or command-line or even used from a bulk password generation
system.
: for i in range(p):
: r = random.randint(0, 94)
Uh-oh! You had already counted and hard-coded the length of your
variable 'series'! What happens if I want to add a few characters
at the end? Like maybe the €, the £ or the ¥. I am currently
obsessed with (con)currency.
If you were to let Python count the elements in your variable
'series', then you would not have to have counted all 94 elements
yourself. So, think about why this might be better (more
maintainable):
: passwd = []
: for i in range(p):
: r = random.randint(0, len(series))
: passwd.append(series[r]) # Append a random char from series[] to passwd
Now, in the (admittedly, revised loop, above), you generate a single
random.randint() for each of the elements that you wish to extract.
Chances are that somebody has already implemented a feature to do
this sort of thing. Doesn't it seem like a pretty rational sort of
thing to have a compute do? Select a bunch of elements randomly
from an input set?
So, let's try this one of two different ways. Using option A, you
can mix up your data and repeatedly pull out the same result
for the N items:
random.shuffle(series)
''.join(series[0:p])
In option B, you would get a different result each time:
''.join(random.sample(validchars,p))
So, I would rewrite your function to be (substituting 'charcount'
for 'p'):
#! /usr/bin/env python
import string
import random
def new_pass(charcount):
validchars = string.ascii_letters + string.digits + string.punctuation
series = list( validchars )
random.shuffle(series)
print ''.join(series[0:charcount])
if __name__ == '__main__':
new_pass(int(input("Enter the length you want your password to be: ")))
Two others have already suggested that you look at the string and
random modules. Here's just one example of how you could use them
together. Now, let's see what you do with MD5 and SHA. (You are
looking at 'hashlib', correct?)
Good luck,
-Martin
--
Martin A. Brown
http://linux-ip.net/
More information about the Tutor
mailing list