Wikijunior:Raspberry Pi/Raspberry Pi Enigma Machine

From Wikibooks, open books for an open world
Jump to navigation Jump to search

Presentation[edit | edit source]

Bletchley Park

GCHQ and Raspberry Pi Foundation CC-BY-SA 4.0

Based on the Raspberry Pi OctoPi tutorial: https://projects.raspberrypi.org/en/projects/octapi-brute-force-enigma

What is the Enigma machine?[edit | edit source]

An Enigma machine is a device used for encrypting and decrypting messages. It was developed in the early 20th century and was used extensively by the Germans during World War II to encode their military communications.

The Enigma machine was famously broken by Alan Turing and his team at Bletchley Park, who developed techniques for cracking the Enigma code. This played a crucial role in the Allied victory in World War II, as it allowed them to intercept and decode important messages sent by the Germans.

How does the Engima machine work?[edit | edit source]

How does an Enigma machine work? on YouTube

The Enigma machine consists of:

  • a keyboard for typing in the message
  • a series of rotors that perform the encryption and decryption
  • a reflector that bounces the electrical current back through the rotors in the opposite direction

The rotors can be set in different positions, allowing for a large number of possible combinations and making it difficult for an attacker to decode the message.

Worksheet[edit | edit source]

Consulting your Enigma settings sheet, you find out that the settings for today are as follows:

rotorsring settingsplug board settingsrotor start
IV I V20 05 10SX KU QF UN JG TC LA WM OB ZFFNZ

Decrypt a message[edit | edit source]

What is the decrypted message?[edit | edit source]

Here is the secret message: GON XXLXYFQNZIK

  1. Open Python 3, then open the file called decrypt.py
  2. Type in the chosen rotors between the green quote marks '' next to chosen_rotors.
  3. Now type in the letters for the rotor start position between the green quote marks '' next to rotor_start.
  4. Type in the message key GON between the green quote marks '' next to message_key.
  5. Type in the plaintext which is the secret message XXLXYFQNZIK.
  6. Run the program by pressing the F5 key (say yes to saving).

Can you decrypt this message?[edit | edit source]

Use the same Enigma settings but don’t forget to change the message key: LJE OIVGWVHOVHKAU

Encrypt a message[edit | edit source]

  1. Open Python 3, then open the file called encrypt.py
  2. Type in the chosen rotors and the rotor start position again from the settings sheet
  3. Type in the message key BFR between the green quote marks ' ' next to message_key.
  4. Run the program and check it works – the resulting cipher text should be XXLXYFQNZIK for the plain text RASPBERRYPI.

Now it’s time to encrypt your own message!

  • Choose a different three letter message_key and type it in
  • Choose a different plaintext message and type it in. Make sure there are no spaces!
  • Run the program, then write down the encrypted key and the cipher text and give it to someone else to decrypt

Challenge[edit | edit source]

Decrypt this message: GED HYZFQOOVVBBKBWPDZLSL

Brute force attack[edit | edit source]

You need to know the Enigma settings to be able to decrypt the message!

Here are today's settings. Unfortunately, someone has spilt some ink on the rotor settings 😟

rotorsring settingsplug board settingsrotor start
21 15 16KL IT PQ MY XC NF VZ JB SH OGPOW

Crib text is where you know both the plain text and the cipher text.

Crib text: WEATHER
Cipher text: VZTLMPU

Can you decrypt this message using a brute force attack if you know the crib text and part of the settings?

VZTLMPUSLKTEXYWZWKXDOTT

Brute force attack[edit | edit source]

  1. Open Python 3, then open the file called bruteforce.py.
  2. Type in the crib text and the corresponding cipher text.
  3. Run the brute force attack to find the rotors and the message key.

Decrypt the message[edit | edit source]

  1. Now open the decrypt.py program you used before.
  2. Type in the rotor start setting, and this time you will need to type in the ring​ and ​plug board​ settings from the settings sheet as well.
  3. Type in the chosen rotors you found via the brute force attack.
  4. This time we already know the decrypted message key. Find this line of code: decrypted_message_key = machine.process_text(message_key).

Change it to say decrypted_message_key = '???' where ??? is the three-letter key you found in the brute force attack.

  • What is the secret message?

Final challenge[edit | edit source]

DHPCMHCQ PXE

18/05/18
ZOC EJDTLFHR BT UKW.

Setup[edit | edit source]

This tutorial uses the py-enigma module by Brian Neal to provide the Enigma machine functionality.

You can install a copy of py-enigma on your Raspberry Pi (or your computer) by running this command from the Terminal:

sudo pip3 install py-enigma

Further reading[edit | edit source]

The Wikijunior World War II book has a section on the Enigma machine which goes into a lot of detail on how it worked.

The best place to learn about the Enigma machine is by visiting Bletchley Park near Milton Keynes in the United Kingdom.

The Imitation Game (2014) is a film starring Benedict Cumberbatch as Alan Turing who cracks the Enigma machine. The film is age-rated 12 (PG-13 in the USA), so it's for older children and adults.

