'This program implements a simulation of the famous ENIGMA cipher
'machine which was used by the Germans before and during WWII.
'Information used in writing the program was obtained from the
'following references:
'
' Garlinski, Joseph, The Enigma War. Charles Scribner's
' Sons, New York, NY, 1980.
' Diffie,W. and M.E. Hellman, "Privacy and Authentication:
' An Introduction to Cryptography", Proc. IEEE, vol. 67,
' No. 3, March 1979, pp. 397-427
'
'The original ENIGMA machine operated something like a typewriter.
'The cipher clerk would press a key corresponding to a plaintext
'letter, and a light would light up to indicate the ciphertext
'letter. This program operates on sequential ASCII files. You choose
'the file to you wish to encrypt, and where you would like the
'output writtem, and the program does the rest. The program
'encrypts only capital letters, and ignores any other characters
'which may be present in the input file.
'
'The file DATA.RND contains data for ten rotors and three reflectors.
'You choose which three rotors and which reflector you wish to use.
'The connections for the rotors and reflectors were generated randomly.
'
'This program is released to the public domain with the understanding
'that it shall not be sold or resold for profit.
'
'If you have any comments, write to:
'
' John A. Shonder
' P.O. Box 4102
' Oak Ridge, TN 37830
'
'
DEFINT A-N, P-Z
OPEN "R", #1, "DATA.RND", 1
FIELD #1, 1 AS F$
'DATA.RND contains the connections for the rotors and reflectors
DIM W(1 TO 4, 0 TO 25), IW(1 TO 3, 0 TO 25), N(3), P(0 TO 25)
'Array W implements the forward rotor and reflector connections
'Array IW implements the inverse of the rotor connections
'Array N holds the initial rotor positions
'Array P implements the plug connections
KEY OFF
CLS
LOCATE 12, 7
LOCATE 10, 32: PRINT "ENIGMA SIMULATOR"
LOCATE 12, 27: PRINT "Written by John A. Shonder"
LOCATE 14, 28: PRINT "Press any key to begin."
130 Q$ = INKEY$: IF Q$ = "" THEN 130
CLS
PRINT TAB(32); "ROTOR SELECTION"
PRINT
PRINT " The Enigma uses three rotors, one each in positions one, two, and three."
PRINT "The basket contains ten rotors labeled 0 through 9. Pick any three."
PRINT : PRINT
FOR I = 1 TO 3
210 'Get the connections for each rotor
PRINT "Rotor to be used in position"; I;
INPUT X
IF X < 0 OR X > 9 THEN PRINT "Enter a number from 0 to 9.": GOTO 210
LOL = 26 * X
FOR J = 0 TO 25: GET #1, LOL + J + 1: W(I, J) = ASC(F$): NEXT J
NEXT I
LOCATE 20, 27: PRINT "PRESS ANY KEY TO CONTINUE"
310 Q$ = INKEY$: IF Q$ = "" THEN 310
CLS
PRINT TAB(30); "REFLECTOR SELECTION"
PRINT
PRINT " The basket also contains three different reflectors labeled 1 through 3."
PRINT "Choose any one."
PRINT
'Get the connections for the reflector
380 INPUT "Which reflector"; X
IF X < 1 OR X > 3 THEN PRINT "Enter a number from 1 to 3.": GOTO 380
LOL = 26 * (X + 9) + 1
FOR I = 0 TO 25: GET #1, LOL + I: W(4, I) = ASC(F$): NEXT I
CLOSE #1
LOCATE 20, 27: PRINT "PRESS ANY KEY TO CONTINUE"
470 Q$ = INKEY$: IF Q$ = "" THEN 470
CLS
PRINT TAB(33); "RING SETTINGS"
PRINT
PRINT " The ring on each rotor is initially set to position 26. Enter the setting"
PRINT "for each ring. Enter an integer between 1 and 26."
PRINT
FOR I = 1 TO 3
550 PRINT "Initial settting of rotor"; I;
INPUT X
IF X < 1 OR X > 26 THEN PRINT "Enter a number between 1 and 26.": GOTO 550
FOR J = 0 TO 25: W(I, J) = (W(I, J) + X) MOD 26: NEXT J
NEXT I
LOCATE 20, 27: PRINT "PRESS ANY KEY TO CONTINUE"
640 Q$ = INKEY$: IF Q$ = "" THEN 640
CLS
PRINT TAB(29); "INITIAL ROTOR SETTINGS"
PRINT
PRINT " Enter the initial setting for each rotor. Enter a capital letter."
PRINT : PRINT
FOR I = 1 TO 3
710 PRINT "Initial position of rotor"; I;
INPUT Q$: N(I) = ASC(Q$) - 65: IF ((N(I) < 0) OR (N(I) > 25)) THEN PRINT "Enter a capital letter.": GOTO 710
730 IF W(I, 0) = N(I) THEN 800
T = W(I, 25): FOR J = 25 TO 1 STEP -1: W(I, J) = W(I, J - 1): NEXT J: W(I, 0) = T
GOTO 730
800 FOR J = 0 TO 25: IW(I, W(I, J)) = J: NEXT J
NEXT I
LOCATE 20, 27: PRINT "PRESS ANY KEY TO CONTINUE"
860 Q$ = INKEY$: IF Q$ = "" THEN 860
CLS
PRINT TAB(32); "PLUG CONNECTIONS"
PRINT
PRINT " Now set the plug connections. The Enigma can be set with from zero to"
PRINT "thirteen plugs. At the prompt, enter the pair of letters to be connected,"
PRINT "for example, AX. Enter a carriage return when you are finished."
PRINT
FOR I = 0 TO 25: P(I) = -1: NEXT I
FOR I = 1 TO 13
960 PRINT "Plug connection "; I; : INPUT A$
IF A$ = "" THEN 1080
P1$ = LEFT$(A$, 1): P1 = ASC(P1$) - 65
P2$ = RIGHT$(A$, 1): P2 = ASC(P2$) - 65
IF ((P1 < 0) OR (P1 > 25) OR (P2 < 0) OR (P2 > 25)) THEN PRINT "Enter a pair of capital letters.": GOTO 960
IF P1 = P2 THEN PRINT "The two letters must be distinct.": GOTO 960
IF (P(P1) <> -1) OR (P(P2) <> -1) THEN PRINT "One of the letters you entered has already been used. Enter a different pair.": GOTO 960
P(P1) = P2
P(P2) = P1
NEXT I
1080 FOR I = 0 TO 25
IF P(I) = -1 THEN P(I) = I
NEXT I
LOCATE 20, 27: PRINT "PRESS ANY KEY TO CONTINUE"
1120 Q$ = INKEY$: IF Q$ = "" THEN 1120
CLS
LOCATE 11, 29: INPUT "Input file name"; IN$
LOCATE 12, 29: INPUT "Output file name"; OT$
OPEN IN$ FOR INPUT AS #1
OPEN OT$ FOR OUTPUT AS #2
X = 0
CLS
LOCATE 12, 33: PRINT "Processing..."
O1 = TIMER
1220 IF EOF(1) THEN 1260
LINE INPUT #1, TX$
GOSUB 1310 'Process a line of text
GOTO 1220 'Read another line
1260 CLOSE #1: CLOSE #2
O2 = TIMER
LOCATE 12, INT((59 - LEN(OT$)) / 2): PRINT "File "; OT$; " has been written"
OEL = O2 - O1
PRINT TAB(30); "Elapsed time:"; : PRINT USING "###.##"; OEL; : PRINT " sec."
PRINT TAB(28); X; "Characters processed."
PRINT TAB(26); "Average speed: ";
PRINT USING "##.#"; 1000 * OEL / X;
PRINT " ms/char."
END
1310 'This subroutine processes one line of text
FOR I = 1 TO LEN(TX$)
W = ASC(MID$(TX$, I, 1)) - 65'Pick off a character and convert to integer
IF (W < 0) OR (W > 25) THEN 1470'If not a capital letter, get next character
U = P(W)'Send character through plug connection
FOR J = 1 TO 4: U = W(J, U): NEXT J'Send character through rotors and reflector
FOR J = 3 TO 1 STEP -1: U = IW(J, U): NEXT J'Send character back through rotors
U = P(U) + 65: C$ = CHR$(U)'Send character through plug connection
X = X + 1'Count characters for reference
PRINT #2, C$; 'Print transformed character to output file
IF X MOD 5 = 0 THEN PRINT #2, " "; 'Print in blocks of five
IF X MOD 65 = 0 THEN PRINT #2, ""'Print 13 blocks per line
R = 3: GOSUB 1490'Increment rotor 3
IF W(3, 0) <> N(3) THEN 1470'Check if rotor 3 has made a complete revolution
R = 2: GOSUB 1490'If so, then increment rotor 2
IF W(2, 0) <> N(2) THEN 1470'Check if rotor 2 has made a complete revolution
R = 1: GOSUB 1490'If so, then increment rotor 1
1470 NEXT I
RETURN
1490 'This subroutine increments the rotors
T = W(R, 25): FOR J = 25 TO 1 STEP -1: W(R, J) = W(R, J - 1): NEXT J: W(R, 0) = T
FOR J = 0 TO 25: IW(R, J) = (IW(R, J) + 1) MOD 26: NEXT J
RETURN