Source code for src.ch04.practice.p5_hack_route

"""Another way to hack a route cipher.

Already implemented in :py:mod:`~src.ch04.practice.p1_hack_lincoln`, but this
version will use the building blocks made in
:py:mod:`~src.ch04.practice.p2_identify_cipher`,
:py:mod:`~src.ch04.practice.p3_get_keys`, and
:py:mod:`~src.ch04.practice.p4_generate_keys`.

"""
from src.ch03.c1_anagram_generator import split
from src.ch04.practice.p2_identify_cipher import is_substitution
from src.ch04.practice.p3_get_keys import key_to_dict
from src.ch04.practice.p4_generate_keys import generate_keys


[docs]def decode_route(keys: dict, cipherlist: list) -> list: """Decode route cipher. Decode **cipherlist** encoded with a route cipher using **keys**. Args: keys (dict): ``up``/``down`` dictionary with column numbers as keys. cipherlist (list): List of strings representing encoded message. Returns: List of strings representing plaintext message. Note: Assumes vertical encoding route. """ table, message = [], [] split_list = split(cipherlist, len(keys)) # Build translation table. for key, value in keys.items(): if value == 'down': # If down, reverse direction split_list[key - 1].reverse() table.append(split_list[key - 1]) # For each column in the table, copy the relevant row. rows = len(split_list[0]) for row in range(rows): for column in table: message.append(column[row]) return message
[docs]def hack_route(ciphertext: str, columns: int) -> None: """Hack route cipher using brute-force attack. Determine if **ciphertext** is a transposition cipher. If so, use **columns** to generate all possible keys. Convert each key to an ``up``/``down`` dictionary for each route to take, then print the result of each key. Args: ciphertext (str): Route cipher encoded string to hack. columns (int): Number route cipher columns. Returns: :py:obj:`None`. Prints all possible decoded messages. """ if ciphertext.isupper(): # Most functions assume lowercase, despite cryptographic convention. ciphertext = ciphertext.lower() if is_substitution(ciphertext): print('Hey, bub, I can\'t help you with substitution ciphers.') return None # Get all possible keys with given number of columns. keys = generate_keys(columns) # For each key, decode route cipher and print result. for key in keys: message = ' '.join(decode_route(key_to_dict(key), ciphertext.split())) print(f'Key: {key}\nDecoded message: {message}\n') return None
[docs]def main(): """Demonstrate the route cipher hacker.""" print('There\'s more than one way to hack a route cipher! I can also do a ' 'brute-force\nhack of a route cipher. Although, you\'ll have to ' 'tell me how many columns to\nuse.') print('\nNote: I only hack the route cipher. I leave the ' 'word-transposition cipher to\nyou and your biochemical brain.\n') # Four column route 'cyphertext' from book. ciphertext = """REST TRANSPORT YOU GODWIN VILLAGE ROANOKE WITH ARE YOUR IS JUST SUPPLIES FREE SNOW HEADING TO GONE TO SOUTH FILLER""" print(f'Hacking: {ciphertext}\n') hack_route(ciphertext, 4)
if __name__ == '__main__': main()