def test_enigma_transmission_decryption(): start_position, encrypted_key, message = "WZA", "IGI", "EVIVKEGIPXXOQZ" enigma = Enigma(["I", "II", "III"], [1, 1, 1], "B", "AB FD CH LO PW", [0, 0, 0]) transmission = enigma.decrypt_transmission(start_position, encrypted_key, message) assert transmission == "HELLOHOWAREYOU"
def test_enigma_transmission_encryption(): start_position, message_key, message = "WZA", "SXT", "HELLOHOWAREYOU" enigma = Enigma(["I", "II", "III"], [1, 1, 1], "B", "AB FD CH LO PW", [0, 0, 0]) transmission = enigma.encrypt_transmission(message, start_position, message_key) assert transmission == ("WZA", "IGI", "EVIVKEGIPXXOQZ")
def test_enigma_transmission_encryption_provides_defaults(): message = "HELLOHOWAREYOU" enigma = Enigma(["I", "II", "III"], [1, 1, 1], "B", "AB FD CH LO PW", [0, 0, 0]) transmission = enigma.encrypt_transmission(message) assert len(transmission[0]) == 3 assert len(transmission[1]) == 3 assert len(transmission[2]) == len(message)
def test_turnover_and_double_stepping(): enigma = Enigma(["I", "II", "III"], [1, 1, 1], "B", "", ["Z", "Z", "Z"]) message = ( "Tomorrow and tomorrow and tomorrow Creeps in this petty pace from day to day " "To the last syllable of recorded time And all our yesterdays have lighted " "fools The way to dusty death Out out brief candle Lifes but a walking shadow " "a poor player That struts and frets his hour upon the stage And then is heard " "no more It is a tale Told by an idiot full of sound and fury Signifying " "nothing") encrypted = enigma.encrypt(message) assert encrypted == ( "MCDDJUXX CJJ JIHHBBLX ZTS KWSSNDHR AMWKIY JP BIDH BOKYL NGZW PATP GIA EI TCM " "MX NXJ CGHW EGNTOJXB TL JDHINBRZ HRNJ HCV RBA UHF MUILKNUMLO VXNA PRZCCNL " "QCCCA MBP CNJ VQ XWYVS KJRML ECE QHE KGUCO JJHCJM FEPSX FOA C LOUGDOO EZOSIG " "Y CTMJ MOFPIS WBTX NAHXIZ RUK ZGKXI VSF BWKU CVWH NZK TKDMW WHK MCFX JC PKCYI " "IJ KWGP OH FC N PLTF ZRIA YH XT BJOHA SOVG WX GSZMZ GSJ AKVZ QTVWSAPOYZ " "VKBTRCO")
def test_update_enigma_rotor_positions(): enigma = Enigma(["I", "II", "III"], [1, 1, 1], "B", "", [0, 0, 0]) encrypted1 = enigma.encrypt("A") enigma.update_rotor_positions([0, 0, 0]) encrypted2 = enigma.encrypt("A") assert encrypted1 == encrypted2 == "E"
def main(argv: Sequence[str] | None = None) -> int: argv = argv if argv is not None else sys.argv[1:] parser = argparse.ArgumentParser( prog="enigma-simulator", description= ("Encrypt or decrypt a simple message or transmission using a simulated " "Enigma machine. The settings of the machine can be passed in " "individually, or can pass in an 'Enigma key' file (see below)."), ) parser.add_argument( "-k", "--key", type=str, nargs=1, help="Path to key file. Must be a json or a yaml file.", ) parser.add_argument( "-n", "--names", type=str, nargs=3, choices=["I", "II", "III", "IV", "V", "VI", "VII", "VIII"], metavar=("rotor_name_1", "rotor_name_2", "rotor_name_3"), help= ("List of the names of which 3 rotors to use. Should be one of: 'I', 'II', " "'III', 'IV', 'V', 'VI', 'VII' or 'VIII'."), ) parser.add_argument( "-s", "--settings", type=int, nargs=3, metavar=("setting_1", "setting_2", "setting_3"), help="Ring settings of the 3 rotors.", ) parser.add_argument( "-r", "--reflector", type=str, nargs="?", default="I", choices=["A", "B", "C", "I"], help="Reflector type.", ) parser.add_argument( "-c", "--connections", type=str, nargs="?", default="", help= ("Plugboard connections as pairs of letters, e.g. 'AB CD' to swap the " "letters A and B, and the letters C and D."), ) subparsers = parser.add_subparsers(help="sub-command help") message_parser = subparsers.add_parser( "message", help="Encrypt or decrypt a simple message.") message_parser.add_argument( "positions", type=str, nargs=1, help= "Positions of the 3 rotors. Should be a 3-length string, e.g. 'ABC'.", ) message_parser.add_argument( "message", type=str, nargs="*", help="Message to encrypt/decrypt. Spaces are kept.", ) transmission_parser = subparsers.add_parser( "transmission", help="Encrypt or decrypt a transmission. See README for details.", ) transmission_parser.add_argument( "-p", "--positions", type=str, nargs="?", help= "Positions of the 3 rotors. Should be a 3-length string, e.g. 'ABC'.", ) transmission_parser.add_argument( "-m", "--message-key", type=str, nargs="?", help="Secret message key. Should be a 3-length string, e.g. 'ABC'.", ) transmission_parser.add_argument( "message", type=str, nargs="*", help="Message to encrypt/decrypt. Spaces are kept.", ) group = transmission_parser.add_mutually_exclusive_group(required=True) group.add_argument("--encrypt", action="store_true", help="Encryption mode.") group.add_argument("--decrypt", action="store_false", help="Decryption mode.") args = parser.parse_args(argv) if args.key: enigma_key = load_key(args.key[0]) enigma = create_enigma_from_key(enigma_key) else: positions = (list(args.positions[0] if isinstance( args.positions, list) else args.positions) if args.positions is not None else ["A", "A", "A"]) enigma = Enigma( args.names, args.settings, args.reflector, args.connections, positions, ) message = " ".join(args.message) if "encrypt" in args: # transmission print(args.positions, args.message_key, message) if args.encrypt: output.write_line(" ".join( enigma.encrypt_transmission(message, args.positions, args.message_key))) else: output.write_line( enigma.decrypt_transmission(args.positions, args.message_key, message)) else: encrypted = enigma.encrypt(message) output.write_line(encrypted) return 0
def test_encryption(message, expected): enigma = Enigma(["I", "II", "III"], [1, 1, 1], "B", "", ["A", "A", "A"]) encrypted = enigma.encrypt(message) assert encrypted == expected