SUBSIM Radio Room Forums



SUBSIM: The Web's #1 resource for all submarine & naval simulations since 1997

Go Back   SUBSIM Radio Room Forums > General > General Topics
Forget password? Reset here

Reply
 
Thread Tools Display Modes
Old 07-21-24, 05:59 PM   #1
Pilot_76
Chief
 
Join Date: Mar 2010
Location: São Paulo, Brazil
Posts: 321
Downloads: 462
Uploads: 0
Exclamation ENIGMA Machine and AI

I had the idea of having MS Copilot to play a role as Bdu and to send us "Bdu" messages from time to time, but with the added feature of it actually sending encrypted messages using Enigma machine's encryption.

After many attempts I have actually made it wrote a working code in Python. "Working" on its own because when using other Enigma's emulators in order to check the encryption, for some reason the settings don't match at all. Rotor order, rotor's settings and starting positions do not encrypt/decrypt correctly against other Enigma machine simulators. Again, it does work when you encrypt/decrypt using its own messages. I know there are many other Enigma machine's written in Python, but I wanted to see MS Copilot to write one by itself.

So I am leaving the code here to see if any expert Python programmer can figure out why this code does not work when using other Enigma Machine simulators.
The code starts below this line:


import random

class Rotor:
def __init__(self, mappings, notch, ring_setting=0):
self.mappings = mappings
self.notch = notch
self.ring_setting = ring_setting
self.position = 0

def encode_forward(self, char):
index = (ord(char) - ord('A') + self.position - self.ring_setting) % 26
return chr((ord(self.mappings[index]) - ord('A') - self.position + self.ring_setting) % 26 + ord('A'))

def encode_backward(self, char):
index = (self.mappings.index(chr((ord(char) - ord('A') + self.position - self.ring_setting) % 26 + ord('A'))) - self.position + self.ring_setting) % 26
return chr(index + ord('A'))

def rotate(self):
self.position = (self.position + 1) % 26
return self.position == self.notch

def set_position(self, position):
self.position = position

class Reflector:
def __init__(self, mappings, name):
self.mappings = mappings
self.name = name

def reflect(self, char):
return self.mappings[ord(char) - ord('A')]

class Plugboard:
def __init__(self, connections):
self.connections = connections

def swap(self, char):
return self.connections.get(char, char)

class EnigmaMachine:
def __init__(self, rotors, reflector, plugboard):
self.rotors = rotors
self.reflector = reflector
self.plugboard = plugboard
self.initial_positions = [rotor.position for rotor in rotors]

def encode(self, message):
encoded_message = ''
for char in message:
if char.isalpha():
char = char.upper()
char = self.plugboard.swap(char)
for rotor in self.rotors:
char = rotor.encode_forward(char)
char = self.reflector.reflect(char)
for rotor in reversed(self.rotors):
char = rotor.encode_backward(char)
char = self.plugboard.swap(char)
encoded_message += char
for rotor in self.rotors:
if not rotor.rotate():
break
else:
encoded_message += char
return encoded_message

def reset_rotors(self):
for rotor, position in zip(self.rotors, self.initial_positions):
rotor.set_position(position)

def get_rotor_by_number(number, rotors):
return rotors[number - 1]

def get_random_position():
return random.randint(0, 25)

