Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
Former Member

I got interested in the story of the Enigma machines and Bletchly Park and ended up writing this, just for kicks :smile:

Now, is someone can write something in ABAP to decypher Enigma messages, please let me know.

*&---------------------------------------------------------------------*
*  Report  Z_ENIGMA
*
*&---------------------------------------------------------------------*
* This is a3 wheel Enigma coding machine emulator using genuine wheel settings.
* Sequence is this :-
* Input -> Plugboard -> Wheel 3,2,1 -> Reflector -> Wheel 1,2,3 -> Plugboard -> Output
*
* The plugboard is a set of connections between the wheel input and either
* the keyboard (i/P) or lightboard (o/p)
*
* An enigma wheel has a set of 26 i/p connections and 26 o/p connections
* It has a ring around the outside so these connections can be
* shifted relative to the characters that are displayed on its outer edge.
* It has a turnover point where the next wheel in the set moves 1 position
* (think how a car odometer works when it moves from 9 to 10)
*
* When in use, the initial settings have to be known by the receiving machine
* So the initial settings are encoded using some other method and transmitted
* to the receiver first. This is called public key encryption, because the key
* is known publicly (but not how to use it).
*&---------------------------------------------------------------------*
* Text symbols are defined as :
* 001 = "Enigma Settings: Wheel order, start positions and plugboard"
* 002 = "Text to be encrypted / decrypted. Characters A to Z only. No puncuation / numbers."
*
* Selection Texts are defined as :
* INIT1    = "Initial Position Wheel 1"
* INIT2    = "Initial Position Wheel 2"
* INIT3    = "Initial Position Wheel 3"
* P_PLUGB  = "Use plugboard mapping?"
* W1      = "Wheel 1"
* W2      = "Wheel 2"
* W3      = "Wheel 3"
*&---------------------------------------------------------------------*

REPORT  z_enigma .

CONSTANTS:
           c_ref_b    TYPE char26 VALUE 'YRUHQSLDPXNGOKMIEBFZCWVJAT',
           c_plugb    TYPE char26 VALUE 'ZBCDEFHGIJKLNMOPQRSTUVWXYA',
           c_alpha    TYPE char26 VALUE 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
           c_wheel1   TYPE char26 VALUE 'EKMFLGDQVZNTOWYHXUSPAIBRCJ',
           c_wheel2   TYPE char26 VALUE 'AJDKSIRUXBLHWTMCQGZNPYFVOE',
           c_wheel3   TYPE char26 VALUE 'BDFHJLCPRTXVZNYEIWGAKMUSQO',
           c_wheel4   TYPE char26 VALUE 'ESOVPZJAYQUIRHXLNFTGKDCMWB',
           c_wheel5   TYPE char26 VALUE 'VZBRGITYUPSDNHLXAWMJQOFECK',
           c_wheel6   TYPE char26 VALUE 'JPGVOUMFYQBENHZRDKASXLICTW',
           c_wheel7   TYPE char26 VALUE 'NZJHGRCXMYSWBOUFAIVLPEKQDT',
           c_wheel8   TYPE char26 VALUE 'FKQHTLXOCBJSPDZRAMEWNIUYGV',
           c_turn1    TYPE char1  VALUE 'R',
           c_turn2    TYPE char1  VALUE 'F',
           c_turn3    TYPE char1  VALUE 'W',
           c_turn4    TYPE char1  VALUE 'K',
           c_turn5    TYPE char1  VALUE 'A',
           c_turn6    TYPE char2  VALUE 'AN', "Getting sneaky by using 2 turnover positions
           c_turn7    TYPE char2  VALUE 'AN',
           c_turn8    TYPE char2  VALUE 'AN'.

DATA: v_output TYPE string,
      v_source TYPE string,
      v_temp   TYPE string,
      v_length TYPE i,
      source   TYPE string,
      wheel3   TYPE char26,
      wheel2   TYPE char26,
      wheel1   TYPE char26,
      alpha    TYPE char26,
      turn1    TYPE char1,
      turn2    TYPE char1,
      fname    TYPE char8.

TYPES : BEGIN OF ty_wrd ,
         text TYPE char80 ,
       END OF ty_wrd .

DATA: char_in    TYPE char1,
      c1    TYPE char1,
      idx   TYPE i,
      pos   TYPE i,
      char_out TYPE char1,
      lt_text  TYPE TABLE OF ty_wrd WITH HEADER LINE,
      gc_docking        TYPE REF TO cl_gui_docking_container,
      gc_text_editor    TYPE REF TO cl_gui_textedit,
      gt_text           TYPE TABLE OF tline-tdline,
      gs_text           TYPE tline-tdline.

FIELD-SYMBOLS <data> TYPE any.

