Unlocking the Secrets of Cryptography: The Enigma Machine

Unlocking the Secrets of Cryptography: The Enigma Machine


🕵️♂️ Exploring the Enigma Machine Simulation in Python: Part 1

In this article, I'll walk you through the steps of creating a Python-based replica of the iconic Enigma machine, which the German military used to encrypt messages during WWII. Today, we'll look at the Enigma simulation's core components and beginning routines.

🔐 What is the Enigma Machine?

The Enigma Machine was an encryption technology used to secure military communications. Its ingenious design comprises multiple rotors, a plugboard, and a reflector, making it extremely difficult to breach. The Enigma's encryption relied heavily on its stepping mechanism, which ensured that each letter was encrypted uniquely each time, resulting in an allegedly unbreakable code.

We created a Python software to emulate the internal workings of this sophisticated device. Let us break it down step by step.


⚙️ Key Elements of the Enigma Simulation

Before we begin coding, let's have a look at the main components that run the Enigma machine emulation.

  1. Rotors & Reflectors: Each rotor has a unique wire configuration, and the reflector ensures that the encryption process is symmetric.
  2. Plugboard: The plugboard swaps letters in pairs, making the encryption more complicated and difficult to crack.
  3. Stepping Mechanism: : Like the original Enigma, each rotor advances once a letter is encrypted, using a double-step function to increase complexity.


🧑💻 Breaking Down the Code: Functions and Key Components

Now, let's break out the functions that replicate the Enigma machine. The code below provides critical components of the Enigma machine emulation in Python.


🌀 Rotors and Reflector Setup

First, let's specify various rotor configurations and the alphabet that will be used in the simulation:

import string

# Constants
ALPHABET = string.ascii_uppercase  # Alphabet letters A-Z
ALPHABET_SIZE = len(ALPHABET)  # Size of the alphabet (26)

# Rotor configurations (wiring and notch positions)
rotor_configurations = {
    "I": ("EKMFLGDQVZNTOWYHXUSPAIBRCJ", "Q"),  # Rotor I with a notch at Q
    "II": ("AJDKSIRUXBLHWTMCQGZNPYFVOE", "E"),  # Rotor II with a notch at E
    "III": ("BDFHJLCPRTXVZNYEIWGAKMUSQO", "V"),  # Rotor III with a notch at V
}
        

Explanation:

  • Rotor configurations define the wiring of each rotor (how one letter is substituted for another when passing through it). The notch positions indicate where the rotor should step after a full rotation.


🔄 Rotor Rotation Function

Second, let's create a function to rotate the rotor (or wheel). This function simulates the movement of the rotors in the Enigma machine.

# Function to rotate the wheel (the rotor)
def rotate_wheel(wheel, steps):
    return wheel[steps:] + wheel[:steps]
        

Explanation:

  • The function rotate_wheel simulates the rotor rotation by moving the letters based on the number of steps the rotor should advance. The steps correspond to how many positions the rotor should be moved.


🔌 Plugboard Functionality

The plugboard swaps pairs of letters before and after they pass through the rotors. We define functions to handle the swap.

# Function to perform the plugboard swap
def plugboard_swap(letter, pairs):
    return pairs.get(letter, letter)  # Swap letters if they're on the plugboard, otherwise return unchanged

# Function to parse plugboard pairs from a string (e.g., "AM BC DE")
def parse_plugboard_pairs(plugboard_string):
    """Parses plugboard pairs from a string like 'AM BC DE' into a dictionary."""
    pairs = {}
    plug_pairs = plugboard_string.split()
    for pair in plug_pairs:
        if len(pair) == 2:
            letter1, letter2 = pair[0], pair[1]
            pairs[letter1] = letter2
            pairs[letter2] = letter1
    return pairs
        

Explanation:

  • Plugboard swap: If a letter is on the plugboard, the letter is swapped with its pair; otherwise, it remains unchanged.
  • parse_plugboard_pairs: This function parses a string input (like "AM BC DE") and converts it into a dictionary that allows easy swapping of letters.


💻 Enigma Machine Class

Now, let’s define the EnigmaMachine class, which will simulate the full encryption and decryption process.

