#!/usr/bin/python """generate word compound passwords usage: pwgen -c [number_of_phrases default=1] or pwgen [len default=20] [number_of_phrases default=1] // no conjunctions -c use conjunction """ import random, sys targetLen = 20 # default pw len useConjunction = False number = 1 punc = " !@#$%^&*()-_=+[{]}\|;:/?.>,<`~" number_punc = "0123456789" def toInt(s, chkRange, errStr = "sorry, that's not a number", rangeStr = "sorry, I can't do that number"): try: t = int(s) except: print errStr sys.exit() if tchkRange[1]: print rangeStr sys.exit() return t narg = 1 if len(sys.argv)>1: if sys.argv[1]=="-h" or sys.argv[1]=="--help": print "pwgen.py v1.3 generate passphrase; inspired by xkcd/936 and SteveGibson\n" print "Usage: pwgen.py [-p | -P | -n ] [length [num_phrases]] " print " pwgen.py -c [num_phrases]" print " pwgen.py -h | --help \n" print " -p pad with only spaces (for smartphone)" print " -P pad with spaces, period and comma (for smartphone)" print " -n pad with numbers" print " -N pad with numbers, spaces, period, comma like -P -n" print " length make pass phrases padded with punctuation filler; default=20" print " -c make 2 word pass phrases with a conjuction filler" print " num_phrases make multiple pass phrases, one per line; default=1\n" sys.exit() elif sys.argv[1]=="-c": # conjunction mode useConjunction = True narg = narg + 1 elif sys.argv[1]=='-n': # number fill mode punc = number_punc narg = narg + 1 elif sys.argv[1]=='-N': punc = number_punc + " ,." narg = narg + 1 elif sys.argv[1]=="-p": # use only space punc = " " narg = narg + 1 elif sys.argv[1]=="-P": punc = " .," narg = narg + 1 if not useConjunction: if len(sys.argv)>narg: targetLen = toInt(sys.argv[narg],[12,36],rangeStr = "Sorry, I can't build phrases that long") narg = narg + 1 if len(sys.argv)>narg: number = toInt(sys.argv[narg],[0,40]) # pick off the number of phrases f = open("/usr/share/dict/words") #f = open("/usr/share/dict/corncob_lowercase.txt") d = f.read().splitlines() f.close() numWords = len(d) for i in range(number): w=['','',''] for i in range(3): w[i] = d[random.randint(0,numWords-1)] while (len(w[i]) > 10) or (w[i].endswith("'s")): w[i] = d[random.randint(0,numWords-1)] whole = len(w[0])+len(w[1]) thisPunct = punc[int(random.random() * len(punc))] conjunctions = ["and", "and a", "and the","or", "or the", "or a", "with a", "with", "with the", "by a", "by the", "on a", "on the","on", "in a", "in the", "in", "for", "for a", "for the"] if useConjunction == False: if whole + 6 >= targetLen: # if 2 words is enough r = max(1,targetLen - whole) pw = w[0] + thisPunct*r + w[1] else: # otherwise use 3 whole = whole + len(w[2]) r = targetLen - whole if r<2: r = 2 pw = w[0] + thisPunct*(r/2) + w[1] + thisPunct*(r-r/2) + w[2] else: conj = conjunctions[random.randint(0,len(conjunctions)-1)] if w[1][0].lower() in ['a','A','e','E','i','I','o','O','u','U']: if conj[-2:]==" a": conj = conj+'n' pw = w[0] + ' ' + conj + ' ' + w[1] print pw """ although this read n; i="1"; while [ $i -le $n ]; do cat /etc/dictionaries-common/words | shuf | head -1; i=$(( $i + 1 )); done will do the job almost as well """