*======================================================================*
SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE text-001.
* Choose 3 wheels
PARAMETERS: w1 TYPE ddtabind DEFAULT 1,
            w2 TYPE ddtabind DEFAULT 2,
            w3 TYPE ddtabind DEFAULT 3.
SELECTION-SCREEN SKIP 1.

* Set wheel start position
PARAMETERS: init1 TYPE sf_char1 DEFAULT 'M',
            init2 TYPE sf_char1 DEFAULT 'C',
            init3 TYPE sf_char1 DEFAULT 'K'.

SELECTION-SCREEN SKIP 1.
PARAMETERS: p_plugb AS CHECKBOX DEFAULT 'X'.

SELECTION-SCREEN END OF BLOCK b1.

SELECTION-SCREEN SKIP 2.
SELECTION-SCREEN COMMENT /1(82) text-002.


*======================================================================*
INITIALIZATION.
  PERFORM initialization.

*======================================================================*
AT SELECTION-SCREEN OUTPUT.
  TRANSLATE init1 TO UPPER CASE.
  TRANSLATE init2 TO UPPER CASE.
  TRANSLATE init3 TO UPPER CASE.

AT SELECTION-SCREEN ON BLOCK b1.
  IF w1 IS INITIAL OR
     w2 IS INITIAL OR
     w3 IS INITIAL OR
     w1 > 8 OR w2 > 8 OR w3 > 8.
    MESSAGE s001(00) WITH 'Select 3 wheel numbers from 1 to 8'.
  ENDIF.

  IF w3 = w2 OR
     w3 = w1 OR
     w2 = w1.
    MESSAGE s001(00) WITH 'Wheels cannot be used in more that 1 position'.
  ENDIF.

  IF init1 IS INITIAL OR
     init1 NA sy-abcde.
    MESSAGE s001(00) WITH 'Set start position wheel 1 A to Z'.
  ENDIF.
  IF init2 IS INITIAL OR
     init2 NA sy-abcde.
    MESSAGE s001(00) WITH 'Set start position wheel 2 A to Z'.
  ENDIF.
  IF init3 IS INITIAL OR
     init3 NA sy-abcde.
    MESSAGE s001(00) WITH 'Set start position wheel 3 A to Z'.
  ENDIF.

*======================================================================*
START-OF-SELECTION.

* Load selected wheels into work areas
  CONCATENATE 'C_WHEEL' w1 INTO fname.
  ASSIGN  (fname) TO <data>.
  wheel1 = <data>.

  CONCATENATE 'C_WHEEL' w2 INTO fname.
  ASSIGN  (fname) TO <data>.
  wheel2 = <data>.
  CONCATENATE 'C_TURN' w2 INTO fname.
  ASSIGN  (fname) TO <data>.
  turn1 = <data>.


  CONCATENATE 'C_WHEEL' w3 INTO fname.
  ASSIGN  (fname) TO <data>.
  wheel3 = <data>.
  CONCATENATE 'C_TURN' w3 INTO fname.
  ASSIGN  (fname) TO <data>.
  turn2 = <data>.

  PERFORM enigma.

*======================================================================*
FORM initialization.

* Add free text box to selection screen
  CREATE OBJECT gc_docking
    EXPORTING
      repid     = sy-repid
      dynnr     = sy-dynnr
      side      = gc_docking->dock_at_bottom
      extension = 200.

  CREATE OBJECT gc_text_editor
    EXPORTING
      parent = gc_docking.

  IMPORT gt_text FROM MEMORY ID sy-repid.
* Put in sample text
  IF gt_text IS INITIAL.
    gs_text =  'ZKA NTCKV KOGZE WAO UPHZX HZSY YNI FKMB AFP'.
* Using wheels 123 at MCK with plugboard turned on
* this will decypher to "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG"
    APPEND gs_text TO gt_text.
  ENDIF.

  CALL METHOD gc_text_editor->set_text_as_r3table
    EXPORTING
      table  = gt_text
    EXCEPTIONS
      OTHERS = 1.

ENDFORM.                    " INITIALIZATION
*&---------------------------------------------------------------------*
*&      Form  enigma
*&---------------------------------------------------------------------*
FORM enigma.

* Get text from selection screen screen editor
  REFRESH gt_text.
  CALL METHOD gc_text_editor->get_text_as_r3table
    IMPORTING
      table  = gt_text
    EXCEPTIONS
      OTHERS = 1.

  CALL FUNCTION 'CONVERT_TABLE_TO_STRING'
    EXPORTING
      i_tabline_length = 132
    IMPORTING
      e_string         = source
    TABLES
      it_table         = gt_text.

* Shift to upper case and remove all spaces
  TRANSLATE source TO UPPER CASE.
  v_source = source.
  CONDENSE source NO-GAPS.
  v_length = strlen( source ).

