# dead simple dictionary attack for fixed-length passwords. # this is far from optimal. from collections import defaultdict import argparse import sys import random program = sys.argv[0] args = sys.argv[1:] parser = argparse.ArgumentParser( description="attack: produce fixed-length strings from dictionaries") parser.add_argument( 'length', type=int, help="the length of the strings to output") parser.add_argument( 'path', metavar='text-file', nargs='+', help="a dictionary file containing one string per line") parser.add_argument( '-n', metavar='limit', type=float, default='inf', help="output this many strings and exit") parser.add_argument( '-s', metavar='seed', type=int, default=None, help="use as a seed for the random number generator") a = parser.parse_args(args) seed = a.s limit = a.n paths = a.path fixed_length = a.length del a lines = [] for path in paths: with open(path, "r") as f: for line in f: lines.append(line.strip('\r\n')) nlines = defaultdict(lambda: []) ncount = defaultdict(lambda: 0) for line in lines: length = len(line) if length == 0 or length > fixed_length: continue nlines[length].append(line) ncount[length] += 1 del lines if seed is not None: random.seed(seed) lengths = list(ncount.keys()) length_weights = list(ncount.values()) i = 0 while i < limit: s = '' new_weights = length_weights.copy() while len(s) < fixed_length: if len(s) > 0: for j, length in enumerate(lengths): if len(s) + length > fixed_length: new_weights[j] = 0 if sum(new_weights) == 0: s = '' new_weights = length_weights.copy() continue chosen_length = random.choices(lengths, new_weights)[0] s += random.choice(nlines[chosen_length]) try: print(s) except OSError: # pipe closed. break i += 1