Python Forum
Enigma Machine, I need help!
Thread Rating:
  • 3 Vote(s) - 4 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Enigma Machine, I need help!
#41
(Nov-22-2017, 08:32 PM)Larz60+ Wrote: Kimkug, have you found anything like this?

Yes indeed I ave heard of interchangeable reflectors too. I am not sure from when on they were used, but only later on in the war.
I have nethertheless not heard of any key that was given.. I know, that each post, having an enigma machine to trancsport messages, had a sheet, where were written all the settings for the machine (of the day), so there was no need to communicate any sort of key?

Anyways, hank you a lot for your help! If possible, could you insert some comments, just in case I need to simplify the program to show others, where to remove for example the multiple triggers in each rotor (if you have some in the program), and other small details of the machine? The only purpose I have for it, is that it should be ready for demonstration purposes (encrypting and decrpyting should therefor work). I thank you a lot for you time and work!
Reply
#42
I think I got the link to this: http://www.ilord.com/enigma.html from your site.
there is a section for downloading manuals.
The Wikipedia page also has some useful links.

This whole think is going to get me on a crypto roll, probably for the next six months.
I did a lot in the past with PGP when it first emerged, and had my 'spy' wheels when I
was a kid (also had micron camera and other geek toys).
Reply
#43
(Nov-22-2017, 09:06 PM)Larz60+ Wrote: This whole think is going to get me on a crypto roll

