Enigma Machine Simulation in Python. Ask Question Asked 4 years, 1 month ago. Active 3 years, 2 months ago. Viewed 3k times 7 $ begingroup $ Background and Example. Implementation of a simulated Enigma Machine in python. Used in IB Math Exploration. User is expected to run Enigma/Enigma.py. The Bombe directory contains a simple and a bit more complex implementation of the Bombe machine. This is incomplete. Implementation of a simulated Enigma Machine in python. Used in IB Math Exploration. User is expected to run Enigma/Enigma.py. The Bombe directory contains a simple and a bit more complex implementation of the Bombe machine. So, in this article I want to explain how Enigma works on the example of a 3 rotors enigma, showing that the same time how you can create an enigma by yourself in python. The anatomy of an Enigma.
The Py-Enigma simulation is made up of several Python classes as describedbelow.
EnigmaMachines¶
The
EnigmaMachine
class represents an assembled Enigma machine that consistsof rotors, a plugboard, a keyboard, and indicator lamps. The keyboard and lampsact as input and outputs. The other components are represented by Pythonclasses.EnigmaMachine class reference¶
The top-level
EnigmaMachine
class represents an assembled Enigma machine.The EnigmaMachine
class resides in the enigma.machine
module.enigma.machine.
EnigmaMachine
(rotors, reflector, plugboard)¶Top-level class that represents Enigma machines.
Parameters: |
|
---|
from_key_sheet
([rotors='I II III'[, ring_settings=None[, reflector='B'[, plugboard_settings=None]]]])¶Convenience function to build an EnigmaMachine from the data as youmight find it on a monthly key sheet (code book).
Parameters: |
|
---|
The
ring_settings
parameter can accept either:- A list/tuple of integers with values between 0-25.
- A string; either space separated letters or numbers, e.g.
'BUL'
or'12011'
. Note that if numbers are used, theyshould be between 1-26 to match historical key sheet data. None
means all ring settings are 0.
The
plugboard_settings
parameter can accept either:- A string of space separated letter pairs; e.g.
'POMLIUKJNHYTGBVFREDC'
. - A string of slash separated number pairs; e.g.
'18/2617/421/63/1619/1422/78/112/255/910/15'
. - A value of
None
means no plugboard connections are made.
from_key_file
(fp[, day=None])¶Convenience function to build an EnigmaMachine by reading key parametersfrom a file.
Parameters: |
|
---|
For more information on the file format, see Key File Format.
set_display
(val)¶Sets the simulated rotor operator windows to val. This establishes a newstarting position for a subsequent encrypt or decrypt operation. See also
get_display()
.Parameters: | val – Must be a string or iterable containing uppercase letter values, onefor each window from left to right. For example, a valid value for a 3 rotormachine would be 'ABC' . |
---|
get_display
(val)¶This method returns the current position of the rotors as a string. Seealso
set_display()
.Returns: | a string of uppercase letters, one for each rotor (left toright) |
---|---|
Return type: | string |
get_rotor_count
()¶Returns a list of integers that represent the rotation counts for eachrotor. The rotation counts are reset to 0 every time
set_display()
is called.key_press
(key)¶Simulate a front panel key press. First the rotors are stepped bysimulating the mechanical action of the machine. Next a simulated currentis run through the machine. The lamp that is lit by this key press isreturned as a string (a single uppercase letter A-Z).
Parameters: | key (string) – the letter pressed (A-Z) |
---|---|
Returns: | the lamp that is lit (A-Z) |
Return type: | string |
process_text
(text[, replace_char='X'])¶This is a convenience function for processing a string of text. For eachcharacter in the input text,
key_press()
is called. The output textis returned as a string.This function performs some pre-processing of the input text, unlike
key_press()
. First, all input is converted to uppercase. Secondly,the parameter replace_char
controls what is done to input charactersthat are not A-Z
. If the input text contains a character not on thekeyboard, it is replaced with replace_char
. If replace_char
isNone
the character is dropped from the input. replace_char
defaults to X
.Parameters: |
|
---|
EnigmaMachine exceptions¶
EnigmaMachine
operations may raiseenigma.machine.EnigmaError
under error conditions. The two classmethod
constructors, from_key_sheet
and from_key_file
assemblean EnigmaMachine
from parts, and thoseparts may raise these exceptions themselves:rotor.rotors.RotorError
plugboard.PlugboardError
Rotors & Reflectors¶
The
Rotor
class represents the Enigma rotors, also known as the wheels orWalzen in German. They are the most important parts of the machine.Rotors have little use on their own. They are placed inside an
EnigmaMachine
object, which then calls the public Rotor
methods.Rotor class reference¶
enigma.rotors.rotor.
Rotor
(model_name, wiring[, ring_setting=0[, stepping=None]])¶A rotor has 26 circularly arranged pins on the right (entry) side and 26contacts on the left side. Each pin is connected to a single contact byinternal wiring, thus establishing a substitution cipher. We represent thiswiring by establishing a mapping from a pin to a contact (and vice versa forthe return path). Internally we number the pins and contacts from 0-25 in aclockwise manner with 0 being the “top”.
An alphabetic or numeric ring is fastened to the rotor by the operator. Thelabels of this ring are displayed to the operator through a small window onthe top panel. The ring can be fixed to the rotor in one of 26 differentpositions; this is called the ring setting (Ringstellung). We will numberthe ring settings from 0-25 where 0 means no offset (e.g. the letter “A” ismapped to pin 0 on an alphabetic ring). A ring setting of 1 means the letter“B” is mapped to pin 0.
Each rotor can be in one of 26 positions on the spindle, with position 0where pin/contact 0 is being indicated in the operator window. The rotorrotates towards the operator by mechanical means during normal operation askeys are being pressed during data entry. Position 1 is thus defined to beone step from position 0. Likewise, position 25 is the last position beforeanother step returns it to position 0, completing 1 trip around the spindle.
Finally, a rotor has a “stepping” or “turnover” parameter. Physically thisis implemented by putting a notch on the alphabet ring and it controls whenthe rotor will “kick” the rotor to its left, causing the neighbor rotor torotate. Photiosity 1 7 0 – sharpen blurred and shaky photos. Most rotors had one notch, but some Kriegsmarine rotors had 2notches and thus rotated twice as fast.
Note that we allow the
stepping
parameter to be None
. This indicatesthe rotor does not rotate. This allows us to model the entry wheel andreflectors as stationary rotors. The fourth rotor on the Kriegsmarine M4models (Beta or Gamma) did not rotate.The rotor constructor establishes the rotor characteristics.
Parameters: |
|
---|---|
Raises: | RotorError – when an invalid parameter is supplied |
Note that for purposes of simulation, our rotors will always use alphabeticlabels A-Z. Smart player 1 0 2. In reality, the Heer & Luftwaffe devices used numbers 01-26, andKriegsmarine devices used A-Z. Our usage of A-Z is simply for simulationconvenience. In the future we may allow either display.
set_display
(val)¶Spin the rotor such that the string
val
appears in the operatorwindow. This sets the internal position of the rotor on the axle and thusrotates the pins and contacts accordingly.A value of ‘A’ for example puts the rotor in position 0, assuming aninternal ring setting of 0.
Parameters: | val (string) – rotor position which must be in the range A-Z |
---|---|
Raises: | RotorError – when an invalid position value is supplied |
get_display
()¶Returns: | current rotor position in the range A-Z |
---|---|
Return type: | string |
signal_in
(n)¶Simulate a signal entering the rotor from the right at a given pinposition n.
Parameters: | n (integer) – pin number between 0 and 25 |
---|---|
Returns: | the contact number of the output signal (0-25) |
Return type: | integer |
signal_out
(n)¶Simulate a signal entering the rotor from the left at a given contactposition n.
Parameters: | n (integer) – contact number between 0 and 25 |
---|---|
Returns: | the pin number of the output signal (0-25) |
Return type: | integer |
notch_over_pawl
()¶Returns
True
if this rotor has a notch in the stepping position andFalse
otherwise.Return type: | Boolean |
---|
rotate
()¶![Enigma Python Enigma Python](https://miro.medium.com/max/1200/1*jKqW7a6yTLWAFbqAL71Pxw.png)
Rotates the rotor forward.
A note on the entry wheel and reflectors¶
The entry wheel (ETW) is a special non-movable rotor that sits on the farright of the rotor array. It connects the rotor array with the plugboard wiring.On Wehrmacht Enigmas, the entry wheel performs a straight-through mapping. Inother words, the wire from the ‘A’ key is passed to pin position 0, ‘B’ to pinposition 1, etc. Thus there is no need to simulate the entry wheel given ourcurrent scope to model only military Enigmas.
The reflector, or Umkehrwalze (UKW), sits at the far left of the rotor array.It simply reflects the incoming signal coming from the right back through theleft side of the rotors. We can thus model the reflector as a special non-movablerotor.
If you decide to create your own reflector, and you desire to maintainreciprocal encryption & decryption, your connections must be made in pairs. Thusif you wire ‘A’ to ‘G’, you must also wire ‘G’ to ‘A’, and so on.
Rotor & reflector factory functions¶
While it is possible to create your own rotor type, for convenience two factoryfunctions have been created to return rotors and reflectors used by theWehrmacht. These factory functions let you refer to the rotors and reflectors byname instead of providing their internal wiring every time you need one (whichwould be both tedious and error prone).
The following table lists the names of the rotors we currently simulate.
Rotor names | Enigma Models |
---|---|
I, II, III, IV, V | All Wehrmacht models |
VI, VII, VIII | Kriegsmarine M3 & M4 |
Beta, Gamma | Kriegsmarine M4(with thin reflectors) |
Any of the names in the first column of the above table can be used by thefactory function
enigma.rotors.factory.create_rotor()
, described below.Likewise there exists a factory function to create reflectors by name. Thefollowing table lists the names of the supported reflectors.
Reflector names | Enigma Models |
---|---|
B, C | All Wehrmacht models |
B-Thin, C-Thin | Kriegsmarine M4(with Beta & Gammarotors) |
The two factory functions are described next:
enigma.rotors.factory.
create_rotor
(model[, ring_setting=0])¶Create and return a
Rotor
object withthe given ring setting.Parameters: |
|
---|---|
Returns: | the newly created Rotor |
Raises: | RotorError – when an unknown model name is provided |
enigma.rotors.factory.
create_reflector
(model)¶Create and return a
Rotor
object thatis meant to be used in the reflector role.Parameters: | model (string) – the model name to create; see the Simulated reflector types table |
---|---|
Returns: | the newly created reflector, which is actually of typeRotor |
Raises: | RotorError – when an unknown model name is provided |
Rotor exceptions¶
Rotor
objects may raiseenigma.rotors.RotorError
when an invalid constructor argument is given, orif the rotor object is given an invalid parameter during a set_display
operation.Plugboards¶
The plugboard, or Steckerbrett in German, allows the operator to swap up to 10keys and indicator lamps for increased key strength.
Plugboards have little use on their own. They are placed inside an
EnigmaMachine
object, which then calls the public Plugboard
methods.Plugboard class reference¶
enigma.plugboard.
Plugboard
([wiring_pairs=None])¶The plugboard allows the operator to swap letters before and after the entrywheel. This is accomplished by connecting cables between pairs of plugs thatare marked with letters (Heer & Luftwaffe models) or numbers (Kriegsmarine).Ten cables were issued with each machine; thus up to 10 of these swappingscould be used as part of a machine setup.
Each cable swaps both the input and output signals. Thus if A is connectedto B, A crosses to B in the keyboard to entry wheel direction and also inthe reverse entry wheel to lamp direction.
The constructor configures the plugboard according to a list or tuple ofinteger pairs, or None.
Parameters: | wiring_pairs – A value of None or an empty list/tuple indicates noplugboard connections are to be used (i.e. a straight mapping). Otherwisewiring_pairs must be an iterable of integer pairs, where each integeris between 0-25, inclusive. At most 10 such pairs can be specified. Eachvalue represents an input/output path through the plugboard. It is invalidto specify the same path more than once in the list. |
---|---|
Raises: | PlugboardError – If an invalid wiring_pairs parameter is given. |
from_key_sheet
([settings=None])¶This is a convenience function to build a plugboard according to asettings string as you may find on a key sheet.
Two syntaxes are supported, the Heer/Luftwaffe and Kriegsmarine styles:
In the Heer syntax, the settings are given as a string ofalphabetic pairs. For example:
'POMLIUKJNHYTGBVFREDC'
.In the Kriegsmarine syntax, the settings are given as a string of numberpairs, separated by a ‘/’. Note that the numbering uses 1-26, inclusive.For example:
'18/2617/421/63/1619/1422/78/112/255/910/15'
.To specify no plugboard connections, settings can be
None
or an emptystring.Parameters: | settings – A settings string as described above, or None . |
---|---|
Raises: | PlugboardError – If the settings string is invalid, or ifit contains more than 10 pairs. Each plug should be present atmost once in the settings string. |
Enigma Python Script
signal
(n)¶Simulate a signal entering the plugboard on wire n, where n must bean integer between 0 and 25.
Parameters: | n (integer) – The wire number the input signal is on (0-25). |
---|---|
Returns: | The wire number of the output signal (0-25). |
Return type: | integer |
Note that since the plugboard always crosses pairs of wires, it doesn’tmatter what direction (keyboard -> entry wheel or vice versa) the signalis coming from.
Plugboard exceptions¶
Plugboard
objects may raiseenigma.plugboard.PlugboardError
when an invalid constructor argument is given.This module implements a rotor-based encryption algorithm, contributed byLance Ellinghouse. The design is derivedfrom the Enigma device, a machineused during World War II to encipher messages. A rotor is simply apermutation. For example, if the character `A' is the origin of the rotor,then a given rotor might map `A' to `L', `B' to `Z', `C' to `G', and so on.To encrypt, we choose several different rotors, and set the origins of therotors to known positions; their initial position is the ciphering key. Toencipher a character, we permute the original character by the first rotor,and then apply the second rotor's permutation to the result. We continueuntil we've applied all the rotors; the resulting character is ourciphertext. We then change the origin of the final rotor by one position,from `A' to `B'; if the final rotor has made a complete revolution, then werotate the next-to-last rotor by one position, and apply the same procedurerecursively. In other words, after enciphering one character, we advancethe rotors in the same fashion as a car's odometer. Decoding works in thesame way, except we reverse the permutations and apply them in the oppositeorder.
The available functions in this module are:
- newrotor (key[, numrotors])
- Return a rotor object. key is a string containing the encryption keyfor the object; it can contain arbitrary binary data. The key will be usedto randomly generate the rotor permutations and their initial positions.numrotors is the number of rotor permutations in the returned object;if it is omitted, a default value of 6 will be used.
Rotor objects have the following methods:
- setkey (key)
- Sets the rotor's key to key.
- encrypt (plaintext)
- Reset the rotor object to its initial state and encrypt plaintext,returning a string containing the ciphertext. The ciphertext is always thesame length as the original plaintext.
- encryptmore (plaintext)
- Encrypt plaintext without resetting the rotor object, and return astring containing the ciphertext.
- decrypt (ciphertext)
- Reset the rotor object to its initial state and decrypt ciphertext,returning a string containing the ciphertext. The plaintext string willalways be the same length as the ciphertext.
- decryptmore (ciphertext)
- Decrypt ciphertext without resetting the rotor object, and return astring containing the ciphertext.
Enigma Python Library
An example usage:
The module's code is not an exact simulation of the original Enigmadevice; it implements the rotor encryption scheme differently from theoriginal. The most important difference is that in the originalEnigma, there were only 5 or 6 different rotors in existence, and theywere applied twice to each character; the cipher key was the order inwhich they were placed in the machine. The Python rotormodule uses the supplied key to initialize a random number generator;the rotor permutations and their initial positions are then randomlygenerated. The original device only enciphered the letters of thealphabet, while this module can handle any 8-bit binary data; it alsoproduces binary output. This module can also operate with anarbitrary number of rotors.
The original Enigma cipher was broken in 1944. The version implemented here is probably a good deal more difficult to crack(especially if you use many rotors), but it won't be impossible fora truly skillful and determined attacker to break the cipher. So if you wantto keep the NSA out of your files, this rotor cipher may well be unsafe, butfor discouraging casual snooping through your files, it will probably bejust fine, and may be somewhat safer than using the Unix cryptcommand.