The Raspberry Pi Foundation recommends the biography Dilly — The Man Who Broke Enigmas (2010, ISBN 9781906447151) by Mavis Batey. The book is about Alfred Dillwyn Knox who was Britain's Chief Cryptographer during World War II.

Files[edit | edit source]

The original PDFs for this tutorial are available on Wikicommons:

Enigma-presentation.pdf[edit | edit source]

Enigma-worksheet.pdf[edit | edit source]

encrypt.py[edit | edit source]

from enigma.machine import EnigmaMachine

chosen_rotors = ''    # Type a space between each rotor e.g. V IV I
rotor_start = ''
message_key = ''
plaintext = 'RASPBERRYPI'   # The message you want to encrypt

print("You started with message key " + message_key + " and plaintext " + plaintext)

# Set up the Enigma machine
machine = EnigmaMachine.from_key_sheet(
   rotors=chosen_rotors,
   reflector='B',
   ring_settings='20 5 10',
   plugboard_settings='SX KU QP VN JG TC LA WM OB ZF')

# Set the initial position of the Enigma rotors
machine.set_display(rotor_start)

# Encrypt the message key (the three letters you chose)
encrypted_message_key = machine.process_text(message_key)
print("The encrypted message key is " + encrypted_message_key)

# Set the rotor start position to the UNENCRYPTED message key
machine.set_display(message_key)

# The result
ciphertext = machine.process_text(plaintext)

print("The cipher text is: " + ciphertext)

decrypt.py[edit | edit source]

from enigma.machine import EnigmaMachine

chosen_rotors = ''    # Type a space between each rotor e.g. V IV I
rotor_start = ''
message_key = ''
plaintext = ''   # The message you want to decrypt

print("You started with message key " + message_key + " and plaintext " + plaintext)

# Set up the Enigma machine
machine = EnigmaMachine.from_key_sheet(
   rotors=chosen_rotors,
   reflector='B',
   ring_settings='20 5 10',
   plugboard_settings='SX KU QP VN JG TC LA WM OB ZF')

# Set the initial position of the Enigma rotors
machine.set_display(rotor_start)

# Decrypt the message key
decrypted_message_key = machine.process_text(message_key)
print("The decrypted message key is " + decrypted_message_key)

# Set the rotor start position to the DECRYPTED message key
machine.set_display(decrypted_message_key)

# The result
ciphertext = machine.process_text(plaintext)

print("The cipher text is: " + ciphertext)

bruteforce.py[edit | edit source]

cribtext = ""
ciphertext = ""

# All possible combinations of rotors
rotors = [ "I II III", "I II IV", "I II V", "I III II",
"I III IV", "I III V", "I IV II", "I IV III",
"I IV V", "I V II", "I V III", "I V IV",
"II I III", "II I IV", "II I V", "II III I",
"II III IV", "II III V", "II IV I", "II IV III",
"II IV V", "II V I", "II V III", "II V IV",
"III I II", "III I IV", "III I V", "III II I",
"III II IV", "III II V", "III IV I", "III IV II",
"III IV V", "IV I II", "IV I III", "IV I V",
"IV II I", "IV II III", "IV I V", "IV II I",
"IV II III", "IV II V", "IV III I", "IV III II",
"IV III V", "IV V I", "IV V II", "IV V III",
"V I II", "V I III", "V I IV", "V II I",
"V II III", "V II IV", "V III I", "V III II",
"V III IV", "V IV I", "V IV II", "V IV III" ]

def find_rotor_start( rotor_choice, ciphertext, cribtext ):

    from enigma.machine import EnigmaMachine

    alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

    machine = EnigmaMachine.from_key_sheet(
       rotors=rotor_choice,
       reflector='B',
       ring_settings='21 15 16',					
       plugboard_settings='KL IT PQ MY XC NF VZ JB SH OG')	


    # Search over all possible rotor starting positions
    for i in range(len(alphabet)):            # search for rotor 1 start position
        for j in range(len(alphabet)):        # search for rotor 2 start position
            for k in range(len(alphabet)):    # search for rotor 3 start position

                # Generate a possible rotor start position
                start_pos = alphabet[i] + alphabet[j] + alphabet[k]

                # Set machine initial starting position and attempt to decrypt
                machine.set_display(start_pos)
                plaintext = machine.process_text(ciphertext)

                #print("Plain: " + plaintext + ", Crib: " + cribtext)

                # Check if decrypted text is the same as the crib text
                if (plaintext == cribtext):
                    return( rotor_choice, start_pos )

    return( rotor_choice, "null" )



print("Brute force crypt attack on Enigma message " + ciphertext)
print("Crib text " + cribtext )

# Try all rotor settings 
for rotor_setting in rotors:
    print("Trying rotors " + rotor_setting)
    rotor_choice, start_pos = find_rotor_start( rotor_setting, ciphertext, cribtext )
    if (start_pos != "null"):
        print("Machine setting found!")
        print("Rotors: " + rotor_choice)
        print("Message key: " + start_pos)
        print("Using crib " + cribtext)
        exit(0)