comparison ppgen.py @ 0:7558ecd1cbf1

Initial version.
author Bernhard Reiter <bernhard@intevation.de>
date Fri, 19 Feb 2016 15:28:46 +0100
parents
children 00ed7df30fe4
comparison
equal deleted inserted replaced
-1:000000000000 0:7558ecd1cbf1
1 #!/usr/bin/env python3
2 """Create a passphrase from a few random words. DRAFT
3
4 Relies on the entropy of python's
5 random.SystemRandom class
6 which (according to the documentation) calls os.urandom()
7 which (according to the documentation) calls the operating system
8 specific randomness source which "should be unpredictable
9 enough for cryptographic applications"
10
11 Requires:
12 * Python v>=3.2
13 * a dictionary, Ding's trans-de-en by default.
14 E.g. on a Debian/Ubuntu system in package "trans-de-en".
15 or from http://ftp.tu-chemnitz.de/pub/Local/urz/ding/de-en/
16
17 Uses a hardcodes filepath and selected language.
18 Search for **customize** below to change it.
19
20 Copyright 2016 by Intevation GmbH.
21 Author: 2016-01-21 Bernhard E. Reiter <bernhard@intevation.de>
22
23 This file is Free Software under the Apache 2.0 license and thus
24 comes without any warranty (to extend permissible under applicable law).
25 """
26
27 import math
28 import re
29 import sys
30
31 from random import SystemRandom
32 _srandom = SystemRandom()
33
34 tainted = False # to be set if we find a hint that the passphrase may be weak
35
36 def buildDictionary():
37 """Build up a dictionary of unique words, calculate stats."""
38 global tainted
39 d = []
40
41 # dictionary for testing
42 #d = ["abc", "aBc", "cde", "efg", "hij", "blubber", "jikf", "zug", "lmf", "opq"]
43
44 # Using the dictionary from Ding **customize**
45 d = readDingDict(filename="/usr/share/trans/de-en", useLeft=True)
46
47 ## for debugging purpuses, dump dictionary
48 #dumpfilename = "ddump.txt"
49 #print("Writing out {}.".format(dumpfilename))
50 #with open(dumpfilename, "w") as f:
51 # for i in d:
52 # f.write("{}\n".format(i))
53
54 # Print some stats on the dictionary to be used
55 dl = len(d)
56 print("Found {:d} dictionary entries".format(dl))
57 if dl < 2000:
58 print("!Your dictionary is below 2k entries, that is quite small!")
59 tainted = True
60
61 print("|= Number of words |= possibilities |")
62 for i in range(1,5):
63 print("| {:2d} | 2^{:4.1f} |".format(
64 i, math.log(dl**i,2)))
65 return d
66
67
68 def readDingDict(filename = "/usr/share/trans/de-en", useLeft=False):
69 """Read dictionary with unique words from file in Ding format.
70
71 useLeft: Boolean to control which language to use
72
73 TODO: add option to use both languages for people that speak them both?
74 """
75
76 dset = set() #using the datatype 'set' to aviod duplicates
77
78 splitter = re.compile(r"""\ \|\ # first pattern ' | '
79 |;\ # second pattern '; '
80 |(?<=\S)/(?=\S) # 3.: '\' surrounded by chars
81 |\s+ # by whitespace
82 """,re.VERBOSE)
83
84 print("Reading entries from {}.".format(filename), end='')
85 counter = 0 # for progress or stopping early
86 with open(filename, "r") as f:
87 for line in f:
88 if line[0] == '#': continue
89
90 # languages are separated by " :: "
91 p = line.partition(" :: ")
92 languageEntry = p[0] if useLeft else p[2]
93
94 for word in splitter.split(languageEntry):
95 word = word.strip('(",.)\'!:;').rstrip('/')
96 if len(word) > 2 and not word[0] in '[{/':
97 dset.add(word)
98
99 #TODO: check for very common words and remove them?
100
101 counter += 1
102 ## stop early when debugging
103 #if counter > 10: break
104 if not counter % 10000:
105 print('.', end='')
106 sys.stdout.flush()
107 print()
108
109 return list(dset)
110
111 def main():
112 global tainted
113 dictionary = buildDictionary()
114
115 howMany = 4
116
117 # use a dictionary with lower case words for a simple check if
118 # our random source is okay
119 print("\nGenerated passphrase with {} randomly selected words:\n".format(
120 howMany))
121 print(" ", end='')
122 words = {}
123 for x in range(howMany):
124 word = _srandom.choice(dictionary)
125 words[word.lower]= True
126 print(word, end='\n ')
127 print("\n")
128
129 if len(words) < howMany:
130 print("! Your random generator is weak")
131 print("! or you are being very lucky.")
132 tainted = True
133
134 if tainted:
135 print("!!! Don't use the resulting passphrase !!!")
136
137 if __name__ == "__main__":
138 main()
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)