bgneal@24: ====== bgneal@24: Purple bgneal@24: ====== bgneal@24: bgneal@24: A historically accurate PURPLE simulator written in Python 3 bgneal@24: ------------------------------------------------------------ bgneal@24: bgneal@24: :Author: Brian Neal bgneal@24: :Version: 0.1 bgneal@24: :Date: February 17, 2013 bgneal@24: :Home Page: https://bitbucket.org/bgneal/purple/ bgneal@24: :License: MIT License (see LICENSE.txt) bgneal@24: :Documentation: This file bgneal@24: :Support: https://bitbucket.org/bgneal/purple/issues bgneal@24: bgneal@26: ``Purple`` is a Python library and command-line utility for simulating the bgneal@26: `PURPLE Machine`_, a cipher machine used by the Japanese Foreign Office before bgneal@26: and during the Second World War. PURPLE was the code name given to the machine bgneal@26: by U.S. cryptanalysts. The Japanese called the machine *97-shiki ōbun inji-ki* bgneal@26: (System 97 Printing Machine for European Characters), and *Angōki B-kata* (Type bgneal@26: B Cipher Machine). The machine was used for secure diplomatic communications bgneal@26: and was implemented as an electromechanical stepping-switch device. bgneal@24: bgneal@24: This project is a Python 3 library and command-line utility for encrypting and bgneal@24: decrypting text by simulating the operation of an actual PURPLE machine. bgneal@24: bgneal@26: If you are brand new to the ``Purple`` cipher machine, please skip down to the bgneal@26: references section and familiarize yourself with the device. This will help you bgneal@26: understand the terminology used in the documentation, below. bgneal@26: bgneal@24: bgneal@24: Requirements bgneal@24: ############ bgneal@24: bgneal@24: ``Purple`` was written in Python_ 3, specifically 3.3.2, and has no other external bgneal@24: dependencies. bgneal@24: bgneal@24: bgneal@24: Installation bgneal@24: ############ bgneal@24: bgneal@24: ``Purple`` is available on the `Python Package Index`_ (PyPI). There are bgneal@24: a number of ways to install to ``Purple``, detailed below. The author bgneal@24: recommends you install into a virtualenv_. Setting up a virtualenv is not hard, bgneal@24: but describing it is out of scope for this document. Please see the virtualenv_ bgneal@24: documentation for more information. bgneal@24: bgneal@24: You can install it using pip_:: bgneal@24: bgneal@24: $ pip install purple # install bgneal@24: $ pip install --upgrade purple # upgrade bgneal@24: bgneal@24: You can also visit the the `Purple Bitbucket page`_ and download an archive bgneal@24: file of the latest code. Alternatively, if you use Mercurial_, you can clone bgneal@24: the repository with the following command:: bgneal@24: bgneal@24: $ hg clone https://bitbucket.org/bgneal/purple bgneal@24: bgneal@24: If you did not use pip_ (you downloaded or cloned the code yourself), you can bgneal@24: install with:: bgneal@24: bgneal@24: $ cd where-you-extracted-purple bgneal@24: $ python setup.py install bgneal@24: bgneal@24: To run the unit tests:: bgneal@24: bgneal@24: $ cd where-you-extracted-purple bgneal@24: $ python -m unittest discover bgneal@24: bgneal@24: bgneal@26: Initial Settings Syntax bgneal@26: ####################### bgneal@26: bgneal@26: In order to exchange messages, each message recipient must use the same initial bgneal@26: machine settings. For the ``Purple`` machine, these settings are the initial bgneal@26: switch positions for the "sixes" and three "twenties" stepping switches, the bgneal@26: switch motion order (which twenties switch is the fast switch, which is the bgneal@26: middle switch, and which is the slow switch), and finally the plugboard bgneal@26: alphabet mapping. bgneal@26: bgneal@26: The ``Purple`` simulation uses the following syntax in both its command-line bgneal@26: application and library code. bgneal@26: bgneal@26: For the switches, we borrow the notation used by U.S. cryptanalysts, for bgneal@26: example:: bgneal@26: bgneal@26: 9-1,24,6-23 bgneal@26: bgneal@26: Here the first number before leading dash, 9, indicates the starting position bgneal@26: of the sixes switch. The next three numbers are the starting positions for the bgneal@26: three twenties switches numbered 1, 2, and 3. Each switch position is a number bgneal@26: from 1 through 25, inclusive. Finally, after the last dash are two digits which bgneal@26: indicate the switch stepping motion. The first number, in this case 2, bgneal@26: indicates that the twenties switch #2 is the fast switch. The second number, 3, bgneal@26: indicates twenties switch #3 is the middle switch. Thus the slow switch, which bgneal@26: is never listed, is in this case twenties switch #1. When using this syntax, do bgneal@26: not insert space characters. bgneal@26: bgneal@26: The plugboard alphabet setting describes how the input typewriters are wired to bgneal@26: the plugboard. We represent this setting as a string of the 26 uppercase bgneal@26: alphabet letters where the first six letters are the wiring to the sixes bgneal@26: switch, and the remaining 20 are wired to the first stage of the twenties bgneal@26: switches. For example:: bgneal@26: bgneal@26: AEIOUYBCDFGHJKLMNPQRSTVWXZ bgneal@26: bgneal@26: For the alphabet setting to be valid, do not insert spaces, and ensure all 26 bgneal@26: letters are used exactly once. bgneal@26: bgneal@26: bgneal@24: Command-line Usage bgneal@24: ################## bgneal@24: bgneal@24: To get help on the command-line ``Purple`` utility, execute the ``purple`` bgneal@24: command with the ``--help`` option:: bgneal@24: bgneal@24: $ purple --help bgneal@24: usage: purple [-h] [-e] [-d] [-f] [-s SWITCHES] [-a ALPHABET] [-t TEXT] bgneal@24: [-i FILE] [-g N] [-w N] bgneal@24: bgneal@24: PURPLE cipher machine simulator bgneal@24: bgneal@24: optional arguments: bgneal@24: -h, --help show this help message and exit bgneal@24: -e, --encrypt perform an encrypt operation bgneal@24: -d, --decrypt perform a decrypt operation bgneal@24: -f, --filter filter plaintext and provide useful substitutions bgneal@24: -s SWITCHES, --switches SWITCHES bgneal@24: switch settings, e.g. 9-1,24,6-23 bgneal@24: -a ALPHABET, --alphabet ALPHABET bgneal@24: plugboard wiring string, 26-letters; e.g. bgneal@24: AEIOUYBCDFGHJKLMNPQRSTVWXZ bgneal@24: -t TEXT, --text TEXT input text to encrypt/decrypt bgneal@24: -i FILE, --input FILE bgneal@24: file to read input text from, - for stdin bgneal@24: -g N, --group N if non-zero, group output in N-letter groups [default: bgneal@24: 5] bgneal@24: -w N, --width N wrap output text to N letters; a value of 0 means do bgneal@24: not wrap [default: 70] bgneal@24: bgneal@24: Supply either -e or -d, but not both, to perform either an encrypt or decrypt. bgneal@24: If the -s option is not supplied, the value of the environment variable bgneal@24: PURPLE97_SWITCHES will be used. If the -a option is not supplied, the value of bgneal@24: the environment variable PURPLE97_ALPHABET will be used. Input text is bgneal@24: supplied either by the -t or by the -f options, but not both. bgneal@24: bgneal@26: The ``purple`` command operates in two modes, either encrypt (specified with bgneal@26: ``-e`` or ``--encrypt``) or decrypt (``-d`` or ``--decrypt``). Input text can bgneal@26: be specified on the command-line with the ``-t`` or ``--text`` option, or bgneal@26: a read from a file (``-i`` or ``--input``). bgneal@26: bgneal@26: The ``-s`` (or ``--switches``) and ``-a`` (or ``--alphabet``) settings bgneal@26: determine the initial machine settings. They use the syntax described above in bgneal@26: the Initial Settings Syntax section. bgneal@24: bgneal@24: If you are going to be working with the same initial switch settings and bgneal@26: plugboard alphabet over many command invocations it may be more convenient to bgneal@26: specify them as environment variables instead of repeatedly using the bgneal@26: command-line arguments. The examples below assume these statements have been bgneal@26: executed:: bgneal@24: bgneal@24: $ export PURPLE97_SWITCHES=9-1,24,6-23 bgneal@24: $ export PURPLE97_ALPHABET=NOKTYUXEQLHBRMPDICJASVWGZF bgneal@24: bgneal@26: If you do not specify initial settings, the ``purple`` machine will attempt to bgneal@26: read them from these two environment variables. Failing that, ``purple`` will bgneal@26: use the following initial settings: bgneal@26: bgneal@26: * default switch settings: 1-1,1,1-12 bgneal@26: * default alphabet: AEIOUYBCDFGHJKLMNPQRSTVWXZ bgneal@24: bgneal@24: When encrypting text, the ``purple`` machine only accepts the letters A-Z, but bgneal@24: also allows for "garble" letters to be indicated by using the ``-`` (dash) bgneal@24: character. This means all punctuation and spaces must be either be omitted or bgneal@24: input via some other convention. The ``-f`` or ``--filter`` flag, when present, bgneal@24: relaxes these restrictions a bit. When this flag is on, all lowercase letters bgneal@24: will be converted to uppercase, digits will be converted to words (e.g. bgneal@24: 5 becomes FIVE), and all other characters will be ignored. bgneal@24: bgneal@24: A simple encrypt example using the ``-f`` flag is given below:: bgneal@24: bgneal@26: $ purple --encrypt -t "The PURPLE machine is now online" -f bgneal@24: OGIVT SIAAH MWMHT VIBYY JUOJF UE bgneal@24: bgneal@24: By default ``purple`` prints the output in 5-letter groups. This can be bgneal@24: disabled or customized with the ``--group`` and ``--width`` options. bgneal@24: bgneal@24: To decrypt this message:: bgneal@24: bgneal@26: $ purple --decrypt -t "OGIVT SIAAH MWMHT VIBYY JUOJF UE" bgneal@24: THEPU RPLEM ACHIN EISNO WONLI NE bgneal@24: bgneal@24: Note that spaces are ignored on input. Again the output is produced in 5-letter bgneal@24: groups and wrapped at 70 letters per line. Here is the output again with bgneal@24: grouping disabled:: bgneal@24: bgneal@24: $ purple -d -t "OGIVT SIAAH MWMHT VIBYY JUOJF UE" -g 0 bgneal@24: THEPURPLEMACHINEISNOWONLINE bgneal@24: bgneal@26: You can use file redirection to capture output in a file:: bgneal@24: bgneal@24: $ purple -e -t "The PURPLE machine is now online" -f > secret.txt bgneal@24: $ purple -d -i secret.txt bgneal@24: THEPU RPLEM ACHIN EISNO WONLI NE bgneal@24: bgneal@24: bgneal@24: Library Usage bgneal@24: ############# bgneal@24: bgneal@26: To use ``Purple`` from within Python code you must first construct bgneal@26: a ``Purple97`` object, which represents a single PURPLE cipher machine. The bgneal@26: constructor is given below:: bgneal@26: bgneal@26: class Purple97(switches_pos=None, fast_switch=1, middle_switch=2, bgneal@26: alphabet=None) bgneal@26: bgneal@26: The ``switches_pos`` argument, when not ``None``, must be a 4-tuple or list of bgneal@26: 4 integers that describe the initial switch positions. Element 0 is the sixes bgneal@26: initial position, and the remaining elements are the initial positions of the bgneal@26: three twenties switches. These values must be in the range 0-24, inclusive. bgneal@26: If ``None`` then switch positions of all zeroes is assumed. bgneal@26: bgneal@26: The ``fast_switch`` argument indicates which twenties switch (numbered 1-3) is bgneal@26: the fast switch. Likewise, ``middle_switch`` indicates which switch is the bgneal@26: middle switch. The slow switch is inferred. It is an error to give the bgneal@26: ``fast_switch`` and ``middle_switch`` arguments the same value. bgneal@26: bgneal@26: The ``alphabet`` argument is the plugboard alphabet mapping. It is expected to bgneal@26: be a 26-letter uppercase string. If ``None``, a mapping of bgneal@26: ``AEIOUYBCDFGHJKLMNPQRSTVWXZ`` is assumed. bgneal@26: bgneal@26: For convenience, another constructor is provided that allows you to specify bgneal@26: initial settings in the syntax described above:: bgneal@26: bgneal@26: classmethod Purple97.from_key_sheet(switches, alphabet=None) bgneal@26: bgneal@26: Here ``switches`` is a string in the syntax described above, e.g. bgneal@26: ``'9-1,24,6-23'``. bgneal@26: bgneal@26: The ``alphabet`` argument is as described in the first constructor. bgneal@26: bgneal@26: Once constructed, you can use the ``Purple97`` object to perform encrypt and bgneal@26: decrypt operations. For example:: bgneal@26: bgneal@26: from purple.machine import Purple97 bgneal@26: bgneal@26: purple = Purple97.from_key_sheet( bgneal@26: switches='9-1,24,6-23', bgneal@26: alphabet='NOKTYUXEQLHBRMPDICJASVWGZF') bgneal@26: bgneal@26: ciphertext = purple.encrypt('THEPURPLEMACHINEISONLINE') bgneal@26: bgneal@26: purple = Purple97([8, 0, 23, 5], fast_switch=2, middle_switch=3, bgneal@26: alphabet='NOKTYUXEQLHBRMPDICJASVWGZF') bgneal@26: bgneal@26: plaintext = purple.decrypt(ciphertext) bgneal@26: bgneal@26: For more information, please review the docstrings in the code. bgneal@26: bgneal@24: bgneal@24: Support bgneal@24: ####### bgneal@24: bgneal@26: To report a bug or suggest a feature, please use the issue tracker at the bgneal@29: `Purple Bitbucket page`_. You can also email the author using the address at bgneal@29: the top of this file. bgneal@26: bgneal@24: bgneal@24: References bgneal@24: ########## bgneal@24: bgneal@26: #. *PURPLE Revealed: Simulation and Computer-aided Cryptanalysis of Angooki bgneal@26: Taipu B*, by Wes Freeman, Geoff Sullivan, and Frode Weierud. This paper bgneal@26: was published in Cryptologia, Volume 27, Issue 1, January, 2003, pp. 1-43. bgneal@26: #. Frode Weierud's CryptoCellar page: `The PURPLE Machine`_ bgneal@26: #. Wikipedia Article: `PURPLE Machine`_ bgneal@26: bgneal@26: The paper in reference 1 is also available here: bgneal@26: http://cryptocellar.web.cern.ch/cryptocellar/pubs/PurpleRevealed.pdf bgneal@26: bgneal@26: This simulator would not have been possible without Frode Weierud's bgneal@26: CryptoCellar page and the detailed explanations and analysis found in reference bgneal@26: 1. The author is also deeply grateful for email discussions with Frode Weierud bgneal@26: and Geoff Sullivan who provided me with plaintext, advice, and encouragement. bgneal@26: bgneal@26: The ``Purple`` simulator's operation was checked against the simulator found in bgneal@26: reference 2. bgneal@26: bgneal@24: bgneal@24: .. _PURPLE Machine: http://en.wikipedia.org/wiki/Purple_(cipher_machine) bgneal@24: .. _Python: http://www.python.org bgneal@26: .. _Python Package Index: http://pypi.python.org/pypi/purple/ bgneal@24: .. _virtualenv: http://www.virtualenv.org/ bgneal@24: .. _pip: http://www.pip-installer.org bgneal@24: .. _Purple Bitbucket page: https://bitbucket.org/bgneal/purple/ bgneal@24: .. _Mercurial: http://mercurial.selenic.com/ bgneal@26: .. _The PURPLE Machine: http://cryptocellar.web.cern.ch/cryptocellar/simula/purple/