enigmapython 1.0.0__tar.gz → 1.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-1.0.0 → enigmapython-1.1.0}/PKG-INFO +33 -3
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/Enigma.py +28 -10
- enigmapython-1.1.0/enigmapython/EnigmaD.py +9 -0
- enigmapython-1.1.0/enigmapython/EnigmaDEtw_JWULCM.py +6 -0
- enigmapython-1.1.0/enigmapython/EnigmaDEtw_QWERTZ.py +6 -0
- enigmapython-1.1.0/enigmapython/EnigmaDRotorI.py +11 -0
- enigmapython-1.1.0/enigmapython/EnigmaDRotorII.py +11 -0
- enigmapython-1.1.0/enigmapython/EnigmaDRotorIII.py +11 -0
- enigmapython-1.1.0/enigmapython/Etw.py +22 -0
- enigmapython-1.1.0/enigmapython/ReflectorDUKW.py +9 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/Rotor.py +10 -9
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython.egg-info/PKG-INFO +33 -3
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython.egg-info/SOURCES.txt +7 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/setup.py +1 -1
- enigmapython-1.0.0/enigmapython/Etw.py +0 -14
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaI.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaINorway.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaINorwayRotorI.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaINorwayRotorII.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaINorwayRotorIII.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaINorwayRotorIV.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaINorwayRotorV.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaIRotorI.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaIRotorII.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaIRotorIII.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaIRotorIV.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaIRotorV.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaISonder.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaISonderRotorI.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaISonderRotorII.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaISonderRotorIII.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaM3.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaM3RotorI.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaM3RotorII.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaM3RotorIII.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaM3RotorIV.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaM3RotorV.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaM3RotorVI.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaM3RotorVII.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaM3RotorVIII.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaM4.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaM4RotorBeta.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaM4RotorGamma.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaM4RotorI.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaM4RotorII.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaM4RotorIII.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaM4RotorIV.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaM4RotorV.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaM4RotorVI.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaM4RotorVII.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EnigmaM4RotorVIII.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/EtwPassthrough.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/Observable.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/Observer.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/Plugboard.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/PlugboardPassthrough.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/Reflector.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/ReflectorNorwayUKW.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/ReflectorSonderUKW.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/ReflectorUKWA.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/ReflectorUKWB.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/ReflectorUKWBThin.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/ReflectorUKWC.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/ReflectorUKWCThin.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/SwappablePlugboard.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/Utils.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython/__init__.py +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython.egg-info/dependency_links.txt +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/enigmapython.egg-info/top_level.txt +0 -0
- {enigmapython-1.0.0 → enigmapython-1.1.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: enigmapython
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.1.0
|
|
4
4
|
Summary: A simple yet faithful library to emulate different Enigma machines models using Python
|
|
5
5
|
Home-page: https://github.com/denismaggior8/enigma-python
|
|
6
6
|
Author: Denis Maggiorotto
|
|
@@ -24,6 +24,17 @@ Welcome to **enigmapython**, a Python package designed to emulate the legendary
|
|
|
24
24
|
|
|
25
25
|
The following Enigma machine models (along with their rotors, reflectors and plugboards) have been implemented:
|
|
26
26
|
|
|
27
|
+
### Enigma D
|
|
28
|
+
|
|
29
|
+
| Scrambler | Wiring | Notch | Implemented |
|
|
30
|
+
|------- |---------------------------- |------- |------------- |
|
|
31
|
+
| ETW "QWERTZ" | qwertzuioasdfghjkpyxcvbnml | N/A | ✅ |
|
|
32
|
+
| ETW "JWULCM" | jwulcmnohpqzyxiradkegvbtsf | N/A | ✅ |
|
|
33
|
+
| Rotor I | lpgszmhaeoqkvxrfybutnicjdw | y | ✅ |
|
|
34
|
+
| Rotor II | slvgbtfxjqohewirzyamkpcndu | e | ✅ |
|
|
35
|
+
| Rotor III | bdfhjlcprtxvznyeiwgakmusqo | n | ✅ |
|
|
36
|
+
| Reflector UKW | imetcgfraysqbzxwlhkdvupojn | N/A | ✅ |
|
|
37
|
+
|
|
27
38
|
### Enigma I
|
|
28
39
|
|
|
29
40
|
| Scrambler | Wiring | Notch | Implemented |
|
|
@@ -109,17 +120,36 @@ Please have a look of the [examples](https://github.com/denismaggior8/enigma-pyt
|
|
|
109
120
|
|
|
110
121
|
## Documentation
|
|
111
122
|
|
|
112
|
-
|
|
123
|
+
An initial documentation draft can be found [here](./docs/README.md), but in most cases examples, code (and comments) are better than the documentation
|
|
124
|
+
|
|
125
|
+
## Known implementations
|
|
126
|
+
|
|
127
|
+
Here's a list containing all the known Enigma simulators that use the **enigmapython** API.
|
|
128
|
+
|
|
129
|
+
- [Retrocampus BBS Enigma simulator](https://retrocampus.com/bbs/). When connected to the BBS, type E to access an Enigma M3 cypher machine. 
|
|
130
|
+
|
|
131
|
+
In the case you leveraged **enigmapython** API in a project, either public or not, drop me an email at __denis.maggiorotto[at]gmail.com__ and I'll be happy to list you here.
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
## Known implementations
|
|
135
|
+
|
|
136
|
+
Here's a list containing all the known Enigma simulators that use the **enigmapython** API.
|
|
137
|
+
|
|
138
|
+
- [Retrocampus BBS Enigma simulator](https://retrocampus.com/bbs/). When connected to the BBS, type E to access an Enigma M3 cypher machine. 
|
|
139
|
+
|
|
140
|
+
In the case you leveraged **enigmapython** API in a project, either public or not, drop me an email at __denis.maggiorotto[at]gmail.com__ and I'll be happy to list you here.
|
|
141
|
+
|
|
113
142
|
|
|
114
143
|
## Credits/references
|
|
115
144
|
|
|
116
145
|
- Early days experiments with Python and Enigma (where this repo comes from) can be found at: https://github.com/denismaggior8/enigma-cypher
|
|
117
|
-
- Rotors wirings have been taken from Crypto Museum at this link https://www.cryptomuseum.com/crypto/enigma/wiring.htm
|
|
146
|
+
- Rotors wirings have been taken from **Crypto Museum** at this link https://www.cryptomuseum.com/crypto/enigma/wiring.htm
|
|
118
147
|
- Thanks to
|
|
119
148
|
- Piotte13 https://piotte13.github.io/enigma-cipher/
|
|
120
149
|
- Cryptii https://cryptii.com
|
|
121
150
|
- PyEnigma https://pypi.org/project/pyenigma/
|
|
122
151
|
- 101 computing https://www.101computing.net/enigma-machine-emulator/
|
|
152
|
+
- DenCode Enigma simulator https://dencode.com/cipher/enigma
|
|
123
153
|
|
|
124
154
|
for having helped me testing the correctness of the generated ciphertexts
|
|
125
155
|
|
|
@@ -11,14 +11,15 @@ class Enigma(Observer):
|
|
|
11
11
|
etw = None
|
|
12
12
|
auto_increment_rotors = False
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
alphabet_list = None
|
|
15
15
|
|
|
16
|
-
def __init__(self, plugboard, rotors, reflector,etw,auto_increment_rotors=False):
|
|
16
|
+
def __init__(self, plugboard, rotors, reflector,etw,auto_increment_rotors=False, alphabet=ascii_lowercase):
|
|
17
17
|
self.plugboard = plugboard
|
|
18
18
|
self.rotors = rotors
|
|
19
19
|
self.reflector = reflector
|
|
20
20
|
self.etw = etw
|
|
21
21
|
self.auto_increment_rotors = auto_increment_rotors
|
|
22
|
+
self.alphabet_list = list(alphabet)
|
|
22
23
|
if auto_increment_rotors == True:
|
|
23
24
|
for rotor in rotors:
|
|
24
25
|
rotor.add_observer(self)
|
|
@@ -42,28 +43,45 @@ class Enigma(Observer):
|
|
|
42
43
|
scrambled_char = self.process_char(char)
|
|
43
44
|
return scrambled_char
|
|
44
45
|
|
|
46
|
+
"""
|
|
47
|
+
UKW Rotor Rotor Rotor ETW PLUGBOARD
|
|
48
|
+
N 2 1
|
|
49
|
+
___ ___ ___ ___ ___ ___
|
|
50
|
+
| | | | | | | | | | | |
|
|
51
|
+
| -|--|---|--|---|--|---|--|---|--|---|-- < Key
|
|
52
|
+
| | | | | | | | | | | | |
|
|
53
|
+
| | | | | | | | | | | | |
|
|
54
|
+
| -|--|---|--|---|--|---|--|---|--|---|-- > Lamp
|
|
55
|
+
| | | | | | | | | | | |
|
|
56
|
+
--- --- --- --- --- ---
|
|
57
|
+
"""
|
|
45
58
|
def process_char(self, char):
|
|
46
59
|
scrambled_char = self.plugboard.switch_char(char)
|
|
47
60
|
logging.debug("Scrambled letter from plugboard: {}".format(scrambled_char))
|
|
61
|
+
scrambled_char = self.etw.process_char_forward(scrambled_char,0)
|
|
62
|
+
logging.debug("Scrambled letter from ETW: {}".format(scrambled_char))
|
|
48
63
|
iteration = 0
|
|
49
64
|
for rotor in self.rotors:
|
|
50
65
|
if iteration == 0:
|
|
51
|
-
scrambled_char = rotor.scramble_letter_index(rotor.wiring,
|
|
66
|
+
scrambled_char = rotor.scramble_letter_index(rotor.wiring,self.alphabet_list.index(scrambled_char))
|
|
52
67
|
else:
|
|
53
|
-
scrambled_char = rotor.scramble_letter_index(rotor.wiring,
|
|
68
|
+
scrambled_char = rotor.scramble_letter_index(rotor.wiring,self.alphabet_list.index(scrambled_char)-self.rotors[iteration-1].position)
|
|
54
69
|
iteration +=1
|
|
55
70
|
logging.debug("Scrambled letter from rotor{}: {}".format(str(iteration),scrambled_char))
|
|
56
|
-
scrambled_char = self.reflector.scramble_letter_index(self.reflector.wiring,(
|
|
71
|
+
scrambled_char = self.reflector.scramble_letter_index(self.reflector.wiring,(self.alphabet_list.index(scrambled_char)-self.rotors[iteration-1].position))
|
|
57
72
|
logging.debug("Scrambled letter from reflector: {}".format(scrambled_char))
|
|
58
73
|
for rotor in reversed(self.rotors):
|
|
59
74
|
if iteration == len(self.rotors):
|
|
60
|
-
scrambled_char = rotor.scramble_letter_index(
|
|
75
|
+
scrambled_char = rotor.scramble_letter_index(self.alphabet_list,(rotor.wiring.index(self.shift_letter(scrambled_char,rotor.position,self.alphabet_list))-rotor.position))
|
|
61
76
|
else:
|
|
62
|
-
scrambled_char = rotor.scramble_letter_index(
|
|
77
|
+
scrambled_char = rotor.scramble_letter_index(self.alphabet_list,(rotor.wiring.index(self.shift_letter(scrambled_char, (rotor.position - self.rotors[iteration].position),self.alphabet_list)) - rotor.position))
|
|
63
78
|
iteration -=1
|
|
64
79
|
logging.debug("Scrambled letter from rotor{}: {}".format(str(iteration+1),scrambled_char))
|
|
65
|
-
|
|
80
|
+
|
|
81
|
+
# Processing rotor 1 returning signal by ETW
|
|
82
|
+
scrambled_char = self.etw.process_char_backward(scrambled_char,self.rotors[iteration].position)
|
|
66
83
|
logging.debug("Scrambled letter from ETW: {}".format(scrambled_char))
|
|
84
|
+
|
|
67
85
|
scrambled_char = self.plugboard.switch_char(scrambled_char)
|
|
68
86
|
logging.debug("Scrambled letter from plugboard: {}".format(scrambled_char))
|
|
69
87
|
logging.info("Scrambled letter to lamp: {}".format(scrambled_char))
|
|
@@ -78,8 +96,8 @@ class Enigma(Observer):
|
|
|
78
96
|
self.rotors[self.rotors.index(observable)+1].double_step_triggered = True
|
|
79
97
|
|
|
80
98
|
@staticmethod
|
|
81
|
-
def shift_letter(letter,shift):
|
|
82
|
-
|
|
99
|
+
def shift_letter(letter,shift,alphabet_list):
|
|
100
|
+
return alphabet_list[(alphabet_list.index(letter)+shift) % len(alphabet_list)]
|
|
83
101
|
|
|
84
102
|
|
|
85
103
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from .Enigma import Enigma
|
|
2
|
+
from .PlugboardPassthrough import PlugboardPassthrough
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class EnigmaD(Enigma):
|
|
6
|
+
|
|
7
|
+
def __init__(self,rotor1, rotor2, rotor3,reflector,etw,auto_increment_rotors=False):
|
|
8
|
+
rotors = [rotor1, rotor2, rotor3]
|
|
9
|
+
super().__init__(PlugboardPassthrough(),rotors,reflector,etw,auto_increment_rotors)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from .Rotor import Rotor
|
|
2
|
+
|
|
3
|
+
class EnigmaDRotorIII(Rotor):
|
|
4
|
+
|
|
5
|
+
wiring = 'cjgdpshkturawzxfmynqobvlie'
|
|
6
|
+
notch_indexes = [13]
|
|
7
|
+
tag = "D_III"
|
|
8
|
+
|
|
9
|
+
def __init__(self, position = 0, ring = 0):
|
|
10
|
+
super().__init__(self.wiring, position, ring, self.notch_indexes)
|
|
11
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
|
|
2
|
+
from string import ascii_lowercase
|
|
3
|
+
|
|
4
|
+
class Etw:
|
|
5
|
+
wiring = None
|
|
6
|
+
alphabet_list = None
|
|
7
|
+
|
|
8
|
+
def process_char_forward(self,char,shift):
|
|
9
|
+
return self.wiring[self.alphabet_list.index(char)+shift]
|
|
10
|
+
|
|
11
|
+
def process_char_backward(self,char,shift):
|
|
12
|
+
myint = (self.alphabet_list.index(char)-shift) % len(self.alphabet_list)
|
|
13
|
+
myletter = self.alphabet_list[myint]
|
|
14
|
+
myint1 = self.wiring.index(myletter)
|
|
15
|
+
return self.alphabet_list[myint1]
|
|
16
|
+
|
|
17
|
+
def __init__(self, wiring, alphabet=ascii_lowercase):
|
|
18
|
+
self.wiring = wiring
|
|
19
|
+
self.alphabet_list = list(alphabet)
|
|
20
|
+
|
|
21
|
+
def __str__(self):
|
|
22
|
+
return self.wiring
|
|
@@ -13,6 +13,7 @@ class Rotor(Observable):
|
|
|
13
13
|
ring = None
|
|
14
14
|
dot_position = None
|
|
15
15
|
lookup = {}
|
|
16
|
+
alphabet_list = None
|
|
16
17
|
|
|
17
18
|
@staticmethod
|
|
18
19
|
def register(tag, class_name):
|
|
@@ -38,7 +39,7 @@ class Rotor(Observable):
|
|
|
38
39
|
scrambled_letter_index_from_rotor = dictionary.index(dictionary[(self.position + letter_index) % len(dictionary)])
|
|
39
40
|
return dictionary[scrambled_letter_index_from_rotor]
|
|
40
41
|
|
|
41
|
-
def __init__(self, wiring, position = 0, ring = 0, notch_indexes=[]):
|
|
42
|
+
def __init__(self, wiring, position = 0, ring = 0, notch_indexes=[], alphabet=ascii_lowercase):
|
|
42
43
|
self.wiring = wiring
|
|
43
44
|
self.position = position % len(wiring)
|
|
44
45
|
self.notch_indexes = notch_indexes
|
|
@@ -46,6 +47,7 @@ class Rotor(Observable):
|
|
|
46
47
|
self.rotations_counter = 0
|
|
47
48
|
self.original_wiring = self.wiring
|
|
48
49
|
self.ring = ring
|
|
50
|
+
self.alphabet_list = list(alphabet)
|
|
49
51
|
self.set_rotor_ring(ring)
|
|
50
52
|
|
|
51
53
|
def __str__(self):
|
|
@@ -59,7 +61,6 @@ class Rotor(Observable):
|
|
|
59
61
|
self.wiring = self.original_wiring
|
|
60
62
|
self.dot_position = list(self.wiring).index("a")
|
|
61
63
|
logging.debug("Dot position: " + str(self.dot_position))
|
|
62
|
-
alphabet = list(ascii_lowercase)
|
|
63
64
|
for i in range(0, ring):
|
|
64
65
|
# Set temporary wiring variable
|
|
65
66
|
temp_wiring = self.wiring
|
|
@@ -68,25 +69,25 @@ class Rotor(Observable):
|
|
|
68
69
|
# Loop over chars in temporary wiring
|
|
69
70
|
for char in temp_wiring:
|
|
70
71
|
# Shift the char by one and add that shifted char to wiring variable
|
|
71
|
-
wiring += Rotor.shift(char, 1,
|
|
72
|
+
wiring += Rotor.shift(char, 1, self.alphabet_list)
|
|
72
73
|
# Add one to dot position, make sure we don't exceed the lenght of the alphabet
|
|
73
74
|
self.wiring = wiring
|
|
74
|
-
self.dot_position = (self.dot_position + 1) % len(
|
|
75
|
+
self.dot_position = (self.dot_position + 1) % len(self.alphabet_list)
|
|
75
76
|
logging.debug("Wiring shifted up the alphabet: " + wiring)
|
|
76
77
|
logging.debug("New dot position: " + str(self.dot_position))
|
|
77
78
|
i = 0
|
|
78
79
|
# While the letter at the dot position doesn't match with the ringstellung
|
|
79
|
-
while not self.wiring[self.dot_position] ==
|
|
80
|
+
while not self.wiring[self.dot_position] == self.alphabet_list[ring % len(self.wiring)]:
|
|
80
81
|
i += 1
|
|
81
82
|
# Rotate the wiring
|
|
82
83
|
self.wiring = self.wiring[-1:] + self.wiring[:-1]
|
|
83
84
|
logging.debug("Rotation " + str(i).zfill(2) + "; Wiring: " + self.wiring)
|
|
84
85
|
|
|
85
86
|
@staticmethod
|
|
86
|
-
def shift(letter, shift,
|
|
87
|
-
for i in range(0, len(
|
|
88
|
-
if
|
|
89
|
-
return
|
|
87
|
+
def shift(letter, shift, alphabet_list):
|
|
88
|
+
for i in range(0, len(alphabet_list)):
|
|
89
|
+
if alphabet_list[i] == letter:
|
|
90
|
+
return alphabet_list[(i + shift) % len(alphabet_list)]
|
|
90
91
|
|
|
91
92
|
@staticmethod
|
|
92
93
|
def get_instance_from_tag(tag: str):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: enigmapython
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.1.0
|
|
4
4
|
Summary: A simple yet faithful library to emulate different Enigma machines models using Python
|
|
5
5
|
Home-page: https://github.com/denismaggior8/enigma-python
|
|
6
6
|
Author: Denis Maggiorotto
|
|
@@ -24,6 +24,17 @@ Welcome to **enigmapython**, a Python package designed to emulate the legendary
|
|
|
24
24
|
|
|
25
25
|
The following Enigma machine models (along with their rotors, reflectors and plugboards) have been implemented:
|
|
26
26
|
|
|
27
|
+
### Enigma D
|
|
28
|
+
|
|
29
|
+
| Scrambler | Wiring | Notch | Implemented |
|
|
30
|
+
|------- |---------------------------- |------- |------------- |
|
|
31
|
+
| ETW "QWERTZ" | qwertzuioasdfghjkpyxcvbnml | N/A | ✅ |
|
|
32
|
+
| ETW "JWULCM" | jwulcmnohpqzyxiradkegvbtsf | N/A | ✅ |
|
|
33
|
+
| Rotor I | lpgszmhaeoqkvxrfybutnicjdw | y | ✅ |
|
|
34
|
+
| Rotor II | slvgbtfxjqohewirzyamkpcndu | e | ✅ |
|
|
35
|
+
| Rotor III | bdfhjlcprtxvznyeiwgakmusqo | n | ✅ |
|
|
36
|
+
| Reflector UKW | imetcgfraysqbzxwlhkdvupojn | N/A | ✅ |
|
|
37
|
+
|
|
27
38
|
### Enigma I
|
|
28
39
|
|
|
29
40
|
| Scrambler | Wiring | Notch | Implemented |
|
|
@@ -109,17 +120,36 @@ Please have a look of the [examples](https://github.com/denismaggior8/enigma-pyt
|
|
|
109
120
|
|
|
110
121
|
## Documentation
|
|
111
122
|
|
|
112
|
-
|
|
123
|
+
An initial documentation draft can be found [here](./docs/README.md), but in most cases examples, code (and comments) are better than the documentation
|
|
124
|
+
|
|
125
|
+
## Known implementations
|
|
126
|
+
|
|
127
|
+
Here's a list containing all the known Enigma simulators that use the **enigmapython** API.
|
|
128
|
+
|
|
129
|
+
- [Retrocampus BBS Enigma simulator](https://retrocampus.com/bbs/). When connected to the BBS, type E to access an Enigma M3 cypher machine. 
|
|
130
|
+
|
|
131
|
+
In the case you leveraged **enigmapython** API in a project, either public or not, drop me an email at __denis.maggiorotto[at]gmail.com__ and I'll be happy to list you here.
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
## Known implementations
|
|
135
|
+
|
|
136
|
+
Here's a list containing all the known Enigma simulators that use the **enigmapython** API.
|
|
137
|
+
|
|
138
|
+
- [Retrocampus BBS Enigma simulator](https://retrocampus.com/bbs/). When connected to the BBS, type E to access an Enigma M3 cypher machine. 
|
|
139
|
+
|
|
140
|
+
In the case you leveraged **enigmapython** API in a project, either public or not, drop me an email at __denis.maggiorotto[at]gmail.com__ and I'll be happy to list you here.
|
|
141
|
+
|
|
113
142
|
|
|
114
143
|
## Credits/references
|
|
115
144
|
|
|
116
145
|
- Early days experiments with Python and Enigma (where this repo comes from) can be found at: https://github.com/denismaggior8/enigma-cypher
|
|
117
|
-
- Rotors wirings have been taken from Crypto Museum at this link https://www.cryptomuseum.com/crypto/enigma/wiring.htm
|
|
146
|
+
- Rotors wirings have been taken from **Crypto Museum** at this link https://www.cryptomuseum.com/crypto/enigma/wiring.htm
|
|
118
147
|
- Thanks to
|
|
119
148
|
- Piotte13 https://piotte13.github.io/enigma-cipher/
|
|
120
149
|
- Cryptii https://cryptii.com
|
|
121
150
|
- PyEnigma https://pypi.org/project/pyenigma/
|
|
122
151
|
- 101 computing https://www.101computing.net/enigma-machine-emulator/
|
|
152
|
+
- DenCode Enigma simulator https://dencode.com/cipher/enigma
|
|
123
153
|
|
|
124
154
|
for having helped me testing the correctness of the generated ciphertexts
|
|
125
155
|
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
setup.py
|
|
2
2
|
enigmapython/Enigma.py
|
|
3
|
+
enigmapython/EnigmaD.py
|
|
4
|
+
enigmapython/EnigmaDEtw_JWULCM.py
|
|
5
|
+
enigmapython/EnigmaDEtw_QWERTZ.py
|
|
6
|
+
enigmapython/EnigmaDRotorI.py
|
|
7
|
+
enigmapython/EnigmaDRotorII.py
|
|
8
|
+
enigmapython/EnigmaDRotorIII.py
|
|
3
9
|
enigmapython/EnigmaI.py
|
|
4
10
|
enigmapython/EnigmaINorway.py
|
|
5
11
|
enigmapython/EnigmaINorwayRotorI.py
|
|
@@ -43,6 +49,7 @@ enigmapython/Observer.py
|
|
|
43
49
|
enigmapython/Plugboard.py
|
|
44
50
|
enigmapython/PlugboardPassthrough.py
|
|
45
51
|
enigmapython/Reflector.py
|
|
52
|
+
enigmapython/ReflectorDUKW.py
|
|
46
53
|
enigmapython/ReflectorNorwayUKW.py
|
|
47
54
|
enigmapython/ReflectorSonderUKW.py
|
|
48
55
|
enigmapython/ReflectorUKWA.py
|
|
@@ -12,7 +12,7 @@ setup(
|
|
|
12
12
|
long_description_content_type='text/markdown',
|
|
13
13
|
url="https://github.com/denismaggior8/enigma-python",
|
|
14
14
|
name="enigmapython",
|
|
15
|
-
version="1.
|
|
15
|
+
version="1.1.0",
|
|
16
16
|
packages=find_packages(
|
|
17
17
|
# All keyword arguments below are optional:
|
|
18
18
|
where='.', # '.' by default
|
|
@@ -1,14 +0,0 @@
|
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|