* Order is this :-
* Input -> Plugboard -> Wheel 3,2,1 -> Reflector -> Wheel 1,2,3 -> Plugboard -> Output
  CLEAR : v_temp, v_output.

  DO v_length TIMES.

* get input character from keyboard
    pos = sy-index - 1.
    char_in = source+pos(1).

* Validate only alphabetic characters used
    IF char_in NA sy-abcde.
      MESSAGE s001(00) WITH 'Only letters A to Z allowed'.
      LEAVE LIST-PROCESSING.
    ENDIF.

* Plugboard mapping inbound
    PERFORM plugboard USING 'I' CHANGING char_in.

* Wheel 3
* Wheel 3 always steps on 1 position before encoding starts
    CLEAR pos.
    SEARCH c_alpha FOR init3.
    pos = sy-fdpos + 1. "11
    PERFORM index_wrap CHANGING pos.
    init3 = c_alpha+pos(1).

* Setup wheel
    CONCATENATE 'C_WHEEL' w3 INTO fname.
    ASSIGN  (fname) TO <data>.
    PERFORM set_wheel USING  <data>
                             init3
                    CHANGING wheel3.

* Look for index of entered character
    SEARCH c_alpha FOR char_in.

* Get wheel character.
    c1 = wheel3+sy-fdpos(1).

* Look for index of o/p character
    PERFORM set_wheel USING  c_alpha
                         init3
                CHANGING alpha.
    SEARCH alpha FOR c1.
    idx = sy-fdpos.

* Wheel 2 turnover
    IF turn1 CA init3.
      CLEAR pos.
      SEARCH c_alpha FOR init2.
      pos = sy-fdpos + 1.
      PERFORM index_wrap CHANGING pos.
      init2 = c_alpha+pos(1).
    ENDIF.

* Wheel 2
* Setup wheel
    CONCATENATE 'C_WHEEL' w2 INTO fname.
    ASSIGN  (fname) TO <data>.
    PERFORM set_wheel USING  <data>
                             init2
                    CHANGING wheel2.

    c1 = wheel2+idx(1).

* Look for index of o/p character
    PERFORM set_wheel USING  c_alpha
                         init2
                CHANGING wheel2.
    SEARCH wheel2 FOR c1.
    idx = sy-fdpos.


* Wheel 1 turnover
    IF turn2 CA init2.
      CLEAR pos.
      SEARCH c_alpha FOR init1.
      pos = sy-fdpos + 1.
      PERFORM index_wrap CHANGING pos.
      init1 = c_alpha+pos(1).
    ENDIF.

* Wheel 1
* Setup wheel
    CONCATENATE 'C_WHEEL' w1 INTO fname.
    ASSIGN  (fname) TO <data>.
    PERFORM set_wheel USING  <data>
                             init1
                    CHANGING wheel1.

    c1 = wheel1+idx(1).

* Look for index of o/p character
    PERFORM set_wheel USING  c_alpha
                         init1
                CHANGING wheel1.
    SEARCH wheel1 FOR c1.
    idx = sy-fdpos.
    c1 = c_alpha+idx(1).

* Reflector
    SEARCH c_ref_b FOR c1.
    c1 = c_alpha+sy-fdpos(1).
    idx = sy-fdpos.

* wheel 1 again
    PERFORM set_wheel USING  c_alpha
                      init1
             CHANGING wheel1.
    c1 = wheel1+idx(1).

    CONCATENATE 'C_WHEEL' w1 INTO fname.
    ASSIGN  (fname) TO <data>.
    PERFORM set_wheel USING  <data>
                             init1
                    CHANGING wheel1.
    SEARCH wheel1 FOR c1.
    idx = sy-fdpos.

* wheel 2 again
    PERFORM set_wheel USING  c_alpha
                      init2
             CHANGING wheel2.
    c1 = wheel2+idx(1).

    CONCATENATE 'C_WHEEL' w2 INTO fname.
    ASSIGN  (fname) TO <data>.
    PERFORM set_wheel USING  <data>
                             init2
                    CHANGING wheel2.
    SEARCH wheel2 FOR c1.
    idx = sy-fdpos.

* wheel 3 again
    PERFORM set_wheel USING  c_alpha
                      init3
             CHANGING wheel3.
    c1 = wheel3+idx(1).

    CONCATENATE 'C_WHEEL' w3 INTO fname.
    ASSIGN  (fname) TO <data>.
    PERFORM set_wheel USING  <data>
                             init3
                    CHANGING wheel3.
    SEARCH wheel3 FOR c1.
    idx = sy-fdpos.

    char_out = c_alpha+idx(1).

* Plugboard mapping outbound
    PERFORM plugboard USING 'O' CHANGING char_out.

