![]() |
SUBSIM: The Web's #1 resource for all submarine & naval simulations since 1997 |
![]() |
#1 |
Chief
![]() Join Date: Mar 2010
Location: São Paulo, Brazil
Posts: 321
Downloads: 462
Uploads: 0
|
![]()
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() |
![]() |
![]() |
|
|