# HG changeset patch # User Bernhard Reiter # Date 1475767726 -7200 # Node ID 85c65a59742033dc2ddb17af600ac162d3ee6097 # Parent 757625ec8364edb8bb0dc97e2244b63ea4230f7c Improves: command line options and code style. Adds a command line option for dumping the dictionary into a file. Improves source code style to better conform to pep8. Calls it BETA now. diff -r 757625ec8364 -r 85c65a597420 ppgen.py --- a/ppgen.py Mon May 02 09:26:29 2016 +0200 +++ b/ppgen.py Thu Oct 06 17:28:46 2016 +0200 @@ -1,11 +1,11 @@ #!/usr/bin/env python3 -"""Create a passphrase from a few random words. DRAFT +"""Create a random passphrase from a dictionary of words. BETA Relies on the entropy of python's random.SystemRandom class which (according to the documentation) calls os.urandom() which (according to the documentation) calls the operating system - specific randomness source which "should be unpredictable + specific randomness source which "should be unpredictable enough for cryptographic applications" Requires: @@ -28,6 +28,7 @@ comes without any warranty (to extend permissible under applicable law). """ +import argparse import math import re import sys @@ -37,13 +38,15 @@ tainted = False # to be set if we find a hint that the passphrase may be weak -def buildDictionary(): + +def buildDictionary(options): """Build up a dictionary of unique words, calculate stats.""" global tainted d = [] # dictionary for testing - #d = ["abc", "aBc", "cde", "efg", "hij", "blubber", "jikf", "zug", "lmf", "opq"] + #d = ["abc", "aBc", "cde", "efg", "hij", "blubber", + # "jikf", "zug", "lmf", "opq"] # second test dictionary to show that different string functions are used. #d = [''.join('A' * 1000) for _ in range(1000)] @@ -51,11 +54,11 @@ d = readDingDict(filename="/usr/share/trans/de-en", useLeft=True) ## for debugging purpuses, dump dictionary - #dumpfilename = "ddump.txt" - #print("Writing out {}.".format(dumpfilename)) - #with open(dumpfilename, "w") as f: - # for i in d: - # f.write("{}\n".format(i)) + if options.ddump_filename: + print("Writing out dictionary in '{}'.".format(options.ddump_filename)) + with open(options.ddump_filename, "w") as f: + for i in d: + f.write("{}\n".format(i)) # Print some stats on the dictionary to be used dl = len(d) @@ -65,13 +68,13 @@ tainted = True print("|= Number of words |= possibilities |") - for i in range(1,5): + for i in range(1, 5): print("| {:2d} | 2^{:4.1f} |".format( - i, math.log(dl**i,2))) + i, math.log(dl**i, 2))) return d -def readDingDict(filename = "/usr/share/trans/de-en", useLeft=False): +def readDingDict(filename="/usr/share/trans/de-en", useLeft=False): """Read dictionary with unique words from file in Ding format. useLeft: Boolean to control which language to use @@ -79,19 +82,20 @@ TODO: add option to use both languages for people that speak them both? """ - dset = set() #using the datatype 'set' to aviod duplicates + dset = set() # using the datatype 'set' to aviod duplicates splitter = re.compile(r"""\ \|\ # first pattern ' | ' |;\ # second pattern '; ' |(?<=\S)/(?=\S) # 3.: '\' surrounded by chars |\s+ # by whitespace - """,re.VERBOSE) + """, re.VERBOSE) print("Reading entries from {}.".format(filename), end='') - counter = 0 # for progress or stopping early + counter = 0 # for progress or stopping early with open(filename, "r") as f: for line in f: - if line[0] == '#': continue + if line[0] == '#': + continue # languages are separated by " :: " p = line.partition(" :: ") @@ -114,9 +118,16 @@ return list(dset) + def main(): global tainted - dictionary = buildDictionary() + + parser = argparse.ArgumentParser(description=__doc__.splitlines()[0]) + parser.add_argument('--ddump-filename', + help='filename to dump the dictionary to') + options = parser.parse_args() + + dictionary = buildDictionary(options) howMany = 4 @@ -128,7 +139,7 @@ words = {} for x in range(howMany): word = _srandom.choice(dictionary) - words[word.lower()]= True + words[word.lower()] = True print(word, end='\n ') print("\n")