enigmapython 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- enigmapython-0.1.0/PKG-INFO +4 -0
- enigmapython-0.1.0/enigmapython/Enigma.py +86 -0
- enigmapython-0.1.0/enigmapython/EnigmaI.py +8 -0
- enigmapython-0.1.0/enigmapython/EnigmaINorway.py +8 -0
- enigmapython-0.1.0/enigmapython/EnigmaINorwayRotorI.py +11 -0
- enigmapython-0.1.0/enigmapython/EnigmaINorwayRotorII.py +11 -0
- enigmapython-0.1.0/enigmapython/EnigmaINorwayRotorIII.py +12 -0
- enigmapython-0.1.0/enigmapython/EnigmaINorwayRotorIV.py +12 -0
- enigmapython-0.1.0/enigmapython/EnigmaINorwayRotorV.py +12 -0
- enigmapython-0.1.0/enigmapython/EnigmaIRotorI.py +11 -0
- enigmapython-0.1.0/enigmapython/EnigmaIRotorII.py +11 -0
- enigmapython-0.1.0/enigmapython/EnigmaIRotorIII.py +11 -0
- enigmapython-0.1.0/enigmapython/EnigmaIRotorIV.py +12 -0
- enigmapython-0.1.0/enigmapython/EnigmaIRotorV.py +12 -0
- enigmapython-0.1.0/enigmapython/EnigmaISonder.py +8 -0
- enigmapython-0.1.0/enigmapython/EnigmaISonderRotorI.py +11 -0
- enigmapython-0.1.0/enigmapython/EnigmaISonderRotorII.py +12 -0
- enigmapython-0.1.0/enigmapython/EnigmaISonderRotorIII.py +12 -0
- enigmapython-0.1.0/enigmapython/EnigmaM3.py +8 -0
- enigmapython-0.1.0/enigmapython/EnigmaM3RotorI.py +10 -0
- enigmapython-0.1.0/enigmapython/EnigmaM3RotorII.py +10 -0
- enigmapython-0.1.0/enigmapython/EnigmaM3RotorIII.py +10 -0
- enigmapython-0.1.0/enigmapython/EnigmaM3RotorIV.py +10 -0
- enigmapython-0.1.0/enigmapython/EnigmaM3RotorV.py +10 -0
- enigmapython-0.1.0/enigmapython/EnigmaM3RotorVI.py +12 -0
- enigmapython-0.1.0/enigmapython/EnigmaM3RotorVII.py +12 -0
- enigmapython-0.1.0/enigmapython/EnigmaM3RotorVIII.py +12 -0
- enigmapython-0.1.0/enigmapython/EnigmaM4.py +8 -0
- enigmapython-0.1.0/enigmapython/EnigmaM4RotorBeta.py +12 -0
- enigmapython-0.1.0/enigmapython/EnigmaM4RotorGamma.py +12 -0
- enigmapython-0.1.0/enigmapython/EnigmaM4RotorI.py +10 -0
- enigmapython-0.1.0/enigmapython/EnigmaM4RotorII.py +10 -0
- enigmapython-0.1.0/enigmapython/EnigmaM4RotorIII.py +10 -0
- enigmapython-0.1.0/enigmapython/EnigmaM4RotorIV.py +9 -0
- enigmapython-0.1.0/enigmapython/EnigmaM4RotorV.py +9 -0
- enigmapython-0.1.0/enigmapython/EnigmaM4RotorVI.py +9 -0
- enigmapython-0.1.0/enigmapython/EnigmaM4RotorVII.py +9 -0
- enigmapython-0.1.0/enigmapython/EnigmaM4RotorVIII.py +10 -0
- enigmapython-0.1.0/enigmapython/Etw.py +14 -0
- enigmapython-0.1.0/enigmapython/EtwPassthrough.py +7 -0
- enigmapython-0.1.0/enigmapython/Observable.py +18 -0
- enigmapython-0.1.0/enigmapython/Observer.py +3 -0
- enigmapython-0.1.0/enigmapython/Plugboard.py +15 -0
- enigmapython-0.1.0/enigmapython/PlugboardPassthrough.py +7 -0
- enigmapython-0.1.0/enigmapython/Reflector.py +4 -0
- enigmapython-0.1.0/enigmapython/ReflectorNorwayUKW.py +9 -0
- enigmapython-0.1.0/enigmapython/ReflectorSonderUKW.py +9 -0
- enigmapython-0.1.0/enigmapython/ReflectorUKWA.py +9 -0
- enigmapython-0.1.0/enigmapython/ReflectorUKWB.py +9 -0
- enigmapython-0.1.0/enigmapython/ReflectorUKWBThin.py +9 -0
- enigmapython-0.1.0/enigmapython/ReflectorUKWC.py +10 -0
- enigmapython-0.1.0/enigmapython/ReflectorUKWCThin.py +10 -0
- enigmapython-0.1.0/enigmapython/Rotor.py +93 -0
- enigmapython-0.1.0/enigmapython/SwappablePlugboard.py +19 -0
- enigmapython-0.1.0/enigmapython/Utils.py +31 -0
- enigmapython-0.1.0/enigmapython/__init__.py +58 -0
- enigmapython-0.1.0/enigmapython.egg-info/PKG-INFO +4 -0
- enigmapython-0.1.0/enigmapython.egg-info/SOURCES.txt +60 -0
- enigmapython-0.1.0/enigmapython.egg-info/dependency_links.txt +1 -0
- enigmapython-0.1.0/enigmapython.egg-info/top_level.txt +1 -0
- enigmapython-0.1.0/setup.cfg +4 -0
- enigmapython-0.1.0/setup.py +14 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
from .Observer import Observer
|
|
2
|
+
from string import ascii_lowercase
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Enigma(Observer):
|
|
7
|
+
|
|
8
|
+
plugboard = None
|
|
9
|
+
rotors = None
|
|
10
|
+
reflector = None
|
|
11
|
+
etw = None
|
|
12
|
+
auto_increment_rotors = False
|
|
13
|
+
|
|
14
|
+
alphabet = list(ascii_lowercase)
|
|
15
|
+
|
|
16
|
+
def __init__(self, plugboard, rotors, reflector,etw,auto_increment_rotors=False):
|
|
17
|
+
self.plugboard = plugboard
|
|
18
|
+
self.rotors = rotors
|
|
19
|
+
self.reflector = reflector
|
|
20
|
+
self.etw = etw
|
|
21
|
+
self.auto_increment_rotors = auto_increment_rotors
|
|
22
|
+
if auto_increment_rotors == True:
|
|
23
|
+
for rotor in rotors:
|
|
24
|
+
rotor.add_observer(self)
|
|
25
|
+
|
|
26
|
+
def input_string(self,str):
|
|
27
|
+
output_string = ""
|
|
28
|
+
for char in str:
|
|
29
|
+
output_string += self.input_char(char)
|
|
30
|
+
return output_string
|
|
31
|
+
|
|
32
|
+
def input_char(self,char):
|
|
33
|
+
logging.info("Input char: {}".format(char))
|
|
34
|
+
## Triggering rotors extra rotation due to double step issue
|
|
35
|
+
for rotor in self.rotors:
|
|
36
|
+
## Rotor extra rotation should be done only if the rotor is not the last one in the list
|
|
37
|
+
if rotor.double_step_triggered == True and self.rotors.index(rotor) < len(self.rotors)-1:
|
|
38
|
+
rotor.increment_position()
|
|
39
|
+
rotor.double_step_triggered = False
|
|
40
|
+
if self.auto_increment_rotors == True:
|
|
41
|
+
self.rotors[0].increment_position()
|
|
42
|
+
scrambled_char = self.process_char(char)
|
|
43
|
+
return scrambled_char
|
|
44
|
+
|
|
45
|
+
def process_char(self, char):
|
|
46
|
+
scrambled_char = self.plugboard.switch_char(char)
|
|
47
|
+
logging.debug("Scrambled letter from plugboard: {}".format(scrambled_char))
|
|
48
|
+
iteration = 0
|
|
49
|
+
for rotor in self.rotors:
|
|
50
|
+
if iteration == 0:
|
|
51
|
+
scrambled_char = rotor.scramble_letter_index(rotor.wiring,Enigma.alphabet.index(scrambled_char))
|
|
52
|
+
else:
|
|
53
|
+
scrambled_char = rotor.scramble_letter_index(rotor.wiring,Enigma.alphabet.index(scrambled_char)-self.rotors[iteration-1].position)
|
|
54
|
+
iteration +=1
|
|
55
|
+
logging.debug("Scrambled letter from rotor{}: {}".format(str(iteration),scrambled_char))
|
|
56
|
+
scrambled_char = self.reflector.scramble_letter_index(self.reflector.wiring,(Enigma.alphabet.index(scrambled_char)-self.rotors[iteration-1].position))
|
|
57
|
+
logging.debug("Scrambled letter from reflector: {}".format(scrambled_char))
|
|
58
|
+
for rotor in reversed(self.rotors):
|
|
59
|
+
if iteration == len(self.rotors):
|
|
60
|
+
scrambled_char = rotor.scramble_letter_index(Enigma.alphabet,(rotor.wiring.index(Enigma.shift_letter(scrambled_char,rotor.position))-rotor.position))
|
|
61
|
+
else:
|
|
62
|
+
scrambled_char = rotor.scramble_letter_index(Enigma.alphabet,(rotor.wiring.index(Enigma.shift_letter(scrambled_char, (rotor.position - self.rotors[iteration].position))) - rotor.position))
|
|
63
|
+
iteration -=1
|
|
64
|
+
logging.debug("Scrambled letter from rotor{}: {}".format(str(iteration+1),scrambled_char))
|
|
65
|
+
scrambled_char = self.etw.switch_char(scrambled_char,-self.rotors[iteration].position)
|
|
66
|
+
logging.debug("Scrambled letter from ETW: {}".format(scrambled_char))
|
|
67
|
+
scrambled_char = self.plugboard.switch_char(scrambled_char)
|
|
68
|
+
logging.debug("Scrambled letter from plugboard: {}".format(scrambled_char))
|
|
69
|
+
logging.info("Scrambled letter to lamp: {}".format(scrambled_char))
|
|
70
|
+
return scrambled_char
|
|
71
|
+
|
|
72
|
+
def update(self, observable, *args, **kwargs):
|
|
73
|
+
# If there is rotor N+1, increment its position by 1
|
|
74
|
+
if observable in self.rotors and self.rotors.index(observable) < len(self.rotors)-1:
|
|
75
|
+
self.rotors[self.rotors.index(observable)+1].increment_position()
|
|
76
|
+
# Engaging the enigma double step issue, only if the next rotor position is in its notch indexe/s
|
|
77
|
+
if self.rotors[self.rotors.index(observable)+1].position in self.rotors[self.rotors.index(observable)+1].notch_indexes:
|
|
78
|
+
self.rotors[self.rotors.index(observable)+1].double_step_triggered = True
|
|
79
|
+
|
|
80
|
+
@staticmethod
|
|
81
|
+
def shift_letter(letter,shift):
|
|
82
|
+
return Enigma.alphabet[(Enigma.alphabet.index(letter)+shift) % len(Enigma.alphabet)]
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
from .Enigma import Enigma
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class EnigmaINorway(Enigma):
|
|
5
|
+
|
|
6
|
+
def __init__(self,plugboard,rotor1, rotor2, rotor3,reflector,etw,auto_increment_rotors=False):
|
|
7
|
+
rotors = [rotor1, rotor2, rotor3]
|
|
8
|
+
super().__init__(plugboard,rotors,reflector,etw,auto_increment_rotors)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from .Rotor import Rotor
|
|
2
|
+
|
|
3
|
+
class EnigmaINorwayRotorI(Rotor):
|
|
4
|
+
|
|
5
|
+
wiring = 'wtokasuyvrbxjhqcpzefmdinlg'
|
|
6
|
+
notch_indexes = [16]
|
|
7
|
+
tag = "IN_I"
|
|
8
|
+
|
|
9
|
+
def __init__(self, position = 0, ring = 0):
|
|
10
|
+
super().__init__(self.wiring, position, ring, self.notch_indexes)
|
|
11
|
+
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from .Rotor import Rotor
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class EnigmaINorwayRotorII(Rotor):
|
|
5
|
+
|
|
6
|
+
wiring = 'gjlpubswemctqvhxaofzdrkyni'
|
|
7
|
+
notch_indexes = [4]
|
|
8
|
+
tag = "IN_II"
|
|
9
|
+
|
|
10
|
+
def __init__(self, position = 0, ring = 0):
|
|
11
|
+
super().__init__(self.wiring, position, ring, self.notch_indexes)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from .Rotor import Rotor
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class EnigmaINorwayRotorIII(Rotor):
|
|
5
|
+
|
|
6
|
+
wiring = 'jwfmhnbpusdytixvzgrqlaoekc'
|
|
7
|
+
notch_indexes = [21]
|
|
8
|
+
tag = "IN_III"
|
|
9
|
+
|
|
10
|
+
def __init__(self, position = 0, ring = 0):
|
|
11
|
+
super().__init__(self.wiring, position, ring, self.notch_indexes)
|
|
12
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from .Rotor import Rotor
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class EnigmaINorwayRotorIV(Rotor):
|
|
5
|
+
|
|
6
|
+
wiring = 'fgzjmvxepbwshqtliudykcnrao'
|
|
7
|
+
notch_indexes = [21]
|
|
8
|
+
tag = "IN_IV"
|
|
9
|
+
|
|
10
|
+
def __init__(self, position = 0, ring = 0):
|
|
11
|
+
super().__init__(self.wiring, position, ring, self.notch_indexes)
|
|
12
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from .Rotor import Rotor
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class EnigmaINorwayRotorV(Rotor):
|
|
5
|
+
|
|
6
|
+
wiring = 'hejxqotzbvfdascilwpgynmurk'
|
|
7
|
+
notch_indexes = [25]
|
|
8
|
+
tag = "IN_V"
|
|
9
|
+
|
|
10
|
+
def __init__(self, position = 0, ring = 0):
|
|
11
|
+
super().__init__(self.wiring, position, ring, self.notch_indexes)
|
|
12
|
+
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from .Rotor import Rotor
|
|
2
|
+
|
|
3
|
+
class EnigmaIRotorIII(Rotor):
|
|
4
|
+
|
|
5
|
+
wiring = 'bdfhjlcprtxvznyeiwgakmusqo'
|
|
6
|
+
notch_indexes = [21]
|
|
7
|
+
tag = "I_III"
|
|
8
|
+
|
|
9
|
+
def __init__(self, position = 0, ring = 0):
|
|
10
|
+
super().__init__(self.wiring, position, ring, self.notch_indexes)
|
|
11
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from .Rotor import Rotor
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class EnigmaIRotorIV(Rotor):
|
|
5
|
+
|
|
6
|
+
wiring = 'esovpzjayquirhxlnftgkdcmwb'
|
|
7
|
+
notch_indexes = [9]
|
|
8
|
+
tag = "I_IV"
|
|
9
|
+
|
|
10
|
+
def __init__(self, position = 0, ring = 0):
|
|
11
|
+
super().__init__(self.wiring, position, ring, self.notch_indexes)
|
|
12
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from .Rotor import Rotor
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class EnigmaIRotorV(Rotor):
|
|
5
|
+
|
|
6
|
+
wiring = 'vzbrgityupsdnhlxawmjqofeck'
|
|
7
|
+
notch_indexes = [25]
|
|
8
|
+
tag = "I_V"
|
|
9
|
+
|
|
10
|
+
def __init__(self, position = 0, ring = 0):
|
|
11
|
+
super().__init__(self.wiring, position, ring, self.notch_indexes)
|
|
12
|
+
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
from .Enigma import Enigma
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class EnigmaISonder(Enigma):
|
|
5
|
+
|
|
6
|
+
def __init__(self,plugboard,rotor1, rotor2, rotor3,reflector,etw,auto_increment_rotors=False):
|
|
7
|
+
rotors = [rotor1, rotor2, rotor3]
|
|
8
|
+
super().__init__(plugboard,rotors,reflector,etw,auto_increment_rotors)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from .Rotor import Rotor
|
|
2
|
+
|
|
3
|
+
class EnigmaISonderRotorI(Rotor):
|
|
4
|
+
|
|
5
|
+
wiring = 'veosirzujdqckgwypnxaflthmb'
|
|
6
|
+
notch_indexes = [16]
|
|
7
|
+
tag = "IS_I"
|
|
8
|
+
|
|
9
|
+
def __init__(self, position = 0, ring = 0):
|
|
10
|
+
super().__init__(self.wiring, position, ring, self.notch_indexes)
|
|
11
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from .Rotor import Rotor
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class EnigmaISonderRotorII(Rotor):
|
|
5
|
+
|
|
6
|
+
#wiring = 'uemoatqlshpkcyfwjzbgvxindr'
|
|
7
|
+
wiring = 'uemoatqlshpkcyfwjzbgvxidnr'
|
|
8
|
+
notch_indexes = [4]
|
|
9
|
+
tag = "IS_II"
|
|
10
|
+
|
|
11
|
+
def __init__(self, position = 0, ring = 0):
|
|
12
|
+
super().__init__(self.wiring, position, ring, self.notch_indexes)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from .Rotor import Rotor
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class EnigmaISonderRotorIII(Rotor):
|
|
5
|
+
|
|
6
|
+
wiring = 'tzhxmbsipnurjfdkeqvcwglaoy'
|
|
7
|
+
notch_indexes = [21]
|
|
8
|
+
tag = "IS_III"
|
|
9
|
+
|
|
10
|
+
def __init__(self, position = 0, ring = 0):
|
|
11
|
+
super().__init__(self.wiring, position, ring, self.notch_indexes)
|
|
12
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from .Rotor import Rotor
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class EnigmaM3RotorVI(Rotor):
|
|
5
|
+
|
|
6
|
+
wiring = 'jpgvoumfyqbenhzrdkasxlictw'
|
|
7
|
+
notch_indexes = [12,25]
|
|
8
|
+
tag = "M3_VI"
|
|
9
|
+
|
|
10
|
+
def __init__(self, position = 0, ring = 0):
|
|
11
|
+
super().__init__(self.wiring, position, ring, self.notch_indexes)
|
|
12
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from .Rotor import Rotor
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class EnigmaM3RotorVII(Rotor):
|
|
5
|
+
|
|
6
|
+
wiring = 'nzjhgrcxmyswboufaivlpekqdt'
|
|
7
|
+
notch_indexes = [12,25]
|
|
8
|
+
tag = "M3_VII"
|
|
9
|
+
|
|
10
|
+
def __init__(self, position = 0, ring = 0):
|
|
11
|
+
super().__init__(self.wiring, position, ring, self.notch_indexes)
|
|
12
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from .Rotor import Rotor
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class EnigmaM3RotorVIII(Rotor):
|
|
5
|
+
|
|
6
|
+
wiring = 'fkqhtlxocbjspdzramewniuygv'
|
|
7
|
+
notch_indexes = [12,25]
|
|
8
|
+
tag = "M3_VIII"
|
|
9
|
+
|
|
10
|
+
def __init__(self, position = 0, ring = 0):
|
|
11
|
+
super().__init__(self.wiring, position, ring, self.notch_indexes)
|
|
12
|
+
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
from .Enigma import Enigma
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class EnigmaM4(Enigma):
|
|
5
|
+
|
|
6
|
+
def __init__(self, plugboard, rotor1, rotor2, rotor3, rotor4, reflector, etw, auto_increment_rotors=False):
|
|
7
|
+
rotors = [rotor1, rotor2, rotor3, rotor4]
|
|
8
|
+
super().__init__(plugboard,rotors,reflector,etw,auto_increment_rotors)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from .Rotor import Rotor
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class EnigmaM4RotorBeta(Rotor):
|
|
5
|
+
|
|
6
|
+
wiring = 'leyjvcnixwpbqmdrtakzgfuhos'
|
|
7
|
+
notch_indexes = []
|
|
8
|
+
tag = "M4_Beta"
|
|
9
|
+
|
|
10
|
+
def __init__(self, position = 0, ring = 0):
|
|
11
|
+
super().__init__(self.wiring, position, ring, self.notch_indexes)
|
|
12
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from .Rotor import Rotor
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class EnigmaM4RotorGamma(Rotor):
|
|
5
|
+
|
|
6
|
+
wiring = 'fsokanuerhmbtiycwlqpzxvgjd'
|
|
7
|
+
notch_indexes = []
|
|
8
|
+
tag = "M4_Gamma"
|
|
9
|
+
|
|
10
|
+
def __init__(self, position = 0, ring = 0):
|
|
11
|
+
super().__init__(self.wiring, position, ring, self.notch_indexes)
|
|
12
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
|
|
2
|
+
from string import ascii_lowercase
|
|
3
|
+
|
|
4
|
+
class Etw:
|
|
5
|
+
wiring = None
|
|
6
|
+
|
|
7
|
+
def switch_char(self,char,shift):
|
|
8
|
+
return self.wiring[self.wiring.index(char)+shift]
|
|
9
|
+
|
|
10
|
+
def __init__(self, wiring):
|
|
11
|
+
self.wiring = wiring
|
|
12
|
+
|
|
13
|
+
def __str__(self):
|
|
14
|
+
return self.wiring
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
class Observable:
|
|
2
|
+
|
|
3
|
+
observers = []
|
|
4
|
+
|
|
5
|
+
def __init__(self):
|
|
6
|
+
self.observers = []
|
|
7
|
+
|
|
8
|
+
def add_observer(self, observer):
|
|
9
|
+
if observer not in self.observers:
|
|
10
|
+
self.observers.append(observer)
|
|
11
|
+
|
|
12
|
+
def remove_observer(self, observer):
|
|
13
|
+
if observer in self.observers:
|
|
14
|
+
self.observers.remove(observer)
|
|
15
|
+
|
|
16
|
+
def notify_observers(self, *args, **kwargs):
|
|
17
|
+
for observer in self.observers:
|
|
18
|
+
observer.update(self, *args, **kwargs)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
from string import ascii_lowercase
|
|
3
|
+
|
|
4
|
+
class Plugboard:
|
|
5
|
+
wiring = None
|
|
6
|
+
|
|
7
|
+
def switch_char(self,char):
|
|
8
|
+
alphabet = list(ascii_lowercase)
|
|
9
|
+
return self.wiring[alphabet.index(char)]
|
|
10
|
+
|
|
11
|
+
def __init__(self, wiring):
|
|
12
|
+
self.wiring = wiring
|
|
13
|
+
|
|
14
|
+
def __str__(self):
|
|
15
|
+
return self.wiring
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
from .Observable import Observable
|
|
2
|
+
from .Utils import Utils
|
|
3
|
+
from string import ascii_lowercase
|
|
4
|
+
import logging
|
|
5
|
+
|
|
6
|
+
class Rotor(Observable):
|
|
7
|
+
original_wiring = None
|
|
8
|
+
wiring = None
|
|
9
|
+
position = None
|
|
10
|
+
rotations_counter = None
|
|
11
|
+
notch_indexes = None
|
|
12
|
+
double_step_triggered = None
|
|
13
|
+
ring = None
|
|
14
|
+
dot_position = None
|
|
15
|
+
lookup = {}
|
|
16
|
+
|
|
17
|
+
@staticmethod
|
|
18
|
+
def register(tag, class_name):
|
|
19
|
+
Rotor.lookup[tag] = class_name
|
|
20
|
+
|
|
21
|
+
def reset_position(self):
|
|
22
|
+
self.position = 0
|
|
23
|
+
|
|
24
|
+
def increment_position(self):
|
|
25
|
+
self.position = ((self.position + 1) % len(self.wiring))
|
|
26
|
+
self.rotations_counter = self.rotations_counter + 1
|
|
27
|
+
for notch_index in self.notch_indexes:
|
|
28
|
+
logging.debug("Evaluating notch_index {} against position {}".format(notch_index+1,self.position))
|
|
29
|
+
if (self.position == ((notch_index+1) % len(self.wiring))):
|
|
30
|
+
logging.debug("Found that rotor position {} is equals to notch {}, notifying observers".format(self.position, ((notch_index+1) % len(self.wiring))))
|
|
31
|
+
self.notify_observers(None,None)
|
|
32
|
+
|
|
33
|
+
def set_position(self,position):
|
|
34
|
+
self.position = position % len(self.wiring)
|
|
35
|
+
self.rotations_counter = 0
|
|
36
|
+
|
|
37
|
+
def scramble_letter_index(self, dictionary, letter_index):
|
|
38
|
+
scrambled_letter_index_from_rotor = dictionary.index(dictionary[(self.position + letter_index) % len(dictionary)])
|
|
39
|
+
return dictionary[scrambled_letter_index_from_rotor]
|
|
40
|
+
|
|
41
|
+
def __init__(self, wiring, position = 0, ring = 0, notch_indexes=[]):
|
|
42
|
+
self.wiring = wiring
|
|
43
|
+
self.position = position % len(wiring)
|
|
44
|
+
self.notch_indexes = notch_indexes
|
|
45
|
+
self.double_step_triggered = False
|
|
46
|
+
self.rotations_counter = 0
|
|
47
|
+
self.original_wiring = self.wiring
|
|
48
|
+
self.ring = ring
|
|
49
|
+
self.set_rotor_ring(ring)
|
|
50
|
+
|
|
51
|
+
def __str__(self):
|
|
52
|
+
pointer = ' ' * self.position + '^'
|
|
53
|
+
return self.wiring + '\n' + pointer
|
|
54
|
+
|
|
55
|
+
def __eq__(self, __value: object) -> bool:
|
|
56
|
+
return id(self) == id(object)
|
|
57
|
+
|
|
58
|
+
def set_rotor_ring(self, ring):
|
|
59
|
+
self.wiring = self.original_wiring
|
|
60
|
+
self.dot_position = list(self.wiring).index("a")
|
|
61
|
+
logging.debug("Dot position: " + str(self.dot_position))
|
|
62
|
+
alphabet = list(ascii_lowercase)
|
|
63
|
+
for i in range(0, ring):
|
|
64
|
+
# Set temporary wiring variable
|
|
65
|
+
temp_wiring = self.wiring
|
|
66
|
+
# Set actual wiring to empty string
|
|
67
|
+
wiring = ""
|
|
68
|
+
# Loop over chars in temporary wiring
|
|
69
|
+
for char in temp_wiring:
|
|
70
|
+
# Shift the char by one and add that shifted char to wiring variable
|
|
71
|
+
wiring += Rotor.shift(char, 1, alphabet)
|
|
72
|
+
# Add one to dot position, make sure we don't exceed the lenght of the alphabet
|
|
73
|
+
self.wiring = wiring
|
|
74
|
+
self.dot_position = (self.dot_position + 1) % len(alphabet)
|
|
75
|
+
logging.debug("Wiring shifted up the alphabet: " + wiring)
|
|
76
|
+
logging.debug("New dot position: " + str(self.dot_position))
|
|
77
|
+
i = 0
|
|
78
|
+
# While the letter at the dot position doesn't match with the ringstellung
|
|
79
|
+
while not self.wiring[self.dot_position] == alphabet[ring % len(self.wiring)]:
|
|
80
|
+
i += 1
|
|
81
|
+
# Rotate the wiring
|
|
82
|
+
self.wiring = self.wiring[-1:] + self.wiring[:-1]
|
|
83
|
+
logging.debug("Rotation " + str(i).zfill(2) + "; Wiring: " + self.wiring)
|
|
84
|
+
|
|
85
|
+
@staticmethod
|
|
86
|
+
def shift(letter, shift, alphabet):
|
|
87
|
+
for i in range(0, len(alphabet)):
|
|
88
|
+
if alphabet[i] == letter:
|
|
89
|
+
return alphabet[(i + shift) % len(alphabet)]
|
|
90
|
+
|
|
91
|
+
@staticmethod
|
|
92
|
+
def get_instance_from_tag(tag: str):
|
|
93
|
+
return Utils.get_class_instance(Rotor.lookup[tag].__module__+"."+Rotor.lookup[tag].__name__)()
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from .Plugboard import Plugboard
|
|
2
|
+
from .Utils import Utils
|
|
3
|
+
from .PlugboardPassthrough import PlugboardPassthrough
|
|
4
|
+
|
|
5
|
+
class SwappablePlugboard(PlugboardPassthrough):
|
|
6
|
+
|
|
7
|
+
def __init__(self, chars=None):
|
|
8
|
+
super().__init__()
|
|
9
|
+
self.bulk_swap(chars)
|
|
10
|
+
|
|
11
|
+
def bulk_swap(self,chars):
|
|
12
|
+
if chars != None and isinstance(chars, dict):
|
|
13
|
+
for key, value in chars.items():
|
|
14
|
+
self.swap(key,value)
|
|
15
|
+
|
|
16
|
+
def swap(self, c1, c2):
|
|
17
|
+
if c1 != None and self.wiring.__contains__(c1) and c2 != None and self.wiring.__contains__(c2):
|
|
18
|
+
self.wiring = Utils.swap_chars(self.wiring, c1, c2)
|
|
19
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from importlib import import_module
|
|
2
|
+
|
|
3
|
+
class Utils:
|
|
4
|
+
|
|
5
|
+
@staticmethod
|
|
6
|
+
def find_all_subclasses(cls):
|
|
7
|
+
return set(cls.__subclasses__()).union(
|
|
8
|
+
[s for c in cls.__subclasses__() for s in Utils.find_all_subclasses(c)])
|
|
9
|
+
|
|
10
|
+
@staticmethod
|
|
11
|
+
def get_class_instance(cls):
|
|
12
|
+
try:
|
|
13
|
+
module_path, class_name = cls.rsplit('.', 1)
|
|
14
|
+
module = import_module(module_path)
|
|
15
|
+
return getattr(module, class_name)
|
|
16
|
+
except (ImportError, AttributeError) as e:
|
|
17
|
+
raise ImportError(cls)
|
|
18
|
+
|
|
19
|
+
@staticmethod
|
|
20
|
+
def swap_chars(string, ch1, ch2):
|
|
21
|
+
if ch1 == ch2: return string
|
|
22
|
+
str_list = []
|
|
23
|
+
for char in string:
|
|
24
|
+
if char == ch1:
|
|
25
|
+
str_list.append(ch2)
|
|
26
|
+
elif char == ch2:
|
|
27
|
+
str_list.append(ch1)
|
|
28
|
+
else:
|
|
29
|
+
str_list.append(char)
|
|
30
|
+
return ''.join(str_list)
|
|
31
|
+
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
__all__ = [
|
|
2
|
+
'EnigmaIRotorI',
|
|
3
|
+
'EnigmaIRotorII',
|
|
4
|
+
'EnigmaIRotorIII',
|
|
5
|
+
'EnigmaIRotorIV',
|
|
6
|
+
'EnigmaIRotorV',
|
|
7
|
+
'EnigmaINorwayRotorI',
|
|
8
|
+
'EnigmaINorwayRotorII',
|
|
9
|
+
'EnigmaINorwayRotorIII',
|
|
10
|
+
'EnigmaINorwayRotorIV',
|
|
11
|
+
'EnigmaINorwayRotorV',
|
|
12
|
+
'EnigmaISonderRotorI',
|
|
13
|
+
'EnigmaISonderRotorII',
|
|
14
|
+
'EnigmaISonderRotorIII',
|
|
15
|
+
'EnigmaM3RotorI',
|
|
16
|
+
'EnigmaM3RotorII',
|
|
17
|
+
'EnigmaM3RotorIII',
|
|
18
|
+
'EnigmaM3RotorIV',
|
|
19
|
+
'EnigmaM3RotorV',
|
|
20
|
+
'EnigmaM3RotorVI',
|
|
21
|
+
'EnigmaM3RotorVII',
|
|
22
|
+
'EnigmaM3RotorVIII',
|
|
23
|
+
'EnigmaM4RotorI',
|
|
24
|
+
'EnigmaM4RotorII',
|
|
25
|
+
'EnigmaM4RotorIII',
|
|
26
|
+
'EnigmaM4RotorIV',
|
|
27
|
+
'EnigmaM4RotorV',
|
|
28
|
+
'EnigmaM4RotorVI',
|
|
29
|
+
'EnigmaM4RotorVII',
|
|
30
|
+
'EnigmaM4RotorVIII',
|
|
31
|
+
'EnigmaM4RotorBeta',
|
|
32
|
+
'EnigmaM4RotorGamma',
|
|
33
|
+
'Utils',
|
|
34
|
+
'Rotor',
|
|
35
|
+
'Plugboard',
|
|
36
|
+
'PlugboardPassthrough',
|
|
37
|
+
'Etw',
|
|
38
|
+
'EtwPassthrough',
|
|
39
|
+
'Reflector',
|
|
40
|
+
'ReflectorNorwayUKW',
|
|
41
|
+
'ReflectorSonderUKW',
|
|
42
|
+
'ReflectorUKWA',
|
|
43
|
+
'ReflectorUKWB',
|
|
44
|
+
'ReflectorUKWBThin',
|
|
45
|
+
'ReflectorUKWC',
|
|
46
|
+
'ReflectorUKWCThin',
|
|
47
|
+
'EnigmaI',
|
|
48
|
+
'EnigmaINorway',
|
|
49
|
+
'EnigmaISonder',
|
|
50
|
+
'EnigmaM3',
|
|
51
|
+
'EnigmaM4',
|
|
52
|
+
]
|
|
53
|
+
from .Rotor import Rotor
|
|
54
|
+
from .Utils import Utils
|
|
55
|
+
from . import *
|
|
56
|
+
|
|
57
|
+
for sub in Utils.find_all_subclasses(Rotor):
|
|
58
|
+
Rotor.register(sub.tag,sub)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
setup.py
|
|
2
|
+
enigmapython/Enigma.py
|
|
3
|
+
enigmapython/EnigmaI.py
|
|
4
|
+
enigmapython/EnigmaINorway.py
|
|
5
|
+
enigmapython/EnigmaINorwayRotorI.py
|
|
6
|
+
enigmapython/EnigmaINorwayRotorII.py
|
|
7
|
+
enigmapython/EnigmaINorwayRotorIII.py
|
|
8
|
+
enigmapython/EnigmaINorwayRotorIV.py
|
|
9
|
+
enigmapython/EnigmaINorwayRotorV.py
|
|
10
|
+
enigmapython/EnigmaIRotorI.py
|
|
11
|
+
enigmapython/EnigmaIRotorII.py
|
|
12
|
+
enigmapython/EnigmaIRotorIII.py
|
|
13
|
+
enigmapython/EnigmaIRotorIV.py
|
|
14
|
+
enigmapython/EnigmaIRotorV.py
|
|
15
|
+
enigmapython/EnigmaISonder.py
|
|
16
|
+
enigmapython/EnigmaISonderRotorI.py
|
|
17
|
+
enigmapython/EnigmaISonderRotorII.py
|
|
18
|
+
enigmapython/EnigmaISonderRotorIII.py
|
|
19
|
+
enigmapython/EnigmaM3.py
|
|
20
|
+
enigmapython/EnigmaM3RotorI.py
|
|
21
|
+
enigmapython/EnigmaM3RotorII.py
|
|
22
|
+
enigmapython/EnigmaM3RotorIII.py
|
|
23
|
+
enigmapython/EnigmaM3RotorIV.py
|
|
24
|
+
enigmapython/EnigmaM3RotorV.py
|
|
25
|
+
enigmapython/EnigmaM3RotorVI.py
|
|
26
|
+
enigmapython/EnigmaM3RotorVII.py
|
|
27
|
+
enigmapython/EnigmaM3RotorVIII.py
|
|
28
|
+
enigmapython/EnigmaM4.py
|
|
29
|
+
enigmapython/EnigmaM4RotorBeta.py
|
|
30
|
+
enigmapython/EnigmaM4RotorGamma.py
|
|
31
|
+
enigmapython/EnigmaM4RotorI.py
|
|
32
|
+
enigmapython/EnigmaM4RotorII.py
|
|
33
|
+
enigmapython/EnigmaM4RotorIII.py
|
|
34
|
+
enigmapython/EnigmaM4RotorIV.py
|
|
35
|
+
enigmapython/EnigmaM4RotorV.py
|
|
36
|
+
enigmapython/EnigmaM4RotorVI.py
|
|
37
|
+
enigmapython/EnigmaM4RotorVII.py
|
|
38
|
+
enigmapython/EnigmaM4RotorVIII.py
|
|
39
|
+
enigmapython/Etw.py
|
|
40
|
+
enigmapython/EtwPassthrough.py
|
|
41
|
+
enigmapython/Observable.py
|
|
42
|
+
enigmapython/Observer.py
|
|
43
|
+
enigmapython/Plugboard.py
|
|
44
|
+
enigmapython/PlugboardPassthrough.py
|
|
45
|
+
enigmapython/Reflector.py
|
|
46
|
+
enigmapython/ReflectorNorwayUKW.py
|
|
47
|
+
enigmapython/ReflectorSonderUKW.py
|
|
48
|
+
enigmapython/ReflectorUKWA.py
|
|
49
|
+
enigmapython/ReflectorUKWB.py
|
|
50
|
+
enigmapython/ReflectorUKWBThin.py
|
|
51
|
+
enigmapython/ReflectorUKWC.py
|
|
52
|
+
enigmapython/ReflectorUKWCThin.py
|
|
53
|
+
enigmapython/Rotor.py
|
|
54
|
+
enigmapython/SwappablePlugboard.py
|
|
55
|
+
enigmapython/Utils.py
|
|
56
|
+
enigmapython/__init__.py
|
|
57
|
+
enigmapython.egg-info/PKG-INFO
|
|
58
|
+
enigmapython.egg-info/SOURCES.txt
|
|
59
|
+
enigmapython.egg-info/dependency_links.txt
|
|
60
|
+
enigmapython.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
enigmapython
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
setup(
|
|
5
|
+
name="enigmapython",
|
|
6
|
+
version="0.1.0",
|
|
7
|
+
packages=find_packages(
|
|
8
|
+
# All keyword arguments below are optional:
|
|
9
|
+
where='.', # '.' by default
|
|
10
|
+
include=['enigmapython'], # ['*'] by default
|
|
11
|
+
),
|
|
12
|
+
long_description=open('./enigmapython/README.txt').read(),
|
|
13
|
+
long_description_content_type='text/markdown'
|
|
14
|
+
)
|