bgneal@24
|
1 ======
|
bgneal@24
|
2 Purple
|
bgneal@24
|
3 ======
|
bgneal@24
|
4
|
bgneal@24
|
5 A historically accurate PURPLE simulator written in Python 3
|
bgneal@24
|
6 ------------------------------------------------------------
|
bgneal@24
|
7
|
bgneal@24
|
8 :Author: Brian Neal <bgneal@gmail.com>
|
bgneal@24
|
9 :Version: 0.1
|
bgneal@24
|
10 :Date: February 17, 2013
|
bgneal@24
|
11 :Home Page: https://bitbucket.org/bgneal/purple/
|
bgneal@24
|
12 :License: MIT License (see LICENSE.txt)
|
bgneal@24
|
13 :Documentation: This file
|
bgneal@24
|
14 :Support: https://bitbucket.org/bgneal/purple/issues
|
bgneal@24
|
15
|
bgneal@26
|
16 ``Purple`` is a Python library and command-line utility for simulating the
|
bgneal@26
|
17 `PURPLE Machine`_, a cipher machine used by the Japanese Foreign Office before
|
bgneal@26
|
18 and during the Second World War. PURPLE was the code name given to the machine
|
bgneal@26
|
19 by U.S. cryptanalysts. The Japanese called the machine *97-shiki ōbun inji-ki*
|
bgneal@26
|
20 (System 97 Printing Machine for European Characters), and *Angōki B-kata* (Type
|
bgneal@26
|
21 B Cipher Machine). The machine was used for secure diplomatic communications
|
bgneal@26
|
22 and was implemented as an electromechanical stepping-switch device.
|
bgneal@24
|
23
|
bgneal@24
|
24 This project is a Python 3 library and command-line utility for encrypting and
|
bgneal@24
|
25 decrypting text by simulating the operation of an actual PURPLE machine.
|
bgneal@24
|
26
|
bgneal@26
|
27 If you are brand new to the ``Purple`` cipher machine, please skip down to the
|
bgneal@26
|
28 references section and familiarize yourself with the device. This will help you
|
bgneal@26
|
29 understand the terminology used in the documentation, below.
|
bgneal@26
|
30
|
bgneal@24
|
31
|
bgneal@24
|
32 Requirements
|
bgneal@24
|
33 ############
|
bgneal@24
|
34
|
bgneal@24
|
35 ``Purple`` was written in Python_ 3, specifically 3.3.2, and has no other external
|
bgneal@24
|
36 dependencies.
|
bgneal@24
|
37
|
bgneal@24
|
38
|
bgneal@24
|
39 Installation
|
bgneal@24
|
40 ############
|
bgneal@24
|
41
|
bgneal@24
|
42 ``Purple`` is available on the `Python Package Index`_ (PyPI). There are
|
bgneal@24
|
43 a number of ways to install to ``Purple``, detailed below. The author
|
bgneal@24
|
44 recommends you install into a virtualenv_. Setting up a virtualenv is not hard,
|
bgneal@24
|
45 but describing it is out of scope for this document. Please see the virtualenv_
|
bgneal@24
|
46 documentation for more information.
|
bgneal@24
|
47
|
bgneal@24
|
48 You can install it using pip_::
|
bgneal@24
|
49
|
bgneal@24
|
50 $ pip install purple # install
|
bgneal@24
|
51 $ pip install --upgrade purple # upgrade
|
bgneal@24
|
52
|
bgneal@24
|
53 You can also visit the the `Purple Bitbucket page`_ and download an archive
|
bgneal@24
|
54 file of the latest code. Alternatively, if you use Mercurial_, you can clone
|
bgneal@24
|
55 the repository with the following command::
|
bgneal@24
|
56
|
bgneal@24
|
57 $ hg clone https://bitbucket.org/bgneal/purple
|
bgneal@24
|
58
|
bgneal@24
|
59 If you did not use pip_ (you downloaded or cloned the code yourself), you can
|
bgneal@24
|
60 install with::
|
bgneal@24
|
61
|
bgneal@24
|
62 $ cd where-you-extracted-purple
|
bgneal@24
|
63 $ python setup.py install
|
bgneal@24
|
64
|
bgneal@24
|
65 To run the unit tests::
|
bgneal@24
|
66
|
bgneal@24
|
67 $ cd where-you-extracted-purple
|
bgneal@24
|
68 $ python -m unittest discover
|
bgneal@24
|
69
|
bgneal@24
|
70
|
bgneal@26
|
71 Initial Settings Syntax
|
bgneal@26
|
72 #######################
|
bgneal@26
|
73
|
bgneal@26
|
74 In order to exchange messages, each message recipient must use the same initial
|
bgneal@26
|
75 machine settings. For the ``Purple`` machine, these settings are the initial
|
bgneal@26
|
76 switch positions for the "sixes" and three "twenties" stepping switches, the
|
bgneal@26
|
77 switch motion order (which twenties switch is the fast switch, which is the
|
bgneal@26
|
78 middle switch, and which is the slow switch), and finally the plugboard
|
bgneal@26
|
79 alphabet mapping.
|
bgneal@26
|
80
|
bgneal@26
|
81 The ``Purple`` simulation uses the following syntax in both its command-line
|
bgneal@26
|
82 application and library code.
|
bgneal@26
|
83
|
bgneal@26
|
84 For the switches, we borrow the notation used by U.S. cryptanalysts, for
|
bgneal@26
|
85 example::
|
bgneal@26
|
86
|
bgneal@26
|
87 9-1,24,6-23
|
bgneal@26
|
88
|
bgneal@26
|
89 Here the first number before leading dash, 9, indicates the starting position
|
bgneal@26
|
90 of the sixes switch. The next three numbers are the starting positions for the
|
bgneal@26
|
91 three twenties switches numbered 1, 2, and 3. Each switch position is a number
|
bgneal@26
|
92 from 1 through 25, inclusive. Finally, after the last dash are two digits which
|
bgneal@26
|
93 indicate the switch stepping motion. The first number, in this case 2,
|
bgneal@26
|
94 indicates that the twenties switch #2 is the fast switch. The second number, 3,
|
bgneal@26
|
95 indicates twenties switch #3 is the middle switch. Thus the slow switch, which
|
bgneal@26
|
96 is never listed, is in this case twenties switch #1. When using this syntax, do
|
bgneal@26
|
97 not insert space characters.
|
bgneal@26
|
98
|
bgneal@26
|
99 The plugboard alphabet setting describes how the input typewriters are wired to
|
bgneal@26
|
100 the plugboard. We represent this setting as a string of the 26 uppercase
|
bgneal@26
|
101 alphabet letters where the first six letters are the wiring to the sixes
|
bgneal@26
|
102 switch, and the remaining 20 are wired to the first stage of the twenties
|
bgneal@26
|
103 switches. For example::
|
bgneal@26
|
104
|
bgneal@26
|
105 AEIOUYBCDFGHJKLMNPQRSTVWXZ
|
bgneal@26
|
106
|
bgneal@26
|
107 For the alphabet setting to be valid, do not insert spaces, and ensure all 26
|
bgneal@26
|
108 letters are used exactly once.
|
bgneal@26
|
109
|
bgneal@26
|
110
|
bgneal@24
|
111 Command-line Usage
|
bgneal@24
|
112 ##################
|
bgneal@24
|
113
|
bgneal@24
|
114 To get help on the command-line ``Purple`` utility, execute the ``purple``
|
bgneal@24
|
115 command with the ``--help`` option::
|
bgneal@24
|
116
|
bgneal@24
|
117 $ purple --help
|
bgneal@24
|
118 usage: purple [-h] [-e] [-d] [-f] [-s SWITCHES] [-a ALPHABET] [-t TEXT]
|
bgneal@24
|
119 [-i FILE] [-g N] [-w N]
|
bgneal@24
|
120
|
bgneal@24
|
121 PURPLE cipher machine simulator
|
bgneal@24
|
122
|
bgneal@24
|
123 optional arguments:
|
bgneal@24
|
124 -h, --help show this help message and exit
|
bgneal@24
|
125 -e, --encrypt perform an encrypt operation
|
bgneal@24
|
126 -d, --decrypt perform a decrypt operation
|
bgneal@24
|
127 -f, --filter filter plaintext and provide useful substitutions
|
bgneal@24
|
128 -s SWITCHES, --switches SWITCHES
|
bgneal@24
|
129 switch settings, e.g. 9-1,24,6-23
|
bgneal@24
|
130 -a ALPHABET, --alphabet ALPHABET
|
bgneal@24
|
131 plugboard wiring string, 26-letters; e.g.
|
bgneal@24
|
132 AEIOUYBCDFGHJKLMNPQRSTVWXZ
|
bgneal@24
|
133 -t TEXT, --text TEXT input text to encrypt/decrypt
|
bgneal@24
|
134 -i FILE, --input FILE
|
bgneal@24
|
135 file to read input text from, - for stdin
|
bgneal@24
|
136 -g N, --group N if non-zero, group output in N-letter groups [default:
|
bgneal@24
|
137 5]
|
bgneal@24
|
138 -w N, --width N wrap output text to N letters; a value of 0 means do
|
bgneal@24
|
139 not wrap [default: 70]
|
bgneal@24
|
140
|
bgneal@24
|
141 Supply either -e or -d, but not both, to perform either an encrypt or decrypt.
|
bgneal@24
|
142 If the -s option is not supplied, the value of the environment variable
|
bgneal@24
|
143 PURPLE97_SWITCHES will be used. If the -a option is not supplied, the value of
|
bgneal@24
|
144 the environment variable PURPLE97_ALPHABET will be used. Input text is
|
bgneal@24
|
145 supplied either by the -t or by the -f options, but not both.
|
bgneal@24
|
146
|
bgneal@26
|
147 The ``purple`` command operates in two modes, either encrypt (specified with
|
bgneal@26
|
148 ``-e`` or ``--encrypt``) or decrypt (``-d`` or ``--decrypt``). Input text can
|
bgneal@26
|
149 be specified on the command-line with the ``-t`` or ``--text`` option, or
|
bgneal@26
|
150 a read from a file (``-i`` or ``--input``).
|
bgneal@26
|
151
|
bgneal@26
|
152 The ``-s`` (or ``--switches``) and ``-a`` (or ``--alphabet``) settings
|
bgneal@26
|
153 determine the initial machine settings. They use the syntax described above in
|
bgneal@26
|
154 the Initial Settings Syntax section.
|
bgneal@24
|
155
|
bgneal@24
|
156 If you are going to be working with the same initial switch settings and
|
bgneal@26
|
157 plugboard alphabet over many command invocations it may be more convenient to
|
bgneal@26
|
158 specify them as environment variables instead of repeatedly using the
|
bgneal@26
|
159 command-line arguments. The examples below assume these statements have been
|
bgneal@26
|
160 executed::
|
bgneal@24
|
161
|
bgneal@24
|
162 $ export PURPLE97_SWITCHES=9-1,24,6-23
|
bgneal@24
|
163 $ export PURPLE97_ALPHABET=NOKTYUXEQLHBRMPDICJASVWGZF
|
bgneal@24
|
164
|
bgneal@26
|
165 If you do not specify initial settings, the ``purple`` machine will attempt to
|
bgneal@26
|
166 read them from these two environment variables. Failing that, ``purple`` will
|
bgneal@26
|
167 use the following initial settings:
|
bgneal@26
|
168
|
bgneal@26
|
169 * default switch settings: 1-1,1,1-12
|
bgneal@26
|
170 * default alphabet: AEIOUYBCDFGHJKLMNPQRSTVWXZ
|
bgneal@24
|
171
|
bgneal@24
|
172 When encrypting text, the ``purple`` machine only accepts the letters A-Z, but
|
bgneal@24
|
173 also allows for "garble" letters to be indicated by using the ``-`` (dash)
|
bgneal@24
|
174 character. This means all punctuation and spaces must be either be omitted or
|
bgneal@24
|
175 input via some other convention. The ``-f`` or ``--filter`` flag, when present,
|
bgneal@24
|
176 relaxes these restrictions a bit. When this flag is on, all lowercase letters
|
bgneal@24
|
177 will be converted to uppercase, digits will be converted to words (e.g.
|
bgneal@24
|
178 5 becomes FIVE), and all other characters will be ignored.
|
bgneal@24
|
179
|
bgneal@24
|
180 A simple encrypt example using the ``-f`` flag is given below::
|
bgneal@24
|
181
|
bgneal@26
|
182 $ purple --encrypt -t "The PURPLE machine is now online" -f
|
bgneal@24
|
183 OGIVT SIAAH MWMHT VIBYY JUOJF UE
|
bgneal@24
|
184
|
bgneal@24
|
185 By default ``purple`` prints the output in 5-letter groups. This can be
|
bgneal@24
|
186 disabled or customized with the ``--group`` and ``--width`` options.
|
bgneal@24
|
187
|
bgneal@24
|
188 To decrypt this message::
|
bgneal@24
|
189
|
bgneal@26
|
190 $ purple --decrypt -t "OGIVT SIAAH MWMHT VIBYY JUOJF UE"
|
bgneal@24
|
191 THEPU RPLEM ACHIN EISNO WONLI NE
|
bgneal@24
|
192
|
bgneal@24
|
193 Note that spaces are ignored on input. Again the output is produced in 5-letter
|
bgneal@24
|
194 groups and wrapped at 70 letters per line. Here is the output again with
|
bgneal@24
|
195 grouping disabled::
|
bgneal@24
|
196
|
bgneal@24
|
197 $ purple -d -t "OGIVT SIAAH MWMHT VIBYY JUOJF UE" -g 0
|
bgneal@24
|
198 THEPURPLEMACHINEISNOWONLINE
|
bgneal@24
|
199
|
bgneal@26
|
200 You can use file redirection to capture output in a file::
|
bgneal@24
|
201
|
bgneal@24
|
202 $ purple -e -t "The PURPLE machine is now online" -f > secret.txt
|
bgneal@24
|
203 $ purple -d -i secret.txt
|
bgneal@24
|
204 THEPU RPLEM ACHIN EISNO WONLI NE
|
bgneal@24
|
205
|
bgneal@24
|
206
|
bgneal@24
|
207 Library Usage
|
bgneal@24
|
208 #############
|
bgneal@24
|
209
|
bgneal@26
|
210 To use ``Purple`` from within Python code you must first construct
|
bgneal@26
|
211 a ``Purple97`` object, which represents a single PURPLE cipher machine. The
|
bgneal@26
|
212 constructor is given below::
|
bgneal@26
|
213
|
bgneal@26
|
214 class Purple97(switches_pos=None, fast_switch=1, middle_switch=2,
|
bgneal@26
|
215 alphabet=None)
|
bgneal@26
|
216
|
bgneal@26
|
217 The ``switches_pos`` argument, when not ``None``, must be a 4-tuple or list of
|
bgneal@26
|
218 4 integers that describe the initial switch positions. Element 0 is the sixes
|
bgneal@26
|
219 initial position, and the remaining elements are the initial positions of the
|
bgneal@26
|
220 three twenties switches. These values must be in the range 0-24, inclusive.
|
bgneal@26
|
221 If ``None`` then switch positions of all zeroes is assumed.
|
bgneal@26
|
222
|
bgneal@26
|
223 The ``fast_switch`` argument indicates which twenties switch (numbered 1-3) is
|
bgneal@26
|
224 the fast switch. Likewise, ``middle_switch`` indicates which switch is the
|
bgneal@26
|
225 middle switch. The slow switch is inferred. It is an error to give the
|
bgneal@26
|
226 ``fast_switch`` and ``middle_switch`` arguments the same value.
|
bgneal@26
|
227
|
bgneal@26
|
228 The ``alphabet`` argument is the plugboard alphabet mapping. It is expected to
|
bgneal@26
|
229 be a 26-letter uppercase string. If ``None``, a mapping of
|
bgneal@26
|
230 ``AEIOUYBCDFGHJKLMNPQRSTVWXZ`` is assumed.
|
bgneal@26
|
231
|
bgneal@26
|
232 For convenience, another constructor is provided that allows you to specify
|
bgneal@26
|
233 initial settings in the syntax described above::
|
bgneal@26
|
234
|
bgneal@26
|
235 classmethod Purple97.from_key_sheet(switches, alphabet=None)
|
bgneal@26
|
236
|
bgneal@26
|
237 Here ``switches`` is a string in the syntax described above, e.g.
|
bgneal@26
|
238 ``'9-1,24,6-23'``.
|
bgneal@26
|
239
|
bgneal@26
|
240 The ``alphabet`` argument is as described in the first constructor.
|
bgneal@26
|
241
|
bgneal@26
|
242 Once constructed, you can use the ``Purple97`` object to perform encrypt and
|
bgneal@26
|
243 decrypt operations. For example::
|
bgneal@26
|
244
|
bgneal@26
|
245 from purple.machine import Purple97
|
bgneal@26
|
246
|
bgneal@26
|
247 purple = Purple97.from_key_sheet(
|
bgneal@26
|
248 switches='9-1,24,6-23',
|
bgneal@26
|
249 alphabet='NOKTYUXEQLHBRMPDICJASVWGZF')
|
bgneal@26
|
250
|
bgneal@26
|
251 ciphertext = purple.encrypt('THEPURPLEMACHINEISONLINE')
|
bgneal@26
|
252
|
bgneal@26
|
253 purple = Purple97([8, 0, 23, 5], fast_switch=2, middle_switch=3,
|
bgneal@26
|
254 alphabet='NOKTYUXEQLHBRMPDICJASVWGZF')
|
bgneal@26
|
255
|
bgneal@26
|
256 plaintext = purple.decrypt(ciphertext)
|
bgneal@26
|
257
|
bgneal@26
|
258 For more information, please review the docstrings in the code.
|
bgneal@26
|
259
|
bgneal@24
|
260
|
bgneal@24
|
261 Support
|
bgneal@24
|
262 #######
|
bgneal@24
|
263
|
bgneal@26
|
264 To report a bug or suggest a feature, please use the issue tracker at the
|
bgneal@26
|
265 `Purple Bitbucket page`_.
|
bgneal@26
|
266
|
bgneal@24
|
267
|
bgneal@24
|
268 References
|
bgneal@24
|
269 ##########
|
bgneal@24
|
270
|
bgneal@26
|
271 #. *PURPLE Revealed: Simulation and Computer-aided Cryptanalysis of Angooki
|
bgneal@26
|
272 Taipu B*, by Wes Freeman, Geoff Sullivan, and Frode Weierud. This paper
|
bgneal@26
|
273 was published in Cryptologia, Volume 27, Issue 1, January, 2003, pp. 1-43.
|
bgneal@26
|
274 #. Frode Weierud's CryptoCellar page: `The PURPLE Machine`_
|
bgneal@26
|
275 #. Wikipedia Article: `PURPLE Machine`_
|
bgneal@26
|
276
|
bgneal@26
|
277 The paper in reference 1 is also available here:
|
bgneal@26
|
278 http://cryptocellar.web.cern.ch/cryptocellar/pubs/PurpleRevealed.pdf
|
bgneal@26
|
279
|
bgneal@26
|
280 This simulator would not have been possible without Frode Weierud's
|
bgneal@26
|
281 CryptoCellar page and the detailed explanations and analysis found in reference
|
bgneal@26
|
282 1. The author is also deeply grateful for email discussions with Frode Weierud
|
bgneal@26
|
283 and Geoff Sullivan who provided me with plaintext, advice, and encouragement.
|
bgneal@26
|
284
|
bgneal@26
|
285 The ``Purple`` simulator's operation was checked against the simulator found in
|
bgneal@26
|
286 reference 2.
|
bgneal@26
|
287
|
bgneal@24
|
288
|
bgneal@24
|
289 .. _PURPLE Machine: http://en.wikipedia.org/wiki/Purple_(cipher_machine)
|
bgneal@24
|
290 .. _Python: http://www.python.org
|
bgneal@26
|
291 .. _Python Package Index: http://pypi.python.org/pypi/purple/
|
bgneal@24
|
292 .. _virtualenv: http://www.virtualenv.org/
|
bgneal@24
|
293 .. _pip: http://www.pip-installer.org
|
bgneal@24
|
294 .. _Purple Bitbucket page: https://bitbucket.org/bgneal/purple/
|
bgneal@24
|
295 .. _Mercurial: http://mercurial.selenic.com/
|
bgneal@26
|
296 .. _The PURPLE Machine: http://cryptocellar.web.cern.ch/cryptocellar/simula/purple/
|