* Build output string
    CONCATENATE v_temp char_out INTO v_temp.
  ENDDO.

* Put spaces back in same place as in selection screen text
  SHIFT v_source LEFT DELETING LEADING space.
  v_length = strlen( v_source ).
  CLEAR: pos, idx.

  DO v_length TIMES.
* get selection screen character
    c1 = v_source+pos(1).

    IF c1 IS INITIAL.
      CONCATENATE v_output ' ' INTO v_output RESPECTING BLANKS.
      idx = idx + 1.
      pos = pos + 1.
      CONTINUE.
    ELSE.
      sy-fdpos = pos - idx.
      c1 = v_temp+sy-fdpos(1).
      CONCATENATE v_output c1 INTO v_output.
      pos = pos + 1.
    ENDIF.

  ENDDO.


* Write source to result screen
  REFRESH lt_text.
  CALL FUNCTION 'CONVERT_STRING_TO_TABLE'
    EXPORTING
      i_string         = v_source
      i_tabline_length = 80
    TABLES
      et_table         = lt_text.

  FORMAT INTENSIFIED ON.
  WRITE / 'Input text.'.
  FORMAT INTENSIFIED OFF.
  LOOP AT lt_text.
    SHIFT lt_text-text LEFT DELETING LEADING space.
    WRITE / lt_text-text.
  ENDLOOP.

* Write result to result screen
  REFRESH lt_text.
  CALL FUNCTION 'CONVERT_STRING_TO_TABLE'
    EXPORTING
      i_string         = v_output
      i_tabline_length = 80
    TABLES
      et_table         = lt_text.
  WRITE /.
  FORMAT INTENSIFIED ON.
  WRITE / 'Output text.'.
  FORMAT INTENSIFIED OFF.
  LOOP AT lt_text.
    SHIFT lt_text-text LEFT DELETING LEADING space.
    WRITE / lt_text-text.
  ENDLOOP.

  WRITE /.
  FORMAT INTENSIFIED ON.
  WRITE / 'If you copy the output text and use that as the input text'.
  WRITE / 'with the same initial setup on the selection screen.'.
  WRITE / 'your output will be deciphered or enciphered as required'.

ENDFORM.                    "enigma
*&---------------------------------------------------------------------*
*&      Form  plugboard
*&---------------------------------------------------------------------*
FORM plugboard USING p_direction TYPE char1
               CHANGING p_char TYPE char1.
* This is a simple x to y type mapping
*  Not all charcaters have to be mapped
* EG. You could leave everything as it comes out of the wheels
* except, say, mapping A to G (and therefore G to A)
*
* The default in this pgm only map A/Z and G/H in the plugboard
* c_alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
* c_plugb = 'ZBCDEFHGIJKLNMOPQRSTUVWXYA',
*            ^     ^^                 ^

  CHECK p_plugb = 'X'. " is plugboard mapping ON

  IF p_direction = 'I'.
* Input from keyboard to wheels
    SEARCH c_alpha FOR p_char.
    p_char = c_plugb+sy-fdpos(1).
  ELSE.
* Output from wheels to lightboard
    SEARCH c_plugb FOR p_char.
    p_char = c_alpha+sy-fdpos(1).
  ENDIF.

ENDFORM.                    "plugboard
*&---------------------------------------------------------------------*
*&      Form  index_wrap
*&---------------------------------------------------------------------*
* This is used to correct the wheel index in case of wrap-around
* required to make the linear wheel string act like a circular wheel
FORM index_wrap CHANGING p_i TYPE i.
  IF p_i > 25.
    p_i = p_i - 25.
  ELSEIF p_i < 0.
    p_i = p_i + 25.
  ENDIF.
ENDFORM.                    "index_wrap
*&---------------------------------------------------------------------*
*&      Form  set_wheel
*&---------------------------------------------------------------------*
* Set wheel characters so start position charcater is at position 1.
* EG :
* Wheel 1 with start position is, say, W
* EKMFLGDQVZNTOWYHXUSPAIBRCJ
* -------------^------------
* becomes:
* WYHXUSPAIBRCJEKMFLGDQVZNTO

FORM set_wheel USING     p_wheel_in  TYPE char26
                         p_start     TYPE char1
                CHANGING p_wheel_out TYPE char26.


  DATA: l_index TYPE i,
        l_char  TYPE char1.

  CLEAR p_wheel_out.

  SEARCH c_alpha FOR p_start.
  l_index = sy-fdpos.

  DO 26 TIMES.
    IF l_index > 25.
      l_index = 0.
    ENDIF.

    l_char = p_wheel_in+l_index(1).
    CONCATENATE p_wheel_out l_char
    INTO p_wheel_out.

    l_index = l_index + 1.
  ENDDO.


ENDFORM.                    "set_wheel

Labels in this area