Was thinking last night, if I had a 3D printer for the rotor, rotor rings and reflectors, I could build my own replica!! Had to slap myself back to reality.
If it ain't broke, I just haven't gotten to it yet.
OS: Windows 10, openSuse 42.3, freeBSD 11, Raspian "Stretch"
Python 3.6.5, IDE: PyCharm 2018 Community Edition
Reply
#44
My brother is a mechanical engineer.
He makes all kinds of things. Take a look at this Harley 1/4 scale
Knucklehead engine which is built to run: https://www.youtube.com/watch?v=lZutS12Q3Qs
Reply
#45
I have the incrementor working properly, (at least in the forward direction, bucause I'm not sure how to use the notches
on the reverse trip.

What I'm still not sure of is the way the rotor's rotation affects the cipher output,
because following Tony Sands example, it doesn't seem to have an effect. In addition,
I'm sure I've got the rotation increment correct in the forward direction, but still not clear on the reverse direction action.

New code Incrementor.py with full test (built into script) is now on github:
Testing against the Tony Sands example, here are the results:

First the code:
import json
import EnigmaPaths


class Incrementor:
    def __init__(self, rinfo, start_index=0):
        """
        Initialize - load rotor info, set starting indexes, get cipher
        :param rinfo:
        """
        self.epath = EnigmaPaths.EnigmaPaths()

        with self.epath.enigma_info.open() as f:
            self.init_data = json.load(f)

        self.cipher = rinfo['cipher']
        self.notch = rinfo['notches'][0]
        self.alpha = self.init_data['unencoded']
        self.index = start_index
        self.max_index = len(self.cipher) - 1

    def next_index(self):
        self.index += 1
        if self.index > self.max_index:
            self.index = 0
        return self.index

    def get_next_item(self, alpha_char, direction='f', preincrement=False):
        index = self.index
        if preincrement:
            index = self.next_index()
        if direction == 'f':
            aidx = self.alpha.index(alpha_char)
            item = self.cipher[aidx]
        else:
            cidx = self.cipher.index(alpha_char)
            item = self.alpha[cidx]
        advance = (self.alpha[index] == self.notch)
        if not preincrement:
            index = self.next_index()
        return item, advance

    def set_initial_index(self, index):
        if index >= len(self.cipher):
            print(f'index out of range, valid range is 0 - {self.max_index}')
        else:
            self.index = index

    def query_cipher(self):
        return self.cipher

    def query_index(self):
        return self.index

    def query_notch(self):
        return self.notch

def testit():
    # Order if progression is from right to left (rotors)
    # Assume 'B' selected for reflector
    # Our test letter.
    test_letter = 'G'

    # Setup right rotor(start index = 2, set by set_initial_index):
    rinfo = {'name': 'rotor3', 'cipher': 'BDFHJLCPRTXVZNYEIWGAKMUSQO', 'notches': ['W']}
    r_incrementor = Incrementor(rinfo)

    # Get reflector here (needed init_data to be visible
    test_reflector = r_incrementor.init_data['reflector_B']

    r_incrementor.set_initial_index(2)
    print(f'\nright alpha:  {r_incrementor.alpha}')
    print(f'right cipher: {r_incrementor.query_cipher()}')
    print(f'right index:  {r_incrementor.query_index()}')
    print(f'right notch:  {r_incrementor.query_notch()}')

    # Setup middle rotor (start index = 4 'S'):
    rinfo = {'name': 'rotor2', 'cipher': 'AJDKSIRUXBLHWTMCQGZNPYFVOE', 'notches': ['F']}
    m_incrementor = Incrementor(rinfo, start_index=4)
    print(f'\nmiddle alpha:  {m_incrementor.alpha}')
    print(f'middle cipher: {m_incrementor.query_cipher()}')
    print(f'middle index:  {m_incrementor.query_index()}')
    print(f'middle notch:  {m_incrementor.query_notch()}')

    # Setup left rotor (start index = 16):
    rinfo = {'name': 'rotor1', 'cipher': 'EKMFLGDQVZNTOWYHXUSPAIBRCJ', 'notches': ['R']}
    l_incrementor = Incrementor(rinfo, start_index=16)
    print(f'\nleft alpha:   {l_incrementor.alpha}')
    print(f'left cipher:  {l_incrementor.query_cipher()}')
    print(f'left index:   {l_incrementor.query_index()}')
    print(f'left notch:   {l_incrementor.query_notch()}')

    # Test one letter through entire process

    # First get right rotor cipher and advance rotor
    ritem, advance = r_incrementor.get_next_item(test_letter, direction='f')
    print(f'\nright rotor cipher: in: {test_letter}, out: {ritem}, advance: {advance}')
    # if advance is True increment middle rotor by 1
    # ignore cipher, in each case but check advance again
    if advance:
        # This means slot was encountered on middle advance, so
        #  have to advance left!
        mitem, advance = m_incrementor.get_next_item(ritem, direction='f')
        if advance:
            # This means middle slot was encountered on advance
            litem, advance = l_incrementor.get_next_item(mitem, direction='f')

    # Get middle rotor cipher and advance rotor
    mitem, advance = m_incrementor.get_next_item(ritem, direction='f')
    print(f'\nmiddle rotor cipher: in: {ritem}, out: {mitem}, advance: {advance}')
    if advance:
        # This means middle slot was encountered on advance
        litem, advance = l_incrementor.get_next_item(mitem, direction='f')

    litem, advance = l_incrementor.get_next_item(mitem, direction='f')
    print(f'\nleft rotor cipher: in: {mitem} out: {litem}, advance: {advance}')
    # Read up on what to do if advance = true, is the middle
    # advanced??

    # run through reflector
    aidx = l_incrementor.alpha.index(litem)
    refl_item = test_reflector[aidx]
    print(f'\nreflector output: in: {litem}, out: {refl_item}')

    # reverse trip
    print('Return trip')
    litem, advance = l_incrementor.get_next_item(refl_item, direction='r')
    print(f'\nleft rotor cipher: in: {refl_item}, out: {litem}, advance: {advance}')
    # Read up on what to do if advance = true, is the middle
    # advanced??

    # Get middle rotor cipher and advance rotor
    mitem, advance = m_incrementor.get_next_item(litem, direction='r')
    print(f'\nmiddle rotor cipher: in: {litem}, out: {mitem}, advance: {advance}')

    ritem, advance = r_incrementor.get_next_item(mitem, direction='r')
    print(f'\nright rotor cipher: in: {mitem}, out: {ritem}, advance: {advance}')

    print(f'\n\nletter in: {test_letter}, letter out: {ritem}')

if __name__ == '__main__':
    testit()
and built in test results:
Output:
right alpha:  ABCDEFGHIJKLMNOPQRSTUVWXYZ right cipher: BDFHJLCPRTXVZNYEIWGAKMUSQO right index:  2 right notch:  W middle alpha:  ABCDEFGHIJKLMNOPQRSTUVWXYZ middle cipher: AJDKSIRUXBLHWTMCQGZNPYFVOE middle index:  4 middle notch:  F left alpha:   ABCDEFGHIJKLMNOPQRSTUVWXYZ left cipher:  EKMFLGDQVZNTOWYHXUSPAIBRCJ left index:   16 left notch:   R right rotor cipher: in: G, out: C, advance: False middle rotor cipher: in: C, out: D, advance: False left rotor cipher: in: D out: F, advance: False reflector output: in: F, out: S Return trip left rotor cipher: in: S, out: S, advance: True middle rotor cipher: in: S, out: E, advance: True right rotor cipher: in: E, out: P, advance: False letter in: G, letter out: P
Reply
#46
I Think the best explanation for the Enigma technical operation is in this document:
https://www.nsa.gov/about/cryptologic-he...cipher.pdf
Reply
#47
I found an online emulator. Wish I had of seen this before I started!
http://enigma.louisedade.co.uk/enigma.html

By the way, the 'key' referred to the initial settings of the wheels, ex: 'AQT'
And the plugboard.
Reply
#48
Here are the complete details of how a key sheet worked:

Output:
Table Source: http://users.telenet.be/d.rijmenants/en/enigmaproc.htm The Heer and Luftwaffe Procedures To obtain secure communications, the German Heer (Army) and Luftwaffe (Air Force) used standard procedures to transmit and receive messages. For a message to be correctly encrypted and decrypted, both the sender and receiver needed to set up their Enigma in exactly the same way. These settings were distributed in key sheets. For reasons of security, different parts of the armed forces had their own network, with different key sheets and with a network having its own codename. Each key sheet contained the following information:     Walzenlage: Choice and order of wheels     Ringstellung: The ringsetting, the position of the rotor wiring,                   relative to the alphabet rings     Steckerverbindungen: The plug connections on the plugboard     Kenngruppen: Groups to identify the key to the receiver. The key sheets were distributed on beforehand, and contained the basic settings for a whole month, per day. In general, the key sheets were in the custody of an officer, responsible for setting up the machine rotors and ringsettings. After setup, he could lock the machine front panel with a key. The operator could only select the rotor start position.                             Armee Stabs Maschinenschlussel Nr. 28                               (Army Staffs Machine Key No. 28) --------------------------------------------------------------------------------------- Tag | Walzenlage   | Ringstellung | Steckerverbindungen           | Kenngruppen --------------------------------------------------------------------------------------- 31  | IV   V    I  | 21  15  16   | KL IT FQ HY XC NP VZ JB SE OG | JKM  OGO  NCJ  GLP 30  | IV   II III  | 26  14  11   | ZN YO QB ER DK XU GP TV SJ LM | INO  UDL  NAM  LAX 29  | II   V   IV  | 19  09  24   | ZU HL CQ WM OA PY EB TR DN VI | NCI  OID  YHP  NIP 28  | IV  III   I  | 03  04  22   | YT BX CV ZN UD IR SJ HW GA KQ | ZQJ  HLG  XKY  EBT 27  | I    II   V  | 06  22  14   | PO ML IU KJ NH YT GB VF RE DC | EXS  TGY  IKJ  LOP --------------------------------------------------------------------------------------- o To identify the key that was used for a particular message, the operator had to insert   a five letter group called Buchstabenkenngruppe (letter identification group) as the   first group of the message. The Buchstabenkenngruppe is composed of two randomly selected   letters and one of the four possible three-letter Kenngruppen at the key sheet for that   day. If we take day 31 from the Army Staff key 28 (image above), we see the Kenngruppen   JKM, OGI, NCJ and GLP. In this case, some  examples of a correct Buchstabenkenngruppe are   FDJKM, KVOGI or QNNCJ. This five letter group at the start of the message should not be   encrypted with the rest of the message! If a message was devided into several parts, the   operator had to insert another Buchstabenkenngruppe for each part of the message. When   counting the letters for the message header, the five letters of the Buchstabenkenngruppe   must be included. The receiving operator immediately recognized which key was to be   applied by looking at the last three letters of the first group. o The setting of the machine was typically valid for one day. Using the same settings for a   large number of messages would increase the statistical amount of data to break a   particular key. Therefore, each message was sent with a different startposition of the   Enigma rotors, randomly selected by the operator. This was called the Spruchschlüssel   or message key.   Before 1940, the German military used the daily key and startposition, according to the key   sheet. The operator selected a random message key. This message key was encoded twice, to   exclude errors. As example, the trigram GHK is encoded twice, resulting in XMC FZQ. Next,   the operator moved the rotors to the message key GHK and encoded the message. The two   trigrams, being the encoded message key, were transmitted, together with the message. The   receiver sets his machine on the start position, as described in the codebook, and decodes   the trigrams XMC FZQ back into the GHK message key. Next, he sets the message key GHK as   start position on his machine, to continue decoding the rest of the message. However, this   procedure was actually a security flaw. The message key is encoded twice, resulting in a   relation between first and fourth, second and fifth, and third and sixth character.   Moreover, many message keys on a particular day would have the same setup and startpositions.   This security problem enabled the Polish Cipher Bureau to break the pre-war Enigma messages.     However, German cryptologists were aware of the security flaw and from 1940 on, the Wehrmacht   changed the message key procedures to increase security.     Wehrmacht radio operators now selected for each message a new randomly chosen start position   or Grundstellung, let's say WZA, and random message key or Spruchschlüssel, let's say SXT. He   moved the rotors to the random startposition WZA, and encoded the random message key SXT. Let   us presume that the result was UHL. He sets up the message key SXT as startposition and   encodes the message. Next, he transmits the random start position WZA, the encoded message key   UHL and the message. The receiver sets up the start position according the first trigram WZA,   and decodes the second trigram UHL to obtain the message key SXT. Next, he uses the message   key SXT as startposition to decode the actual message. If a message was devided into several   parts, the operator had to insert a new startposition and message key for each part of the   message.   Example of a typical Wehrmacht message:   1230 = 3tle = 1tl = 250 = WZA UHL =      FDJKM LDAHH YEOEF PTWYB LENDP   MKOXL DFAMU DWIJD XRJZY DFRIO   MFTEV KTGUY DDZED TPOQX FDRIU   CCBFM MQWYE FIPUL WSXHG YHJZE   AOFDU FUTEC VVBDP OLZLG DEJTI   HGYER DCXCV BHSEE TTKJK XAAQU   GTTUO FCXZH IDREF TGHSZ DERFG   EDZZS ERDET RFGTT RREOM MJMED   EDDER FTGRE UUHKD DLEFG FGREZ   ZZSEU YYRGD EDFED HJUIK FXNVB   The message was created at 12h30, consists of three parts (3 teile), of which this is the   first, and contains 250 characters (Buchstabenkenngruppe included). WZA is the startposition   (Grundstellung) to decipher the encrypted message key (Spruchschlüssel) UHL. The   Buchstabenkenngruppe FDJKM shows that the key that was used is the one with Kenngruppe JKM.   Example for decrypt:   U6Z DE C 1510 = 49 = EHZ TBS =   TVEXS QBLTW LDAHH YEOEF   PTWYB LENDP MKOXL DFAMU   DWIJD XRJZ=   To decrypt the message we proceed as follows:       • Select the Wehrmacht Enigma I with B reflector.     • Select the rotors, adjust their ring setting and set the plugs according to key sheet day 27     • Set the rotor start positions to EHZ, the first trigram of the message     • Type in the second trigram TBS to retrieve the original message key. The result should be XWB     • Set the decrypted message key XWB as start position for the three rotors.     • Now decrypt the actual message, but make sure to skip the key identification group TVEXS.   Note: in the pre-war Wehrmacht procedure, each message key was encrypted twice (to exclude errors)   by a fixed secret basic position, valid for the whole day. For instance, with basic setting ABC,   the message key XYZ was keyed in twice, resulting in JKL MNO. Only the double encrypted message key   JKL MNO was sent along with the message. However, this created a mathematical relation between J   and M, K and N, and L and O, a flaw that was exploited by the Polish codebreakers. German   cryptologists understood this flaw and dropped the double encrypted message key in 1939, replacing   it with a random basic position, sent along with a once encrypted message key.
Reply
#49
Very good explanation of the actual usage. Clears up for me the use of the "Kenngruppen". Thanks for posting.
If it ain't broke, I just haven't gotten to it yet.
OS: Windows 10, openSuse 42.3, freeBSD 11, Raspian "Stretch"
Python 3.6.5, IDE: PyCharm 2018 Community Edition
Reply
#50
Wow, I'm so very impressed right now. I did not know much about the information about the "key" you sent, and this will be a big help!

Just a question, how far from completition is the program at the moment?
I still have to thank you in every message for the work you are taking on! So thamk you a lot, and it isn't too urgent that it is done, it just sounded you were near to done ;)
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Numeric Enigma Machine idev 8 218 11 hours ago
Last Post: idev
  Enigma Decoding Problem krisarmstrong 4 633 Dec-14-2023, 10:42 AM
Last Post: Larz60+

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020