def get_random_plugboard():
letters = list("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
random.shuffle(letters)
connections = {}
for i in range(0, len(letters), 2):
connections[letters[i]] = letters[i+1]
connections[letters[i+1]] = letters[i]
return Plugboard(connections)

def get_specific_plugboard():
connections = {}
while True:
pair = input("Enter plugboard pair (e.g., AB) or press Enter to finish: ").strip().upper()
if not pair:
break
if len(pair) == 2 and pair[0] != pair[1]:
connections[pair[0]] = pair[1]
connections[pair[1]] = pair[0]
else:
print("Invalid pair. Please enter two different letters.")
return Plugboard(connections)

def format_output(message, group_size):
return ' '.join([message[i:i+group_size] for i in range(0, len(message), group_size)])

def display_configuration(rotors, reflector, plugboard):
roman_numerals = ["I", "II", "III", "IV", "V", "VI", "VII", "VIII", "Beta", "Gamma"]
rotor_order = '-'.join([roman_numerals[rotors.index(rotor)] for rotor in rotors])
rotor_settings = '-'.join([f"{rotor.ring_setting + 1}" for rotor in rotors])
rotor_positions = '-'.join([chr(rotor.position + ord('A')) for rotor in rotors])
plugboard_info = ', '.join([f"{k}{v}" for k, v in plugboard.connections.items() if k < v])
config = [
f"Rotors Order: {rotor_order}",
f"Rotors Settings: {rotor_settings}",
f"Rotors Starting Positions: {rotor_positions}",
f"Reflector: {reflector.name}",
f"Plugboards: {plugboard_info if plugboard_info else 'None'}"
]
print("\nCurrent Enigma Configuration:")
print("\n".join(config))

def main():
rotors_m3 = [
Rotor("EKMFLGDQVZNTOWYHXUSPAIBRCJ", 16), # Rotor I
Rotor("AJDKSIRUXBLHWTMCQGZNPYFVOE", 4), # Rotor II
Rotor("BDFHJLCPRTXVZNYEIWGAKMUSQO", 21), # Rotor III
Rotor("ESOVPZJAYQUIRHXLNFTGKDCMWB", 9), # Rotor IV
Rotor("VZBRGITYUPSDNHLXAWMJQOFECK", 25), # Rotor V
Rotor("JPGVOUMFYQBENHZRDKASXLICTW", 12), # Rotor VI
Rotor("NZJHGRCXMYSWBOUFAIVLPEKQDT", 12), # Rotor VII
Rotor("FKQHTLXOCBJSPDZRAMEWNIUYGV", 12) # Rotor VIII
]

rotors_m4 = rotors_m3 + [
Rotor("LEYJVCNIXWPBQMDRTAKZGFUHOS", 0), # Rotor Beta
Rotor("FSOKANUERHMBTIYCWLQPZXVGJD", 0) # Rotor Gamma
]

reflector_b = Reflector("YRUHQSLDPXNGOKMIEBFZCWVJAT", "B")
reflector_c = Reflector("FVPJIAOYEDRZXWGCTKUQSBNMHL", "C")

while True:
machine_type = input("Select Enigma Machine Type (1 for M3, 2 for M4): ").strip()
if machine_type == "1":
num_rotors = 3
rotors = rotors_m3
elif machine_type == "2":
num_rotors = 4
rotors = rotors_m4
else:
print("Invalid machine type selected.")
continue

config_choice = input("Select Configuration (1 for Random, 2 for Specific): ").strip()
selected_rotors = []
if config_choice == "1":
selected_rotors = random.sample(rotors, num_rotors)
for rotor in selected_rotors:
rotor.position = get_random_position()
rotor.ring_setting = get_random_position()
reflector = random.choice([reflector_b, reflector_c])
plugboard = get_random_plugboard()
elif config_choice == "2":
for i in range(num_rotors):
rotor_number = int(input(f"Select Rotor {i+1} (1-8 for M3, 1-10 for M4): "))
rotor = get_rotor_by_number(rotor_number, rotors)
start_position = input(f"Enter starting position for Rotor {i+1} (A-Z): ").strip().upper()
rotor.position = ord(start_position) - ord('A')
ring_setting = int(input(f"Enter ring setting for Rotor {i+1} (1-26): ")) - 1
rotor.ring_setting = ring_setting
selected_rotors.append(rotor)
reflector_choice = input("Select Reflector (B/C): ").strip().upper()
if reflector_choice == "B":
reflector = reflector_b
elif reflector_choice == "C":
reflector = reflector_c
else:
print("Invalid reflector selected.")
continue
plugboard = get_specific_plugboard()
else:
print("Invalid configuration selected.")
continue

display_configuration(selected_rotors, reflector, plugboard)

group_size = int(input("Enter group size for output (4 or 5): "))
if group_size not in [4, 5]:
print("Invalid group size selected.")
continue

enigma = EnigmaMachine(selected_rotors, reflector, plugboard)

while True:
print("\nChoose an action:")
print("1. Encode")
print("2. Decode")
print("3. Change Machine")
print("4. Change Configuration")
action = input("Enter the number of your choice: ").strip()
if action == "1" or action == "2":
message = input("Enter message to encode/decode: ")
enigma.reset_rotors() # Reset rotors to initial positions before encoding/decoding
encoded_message = enigma.encode(message)
formatted_message = format_output(encoded_message, group_size)
print(f"Encoded/Decoded Message: {formatted_message}")
elif action == "3":
break
elif action == "4":
break
else:
print("Invalid action selected.")
if action == "3" or action == "4":
continue

if __name__ == "__main__":
main()
Pilot_76 is offline   Reply With Quote
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -5. The time now is 05:33 PM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Copyright © 1995- 2024 Subsim®
"Subsim" is a registered trademark, all rights reserved.