'===========================================================================
' Subject: ENIGMA CODER                       Date: 08-13-97 (08:25)       
'  Author: Davey W. Taylor                    Code: QB, QBasic, PDS        
'  Origin: audio.squad@mailbox.swipnet.se   Packet: ALGOR.ABC
'===========================================================================
'ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ--ÄÄÄ--Ä -ù  ù
'³                   ** ENIGMA CODER **
'³                Created by Davey W Taylor
'³
'³ The ENIGMA machine was used by the germans during the
'³ war to encrypt important messages so that the brittish
'³ could not read them if they were intercepted. It uses
'³ a very simple design and is simple to use and still
'³ it is very hard to decrypt the messages after they
'³ have been encrypted.. why? The ENIGMA machine uses a
'³ very clever way of encrypting the message. Three
'³ different rotors and reflector which all can be
'³ changed. You would also have to know the start
'³ positions of each rotor in order to decrypt the
'³ message. On top of that there was a plugboard on the
'³ front of the machine allowing the user to manually
'³ switch any of the 26 characters. Anyway, what makes
'³ it real hard to decrypt is that the rotors actually
'³ change position. After every keypress the first
'³ rotor changes position, when that one has passed through
'³ one cycle(A to Z) the second one changes and the same
'³ goes for the third one. This program uses the same way
'³ of encrypting/decrypting messages and as far as I know
'³ it should actually decrypt REAL ENIGMA messages if you
'³ know how the needed rotors were constructed. This would
'³ require some modification to the enigma: section though.
'³ More information about the ENIGMA machine can be found
'³ on the internet!
'³
'³ The above text might be a bit hard to understand since
'³ my english spelling is not very good... sorry! :)
'³ Anyway, I hopy you enjoy the program...
'ÀÄÄÄÄÄ--ÄÄù-  ù   ù
' ** If you have any comments / suggestions / questions, my email is: **
' ** audio.squad@mailbox.swipnet.se                                   **

DECLARE SUB add (rot$, alpha$)
DECLARE SUB waitkey ()
DECLARE SUB XYWrite (x%, y%, char$)

DIM rotora$(1 TO 24)                              'set variables
DIM names$(1 TO 24)
alpha$ = "ABCDEFGHIJKLMNOPQRSTUVWXYZ "
plugs$ = alpha$
rotor$ = "AAAA010101"

RESTORE enigma                                    'read rotors
FOR n% = 1 TO 24
 READ rotora$(n%)
NEXT n%

RESTORE greek                                     'read rotor names
FOR n% = 1 TO 24
 READ names$(n%)
NEXT n%

ver$ = "1.9"
SCREEN 12
COLOR 7

menu:                                             'main menu
CLS
PRINT "ENIGMA CODER " + ver$
PRINT
PRINT " L - Load File"
PRINT " S - Save File"
PRINT " P - Edit Plugboard"
PRINT " C - Change Rotors"
PRINT " I - Change Start Positions"
PRINT " F - Change Reflector"
PRINT " E - Encode"
PRINT " Q - Quit"
PRINT
PRINT " Plugbord Edited?         (     )"
PRINT " Current Rotors:          (         :         :         )"
PRINT " Current Start Positions: (    :    :    )"
PRINT " Current Reflector:       (         )"

LOCATE 12, 29
IF plugs$ <> alpha$ THEN COLOR 12: PRINT "Yes": COLOR 7 ELSE PRINT "No"
LOCATE 13, 29
PRINT names$(INSTR(alpha$, MID$(rotor$, 1, 1)))
LOCATE 13, 39
PRINT names$(INSTR(alpha$, MID$(rotor$, 2, 1)))
LOCATE 13, 49
PRINT names$(INSTR(alpha$, MID$(rotor$, 3, 1)))
LOCATE 14, 29
PRINT LTRIM$(STR$(VAL(MID$(rotor$, 5, 2))))
LOCATE 14, 34
PRINT LTRIM$(STR$(VAL(MID$(rotor$, 7, 2))))
LOCATE 14, 39
PRINT LTRIM$(STR$(VAL(MID$(rotor$, 9, 2))))
LOCATE 15, 29
PRINT names$(INSTR(alpha$, MID$(rotor$, 4, 1)))

