# HG changeset patch # User Brian Neal # Date 1371848250 18000 # Node ID 853542100fc60e7b8d14c156209ae3ce1c0983c6 # Parent 908510c6d02a650dc434a41bc2f9afb8f2bd4578 Hooking up main to generate_key_list(). Added logging. diff -r 908510c6d02a -r 853542100fc6 m209/keylist/generate.py --- a/m209/keylist/generate.py Wed Jun 19 21:09:48 2013 -0500 +++ b/m209/keylist/generate.py Fri Jun 21 15:57:30 2013 -0500 @@ -6,6 +6,7 @@ import collections import itertools +import logging import random from .key_list import KeyList @@ -15,6 +16,8 @@ from .data import GROUP_A, GROUP_B +logger = logging.getLogger(__name__) + # Maximum number of attempts to generate valid settings before giving up and # raising a M209Error: MAX_ATTEMPTS = 128 @@ -60,6 +63,8 @@ 1942, and TM-11-380B, 20 September 1943." """ + logger.info("Creating key list %s", indicator) + lugs = generate_lugs() pin_list = generate_pin_list() letter_check = generate_letter_check(lugs=lugs, pin_list=pin_list) @@ -124,6 +129,8 @@ else: raise M209Error("generate_pin_list: too many attempts") + logger.info("Pin list generated in %s iteration(s)", n + 1) + return pin_list @@ -147,18 +154,21 @@ ratio = num_eff / TOTAL_PINS if not (0.4 <= ratio <= 0.6): + logger.info("Pin list ratio check failed: %s", ratio) return False # Check for more than 6 consecutive effective pins on a wheel for n, pins in enumerate(pin_list): if check_consecutive(n, pins): + logger.debug("Pin list consecutive effective check failed") return False # Check for more than 6 consecutive ineffective pins on a wheel for n, pins in enumerate(pin_list): if check_consecutive(n, invert_pins(n, pins)): + logger.debug("Pin list consecutive ineffective check failed") return False return True diff -r 908510c6d02a -r 853542100fc6 m209/keylist/key_list.py --- a/m209/keylist/key_list.py Wed Jun 19 21:09:48 2013 -0500 +++ b/m209/keylist/key_list.py Fri Jun 21 15:57:30 2013 -0500 @@ -2,9 +2,19 @@ # This file is part of m209, the M-209 simulation. # m209 is released under the MIT License (see LICENSE.txt). -"""key_list.py - This module defines the KeyList class.""" +"""This module defines the KeyList class and related functions""" import collections +import re + + +VALID_IND_RE = re.compile('^[A-Z]{2}$') + KeyList = collections.namedtuple('KeyList', ['indicator', 'lugs', 'pin_list', 'letter_check']) + + +def valid_indicator(indicator): + """Returns True if the given indicator is valid and False otherwise.""" + return True if VALID_IND_RE.match(indicator) else False diff -r 908510c6d02a -r 853542100fc6 m209/main.py --- a/m209/main.py Wed Jun 19 21:09:48 2013 -0500 +++ b/m209/main.py Fri Jun 21 15:57:30 2013 -0500 @@ -7,6 +7,11 @@ """ import argparse +import logging +import sys + +from .keylist.generate import generate_key_list +from .keylist.key_list import valid_indicator DESC = "M-209 simulator and utility program" @@ -23,11 +28,22 @@ print('Decrypting!', args) +def keygen(args): + """Key list generation subcommand processor""" + print('Creating key list!', args) + if not valid_indicator(args.keylist_indicator): + sys.exit("Invalid key list indicator\n") + + print(generate_key_list(args.keylist_indicator)) + + def main(argv=None): """Entry point for the m209 command-line utility.""" # create the top-level parser parser = argparse.ArgumentParser(description=DESC) + parser.add_argument('-v', '--verbose', action='store_true', + help='enable verbose output') subparsers = parser.add_subparsers(title='list of commands', description='type %(prog)s {command} -h for help on {command}') @@ -47,15 +63,29 @@ enc_parser.set_defaults(subcommand=encrypt) # create the parser for decrypt - enc_parser = subparsers.add_parser('decrypt', aliases=['de'], + dec_parser = subparsers.add_parser('decrypt', aliases=['de'], help='decrypt text') - enc_parser.add_argument('-k', '--keylist', default=DEFAULT_KEY_LIST, + dec_parser.add_argument('-k', '--keylist', default=DEFAULT_KEY_LIST, help='path to key list file [default: %(default)s]') - enc_parser.add_argument('-c', '--ciphertext', + dec_parser.add_argument('-c', '--ciphertext', help='ciphertext string to decrypt; prompted if omitted') - enc_parser.set_defaults(subcommand=decrypt) + dec_parser.set_defaults(subcommand=decrypt) + + # create the parser for generating key lists + + kg_parser = subparsers.add_parser('keygen', aliases=['kg'], + help='generate key list') + kg_parser.add_argument('-k', '--keylist', default=DEFAULT_KEY_LIST, + help='path to key list file [default: %(default)s]') + kg_parser.add_argument('-i', '--keylist-indicator', + help='2 letter key list indicator') + kg_parser.set_defaults(subcommand=keygen) args = parser.parse_args(args=argv) + + level = logging.DEBUG if args.verbose else logging.WARNING + logging.basicConfig(level=level, format='%(levelname)s:%(message)s') + args.subcommand(args)