# Class for the Enigma Machine
class EnigmaMachine:
    def __init__(self, rotors, reflector, plugboard_pairs, ring_settings):
        self.set_rotors(rotors)
        self.set_reflector(reflector)
        self.set_plugboard_pairs(plugboard_pairs)
        self.set_ring_settings(ring_settings)
        self.rotor_positions = [0, 0, 0]  # Starting positions of the rotors
        

Explanation:

  • The EnigmaMachine class initializes the rotors, reflector, plugboard pairs, and ring settings (which define how the rotor is offset).


🏃♂️ Rotor Stepping Mechanism

Next, we add the stepping mechanism, which controls how the rotors move when a letter is encrypted. The double-step capability allows two rotors to operate at the same time under specified conditions.

double-step : the middle rotor rotate if the right rotor is at its notch or the middle rotor is at its notch

# Function to rotate the rotors according to the Enigma stepping mechanism
def step_rotors(self):
    """Rotates the rotors according to the Enigma stepping mechanism, including the double-step."""
    # Check for the double-step mechanism
    right_rotor_at_notch = index_to_letter(self.rotor_positions[0]) in rotor_configurations["I"][1]
    middle_rotor_at_notch = index_to_letter(self.rotor_positions[1]) in rotor_configurations["II"][1]

    # Always rotate the right rotor
    self.rotor_positions[0] = (self.rotor_positions[0] + 1) % ALPHABET_SIZE

    # Rotate the middle rotor if the right rotor is at its notch or the middle rotor is at its notch (double-step)
    if right_rotor_at_notch or middle_rotor_at_notch:
        self.rotor_positions[1] = (self.rotor_positions[1] + 1) % ALPHABET_SIZE

    # Rotate the left rotor only if the middle rotor has reached its notch
    if middle_rotor_at_notch:
        self.rotor_positions[2] = (self.rotor_positions[2] + 1) % ALPHABET_SIZE
        

Explanation:

  • This function checks if any rotor has reached its notch position. If so, it triggers the double-step mechanism to rotate the next rotor.


✉️ Encrypting a Message

Finally, we have a function for encrypting a message letter by letter.

# Function to encrypt a single letter
def encrypt_letter(self, letter):
    """Encrypts a single letter through the Enigma machine."""
    # Rotate the rotors before processing the letter
    self.step_rotors()

    # Swap via the plugboard
    letter = plugboard_swap(letter, self.plugboard_pairs)

    # Pass through the rotors (forward)
    for i in range(3):
        rotor_offset = (self.rotor_positions[i] - self.ring_settings[i] + ALPHABET_SIZE) % ALPHABET_SIZE
        letter_index = (letter_to_index(letter) + rotor_offset) % ALPHABET_SIZE
        letter = self.rotors[i][letter_index]
        letter = index_to_letter((letter_to_index(letter) - rotor_offset + ALPHABET_SIZE) % ALPHABET_SIZE)

    # Send letter through the reflector
    letter = self.reflector[letter_to_index(letter)]

    # Pass back through the rotors (backward)
    for i in range(2, -1, -1):
        rotor_offset = (self.rotor_positions[i] - self.ring_settings[i] + ALPHABET_SIZE) % ALPHABET_SIZE
        letter_index = (letter_to_index(letter) + rotor_offset) % ALPHABET_SIZE
        letter = index_to_letter(self.rotors[i].index(index_to_letter(letter_index)))
        letter = index_to_letter((letter_to_index(letter) - rotor_offset + ALPHABET_SIZE) % ALPHABET_SIZE)

    # Swap again via the plugboard
    letter = plugboard_swap(letter, self.plugboard_pairs)

    return letter
        

Stay tuned for the next post, where I’ll cover how to encrypt full messages, and how to implement historical Enigma configurations in our simulation.


🔍 Summary So Far:

We've covered the basic components and functions for simulating

the Enigma machine, including how to rotate the rotors, swap letters using the plugboard, and go through the encryption process. Next, we'll look at message encryption and how our simulation compares to historical data.

NEXT STEP : TESTING THE MASCHINE


#Python #EnigmaMachine #Cryptography #CodeSimulation #WWII #Encryption

To view or add a comment, sign in

More articles by Stephane Ulrich N.

Insights from the community

Others also viewed

Explore topics