Update libs
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import argparse, math, random
|
||||
|
||||
from pyutil.mathutil import div_ceil
|
||||
|
||||
from pkg_resources import resource_stream
|
||||
|
||||
def recursive_subset_sum(entropy_needed, wordlists):
|
||||
# Pick a minimalish set of numbers which sum to at least
|
||||
# entropy_needed.
|
||||
|
||||
# Okay now what's the smallest number of words which will give us
|
||||
# at least this much entropy?
|
||||
entropy_of_biggest_wordlist = wordlists[-1][0]
|
||||
assert isinstance(entropy_of_biggest_wordlist, float), wordlists[-1]
|
||||
needed_words = div_ceil(entropy_needed, entropy_of_biggest_wordlist)
|
||||
# How much entropy do we need from each word?
|
||||
needed_entropy_per_word = entropy_needed / needed_words
|
||||
# What's the smallest wordlist that offers at least this much
|
||||
# entropy per word?
|
||||
for (wlentropy, wl) in wordlists:
|
||||
if wlentropy >= needed_entropy_per_word:
|
||||
break
|
||||
assert wlentropy >= needed_entropy_per_word, (wlentropy, needed_entropy_per_word)
|
||||
|
||||
result = [(wlentropy, wl)]
|
||||
# If we need more, recurse...
|
||||
if wlentropy < entropy_needed:
|
||||
rest = recursive_subset_sum(entropy_needed - wlentropy, wordlists)
|
||||
result.extend(rest)
|
||||
return result
|
||||
|
||||
def gen_passphrase(entropy, allwords):
|
||||
maxlenwords = []
|
||||
i = 2 # The smallest set is words of length 1 or 2.
|
||||
words = [x for x in allwords if len(x) <= i]
|
||||
maxlenwords.append((math.log(len(words), 2), words))
|
||||
while len(maxlenwords[-1][1]) < len(allwords):
|
||||
i += 1
|
||||
words = [x for x in allwords if len(x) <= i]
|
||||
maxlenwords.append((math.log(len(words), 2), words))
|
||||
|
||||
sr = random.SystemRandom()
|
||||
passphrase = []
|
||||
|
||||
wordlists_to_use = recursive_subset_sum(entropy, maxlenwords)
|
||||
|
||||
passphraseentropy = 0.0
|
||||
for (wle, wl) in wordlists_to_use:
|
||||
passphrase.append(sr.choice(wl))
|
||||
passphraseentropy += wle
|
||||
|
||||
return (u".".join(passphrase), passphraseentropy)
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(prog="chbs", description="Create a random passphrase by picking a few random words.")
|
||||
|
||||
parser.add_argument('-d', '--dictionary', help="what file to read a list of words from (or omit this option to use chbs's bundled dictionary)", type=argparse.FileType('rU'), metavar="DICT")
|
||||
parser.add_argument('bits', help="how many bits of entropy minimum", type=float, metavar="BITS")
|
||||
args = parser.parse_args()
|
||||
|
||||
dicti = args.dictionary
|
||||
if not dicti:
|
||||
dicti = resource_stream('pyutil', 'data/wordlist.txt')
|
||||
allwords = set([x.decode('utf-8').strip().lower() for x in dicti.readlines()])
|
||||
|
||||
passphrase, bits = gen_passphrase(args.bits, allwords)
|
||||
|
||||
print u"Your new password is: '%s'. It is worth about %s bits." % (passphrase, bits)
|
||||
Reference in New Issue
Block a user