DO
 SELECT CASE UCASE$(INKEY$)
  CASE "L"
   DO
    CLS
    PRINT "ENIGMA CODER " + ver$ + " LOAD FILE"
    PRINT
    LINE INPUT " Filename: ", file$
    IF file$ = "" THEN GOTO menu
    ok% = 1
    ON ERROR GOTO noload
    OPEN file$ FOR INPUT AS #1                    'open and check filesize,
    IF ok% = 1 THEN                               'letters etc...
     IF LOF(1) > 32000 THEN PRINT " File must not exceed 32 kbytes!": CLOSE #1
     file$ = INPUT$(LOF(1), #1)
     CLOSE #1
    END IF
    out$ = ""
    FOR n% = 1 TO LEN(file$)
     ch$ = UCASE$(MID$(file$, n%, 1))
     IF ch$ = CHR$(13) THEN ch$ = " "
     IF ch$ = CHR$(10) THEN ch$ = ""
     IF INSTR(alpha$ + extra$, ch$) = 0 THEN PRINT " File must only contain characters between A and Z!": waitkey: ERROR 0
     IF ok% = 0 THEN EXIT FOR
     out$ = out$ + ch$
    NEXT n%
    ON ERROR GOTO 0
   LOOP UNTIL ok%
   IF LEN(out$) = 0 THEN PRINT " File is empty!": waitkey: GOTO menu
   memory$ = out$
   GOTO menu
 
  CASE "S"
   DO
    CLS
    PRINT "ENIGMA CODER " + ver$ + " SAVE FILE"
    PRINT
    LINE INPUT " Filename: ", file$
    IF file$ = "" THEN GOTO menu
    ok% = 1
    ON ERROR GOTO nosave
    OPEN file$ FOR OUTPUT AS #1                   'save file
    IF ok% = 1 THEN
     PRINT #1, memory$;
     CLOSE #1
    END IF
    ON ERROR GOTO 0
   LOOP UNTIL ok%
   GOTO menu
 
  CASE "P"
   done% = 0
   DO
    CLS
    PRINT "ENIGMA CODER " + ver$ + " EDIT PLUGBOARD"
    PRINT
    PRINT " Use Letters To Swap. Ex: Pressing GA Would Swap G With A"
    PRINT " While In Swap, Press ESC To Abort"
    PRINT " Press ESC When Done Or Space To Reset"
   
    FOR n% = 1 TO 26                              'display plugboard
     p! = n% / 4.15
     CIRCLE (319 + COS(p!) * 100, 239 + SIN(p!) * 100), 5
     XYWrite 315 + COS(p!) * 120, 235 + SIN(p!) * 120, MID$(alpha$, n%, 1)
    NEXT n%
    FOR n% = 1 TO 26
     p! = n% / 4.15
     sx% = 319 + COS(p!) * 100
     sy% = 239 + SIN(p!) * 100
     p! = INSTR(alpha$, MID$(plugs$, n%, 1)) / 4.15
     ex% = 319 + COS(p!) * 100
     ey% = 239 + SIN(p!) * 100
     LINE (sx%, sy%)-(ex%, ey%), 12
    NEXT n%
   
    DO
     ok% = 1
     in$ = UCASE$(INKEY$)
     SELECT CASE in$
      CASE "A" TO "Z"
       sw$ = in$
       p! = INSTR(alpha$, sw$) / 4.15
       CIRCLE (319 + COS(p!) * 100, 239 + SIN(p!) * 100), 5, 12
       ok% = 0
       DO
        in$ = UCASE$(INKEY$)
        SELECT CASE in$
         CASE "A" TO "Z"
          swt$ = in$
          ok% = 1
         CASE CHR$(27): ok% = 2
        END SELECT
       LOOP UNTIL ok% > 0
      
       IF ok% = 1 THEN
        sp% = INSTR(alpha$, sw$)                  'calculate and swap letters
        ep% = INSTR(alpha$, swt$)
        nol% = 0
        IF MID$(plugs$, sp%, 1) <> MID$(alpha$, sp%, 1) THEN nol% = 1
        IF MID$(plugs$, ep%, 1) <> MID$(alpha$, ep%, 1) THEN nol% = 1
        IF MID$(plugs$, sp%, 1) = MID$(alpha$, ep%, 1) THEN nol% = 0
        IF nol% = 0 THEN
         s$ = MID$(plugs$, sp%, 1)
         MID$(plugs$, sp%, 1) = MID$(plugs$, ep%, 1)
         MID$(plugs$, ep%, 1) = s$
        ELSE
         BEEP                                     'beep if error
        END IF
       ELSE
        ok% = 1
       END IF
      CASE " ": plugs$ = alpha$
      CASE CHR$(27): done% = 1
      CASE ELSE: ok% = 0
     END SELECT
    LOOP UNTIL ok%
   LOOP UNTIL done%
   GOTO menu
 
  CASE "C"
   DO
    CLS
    PRINT "ENIGMA CODER " + ver$ + " CHANGE ROTORS"
    PRINT
    PRINT " Availavle Rotors:"
    PRINT "  ";
    FOR n% = 1 TO 24
     IF n% = 12 THEN PRINT CHR$(13); "  ";
     PRINT names$(n%);
     IF n% <> 24 THEN PRINT ", ";
    NEXT n%
    PRINT
    PRINT
    PRINT " Format: rotor: rotor: rotor"
    PRINT " Ex    : alfa: epsilon: pi"
    ok% = 1
    LINE INPUT " Rotors: ", rotr$
   
    IF rotr$ = "" THEN GOTO menu
    IF INSTR(rotr$, ":") = 0 THEN
     ok% = 0
    ELSE
     rot1$ = LTRIM$(RTRIM$(UCASE$(LEFT$(rotr$, INSTR(rotr$, ":") - 1))))
     rotr$ = MID$(rotr$, INSTR(rotr$, ":") + 1)
     IF INSTR(rotr$, ":") = 0 THEN
      ok% = 0
     ELSE
      rot2$ = LTRIM$(RTRIM$(UCASE$(LEFT$(rotr$, INSTR(rotr$, ":") - 1))))
      rotr$ = MID$(rotr$, INSTR(rotr$, ":") + 1)
      rot3$ = LTRIM$(RTRIM$(UCASE$(MID$(rotr$, INSTR(rotr$, ":") + 1))))
     END IF
    END IF
   LOOP UNTIL ok%
  
   o$ = ""                                        'find rotor names
   FOR n% = 1 TO 24
    IF UCASE$(names$(n%)) = rot1$ THEN o$ = o$ + MID$(alpha$, n%, 1): EXIT FOR
   NEXT n%
   IF n% = 25 THEN ok% = 0
   FOR n% = 1 TO 24
    IF UCASE$(names$(n%)) = rot2$ THEN o$ = o$ + MID$(alpha$, n%, 1): EXIT FOR
   NEXT n%
   IF n% = 25 THEN ok% = 0
   FOR n% = 1 TO 24
    IF UCASE$(names$(n%)) = rot3$ THEN o$ = o$ + MID$(alpha$, n%, 1): EXIT FOR
   NEXT n%
   IF n% = 25 THEN ok% = 0
   IF ok% = 0 THEN PRINT " Invalid rotor name!": waitkey: GOTO menu
   MID$(rotor$, 1, 3) = o$                        'change rotors
   GOTO menu
 
  CASE "I"
   DO
    CLS
    PRINT "ENIGMA CODER " + ver$ + " CHANGE START POSITIONS"
    PRINT
    PRINT " Format         : pos: pos: pos (1 to 26)"
    PRINT " Ex             : 1: 7: 5"
    ok% = 1
    LINE INPUT " Start Positions: ", rotr$
    IF rotr$ = "" THEN GOTO menu
    IF INSTR(rotr$, ":") = 0 THEN
     ok% = 0
    ELSE
     rot1% = VAL(LTRIM$(RTRIM$(UCASE$(LEFT$(rotr$, INSTR(rotr$, ":") - 1)))))
     rotr$ = MID$(rotr$, INSTR(rotr$, ":") + 1)
     IF INSTR(rotr$, ":") = 0 THEN
      ok% = 0
     ELSE
      rot2% = VAL(LTRIM$(RTRIM$(UCASE$(LEFT$(rotr$, INSTR(rotr$, ":") - 1)))))
      rotr$ = MID$(rotr$, INSTR(rotr$, ":") + 1)
      rot3% = VAL(LTRIM$(RTRIM$(UCASE$(MID$(rotr$, INSTR(rotr$, ":") + 1)))))
     END IF
    END IF
   LOOP UNTIL ok%
  
   IF rot1% < 1 OR rot1% > 26 THEN ok% = 0        'check positions
   IF rot2% < 1 OR rot2% > 26 THEN ok% = 0
   IF rot3% < 1 OR rot3% > 26 THEN ok% = 0
   IF ok% = 1 THEN
    IF rot1% < 10 THEN rot1$ = "0" ELSE rot1$ = ""
    IF rot2% < 10 THEN rot2$ = "0" ELSE rot2$ = ""
    IF rot3% < 10 THEN rot3$ = "0" ELSE rot3$ = ""
    rot1$ = rot1$ + LTRIM$(STR$(rot1%))
    rot2$ = rot2$ + LTRIM$(STR$(rot2%))
    rot3$ = rot3$ + LTRIM$(STR$(rot3%))
    o$ = rot1$ + rot2$ + rot3$
    MID$(rotor$, 5, 6) = o$                       'change positions
   ELSE
    PRINT " Invalid start positions!"
    waitkey
   END IF
   GOTO menu
 
  CASE "F"
   DO
    CLS
    PRINT "ENIGMA CODER " + ver$ + " CHANGE REFLECTOR"
    PRINT
    PRINT " Availavle Reflectors:"
    PRINT "  ";
    FOR n% = 1 TO 24
     IF n% = 12 THEN PRINT CHR$(13); "  ";
     PRINT names$(n%);
     IF n% <> 24 THEN PRINT ", ";
    NEXT n%
    PRINT
    PRINT
    ok% = 1
    LINE INPUT " Reflector: ", rotr$
    IF rotr$ = "" THEN GOTO menu
    refc$ = LTRIM$(RTRIM$(UCASE$(rotr$)))
    FOR n% = 1 TO 24                              'find reflector name
     IF UCASE$(names$(n%)) = refc$ THEN o$ = MID$(alpha$, n%, 1): EXIT FOR
    NEXT n%
    IF n% = 25 THEN ok% = 0
    IF ok% = 0 THEN PRINT " Invalid reflector name!": waitkey
   LOOP UNTIL ok%
  
   MID$(rotor$, 4, 1) = o$                        'change reflector
   GOTO menu
 
  CASE "E"
   CLS
   PRINT "ENIGMA CODER " + ver$ + " ENCODE"
   PRINT
   rot1% = VAL(MID$(rotor$, 5, 2))                'get the three rotors
   rot1$ = rotora$(INSTR(alpha$, MID$(rotor$, 1, 1))) 'and their positions
   rot2% = VAL(MID$(rotor$, 7, 2))
   rot2$ = rotora$(INSTR(alpha$, MID$(rotor$, 2, 1)))
   rot3% = VAL(MID$(rotor$, 9, 2))
   rot3$ = rotora$(INSTR(alpha$, MID$(rotor$, 3, 1)))
   refc$ = rotora$(INSTR(alpha$, MID$(rotor$, 4, 1)))
  
   FOR n% = 1 TO rot1% - 1                        'rotate all rotors to their
    n$ = LEFT$(rot1$, 1)                          'start positions
    rot1$ = MID$(rot1$, 2) + n$
    add rot1$, alpha$
   NEXT n%
   FOR n% = 1 TO rot2% - 1
    n$ = LEFT$(rot2$, 1)
    rot2$ = MID$(rot2$, 2) + n$
    add rot2$, alpha$
   NEXT n%
   FOR n% = 1 TO rot3% - 1
    n$ = LEFT$(rot3$, 1)
    rot3$ = MID$(rot3$, 2) + n$
    add rot3$, alpha$
   NEXT n%
  
   LOCATE 14, 2: PRINT STRING$(79, "-")
   ty% = 3: tx% = 2
   by% = 15: bx% = 2
  
   FOR n% = 1 TO LEN(memory$)
    VIEW PRINT 3 TO 12
    i$ = MID$(memory$, n%, 1)
    LOCATE ty%, tx%
    PRINT i$;
    ty% = CSRLIN: tx% = POS(0)
    IF tx% = 1 THEN tx% = 2
    VIEW PRINT 15 TO 24
    o$ = i$
   
    IF o$ <> " " THEN
     o$ = MID$(plugs$, INSTR(alpha$, o$), 1)      'this part is the actual
     o$ = MID$(rot1$, INSTR(alpha$, o$), 1)       'encoding. This is the
     o$ = MID$(rot2$, INSTR(alpha$, o$), 1)       'way the electricity would
     o$ = MID$(rot3$, INSTR(alpha$, o$), 1)       'flow through a real enigma
     o$ = MID$(refc$, INSTR(alpha$, o$), 1)       'machine: first through the
     o$ = MID$(rot3$, INSTR(alpha$, o$), 1)       'plugbord then through the
     o$ = MID$(rot2$, INSTR(alpha$, o$), 1)       'rotors, through the
     o$ = MID$(rot1$, INSTR(alpha$, o$), 1)       'reflector and back again!
     o$ = MID$(plugs$, INSTR(alpha$, o$), 1)
     MID$(memory$, n%, 1) = o$
    END IF
   
    FOR z% = 1 TO INSTR(alpha$, o$)
     LOCATE by%, bx%: PRINT MID$(alpha$, z%, 1);
    NEXT z%

    by% = CSRLIN: bx% = POS(0)
    IF bx% = 1 THEN bx% = 2
    IF o$ <> " " THEN
     n$ = LEFT$(rot1$, 1)                         'rotate rotor 1
     rot1$ = MID$(rot1$, 2) + n$
     add rot1$, alpha$
     rot1% = rot1% + 1
     IF rot1% = 27 THEN
      rot1% = 1
      n$ = LEFT$(rot2$, 1)                        'rotate rotor 2
      rot2$ = MID$(rot2$, 2) + n$
      add rot2$, alpha$
      rot2% = rot2% + 1
      IF rot2% = 27 THEN
       rot2% = 1
       n$ = LEFT$(rot3$, 1)                       'rotate rotor 3
       rot3$ = MID$(rot3$, 2) + n$
       add rot3$, alpha$
       rot3% = rot3% + 1
       IF rot3% = 27 THEN rot3% = 1
      END IF
     END IF
    END IF
  
   NEXT n%
   VIEW PRINT
   LOCATE 25, 60
   PRINT "Press Any Key!"
   waitkey
   GOTO menu
 
  CASE "Q"
   WIDTH 80, 25
   PRINT "Thank you for using the ENIGMA CODER!"
   END
 END SELECT
LOOP

noload:                                           'file load error handling
ok% = 0
PRINT " Can't load file!"
waitkey
RESUME NEXT

nosave:                                           'file save error handling
ok% = 0
PRINT " Can't save file!"
waitkey
RESUME NEXT

greek:                                            'the greek alphabet
                                                  '(used as rotor names)
DATA Alpha, Beta, Gamma, Delta, Epsilon, Zeta, Eta, Teta, Jota, Kappa, Lambda
DATA My, Ny, Ksi, Omikron, Pi, Ro, Sigma, Tau, Ypsilon, Fi, Chi, Psi, Omega

enigma:                                           'information on the wiring
                                                  'of each rotor
DATA QXKSGVERLWCINMZYAHDUTFJBPO
DATA IXLOHQUEAMWCJTDSFYPNGZKBRV
DATA IMPGHVDEAUZQBTRCLOYNJFXWSK
DATA JXYRKUNVLAEIZGSWTDOQFHPBCM
DATA KGLHZQBDSTACNMURFPIJOYXWVE
DATA QMVIGLEJDHWFBSZXAUNYRCKPTO
DATA DQMAVTLKYRHGCONSBJPFWEUZIX
DATA GJUVZTARPBMQKSWILHNFCDOYXE
DATA ODTBKMIXGZEWFSAYRQNCVULHPJ
DATA IMRTKJNLAFEHBGSUWCODPZQYXV
DATA IRMNXYWVAZQOCDLSKBPUTHGEFJ
DATA DQOAVXSYULMJKTCZBWGNIERFHP
DATA MXNJQZVWYDRUACPOEKTSLGHBIF
DATA PDIBKRJQCGESZONAHFLXWYUTVM
DATA QHXLYTUBOMVDJZISAWPFGKRCEN
DATA CXATHNUEQWZYPFVMISRDGOJBLK
DATA EPNYAXITGRUSQCZBMJLHKWVFDO
DATA MYWSJVNIHELKAGZTXUDPRFCQBO
DATA XCBRYLITGMNFJKWQPDZHVUOAES
DATA FLSQOAZXKYIBPUEMDVCWNRTHJG
DATA OLRGJYDSNEVBWIATXCHPZKMQFU
DATA LSOEDKPYRQFAWZCGJIBXVUMTHN
DATA COALZWJMPGTDHUBIVSRKNQFYXE
DATA PZYUWTRVOSMXKQIANGJFDHELCB

SUB add (rot$, alpha$)
 FOR n% = 1 TO LEN(rot$)
  i% = INSTR(alpha$, MID$(rot$, n%, 1)) - 1
  IF i% = 0 THEN i% = 26
  MID$(rot$, n%, 1) = MID$(alpha$, i%, 1)
 NEXT n%
END SUB

SUB waitkey
 DO: LOOP WHILE INKEY$ = ""
END SUB

SUB XYWrite (x%, y%, char$)
 DEF SEG = &HF000
 FOR py% = 0 TO 7
  r% = PEEK(&HFA63 + 11 + (ASC(char$) * 8) + py%)
  FOR px% = 0 TO 7
   IF r% AND (2 ^ px%) THEN PSET ((7 - px%) + x%, py% + y%)
  NEXT px%
 NEXT py%
 DEF SEG
END SUB
