Vigenère Cipher

Developer(s): T.S. Thomas
Date: 198x
Type: Program
Platform(s): TS 2068

This program implements the Vigenère cipher, a classical polyalphabetic substitution cipher, offering both encoding and decoding functions. The keyword is repeated (by string concatenation in a loop at lines 150–155 and 350–355) until it matches or exceeds the length of the plaintext message, forming a running key. Encoding adds the ASCII codes of the message and key characters together, then subtracts 65 or 91 to wrap back into a printable range depending on whether the sum exceeds 155. Decoding reverses the process by subtracting key character codes and adding 65 or 91 accordingly. The program uses POKE 23658,8 to enable CAPS LOCK and POKE 23609,100 to set the keyboard repeat delay, and restricts messages to 32 characters to fit within the display column range used for output.


Program Structure

The program is divided into three functional blocks, clearly delineated by REM banners:

  1. Main menu (lines 10–60): displays a title and polls INKEY$ in a tight loop, branching to the encoder, decoder, or STOP.
  2. Encoder (lines 100–245): accepts a keyword and plaintext, builds a running key, computes ciphertext, and displays it.
  3. Decoder (lines 300–445): mirrors the encoder but subtracts key values to recover plaintext.

Cipher Algorithm

The Vigenère cipher is implemented by treating each character as its ASCII code. The running key is built by repeatedly concatenating k$ to h$ until LEN h$ >= s (lines 150–155 / 350–355). For encoding, line 190 computes c(n) = a(n) + b(n); for decoding, line 390 computes c(n) = a(n) - b(n).

The output mapping uses two thresholds to keep results in a printable letter range:

ConditionEncoder outputDecoder output
c(n) <= 155 / c(n) >= 0CHR$ (c(n)-65)CHR$ (c(n)+65)
c(n) > 155 / c(n) < 0CHR$ (c(n)-91)CHR$ (c(n)+91)

The magic constant 155 is 2 × 65 + 25 (i.e., ‘A’+’Z’), and 91 = 65 + 26, providing a one-alphabet wrap. The arithmetic assumes both message and keyword consist of uppercase ASCII letters (codes 65–90); non-uppercase input will produce unpredictable results.

Key BASIC Idioms

  • Running-key construction: the string loop LET h$=h$+k$ followed by IF LEN h$<s THEN GO TO 150 is a compact way to tile the keyword to the required length without a FOR loop.
  • Parallel numeric arrays: DIM a(s), DIM b(s), and DIM c(s) store message codes, key codes, and combined values separately, keeping the arithmetic loop (lines 170–200 / 370–400) simple and the display loop (lines 210–240 / 410–440) separate.
  • PAUSE 0 at lines 244 and 444 halts execution until any key is pressed before returning to the main menu.
  • System POKEs: line 25 uses POKE 23658,8 to force CAPS LOCK on (so uppercase entry is easier) and POKE 23609,100 to set the keyboard click/repeat parameter.

Notable Techniques and Anomalies

  • Column-per-character display: ciphertext and deciphered text are printed one character at a time with PRINT AT 14,n;, so n directly maps to the screen column. This elegantly avoids string concatenation for the output but limits messages to 32 characters (columns 1–32 of a 32-column display).
  • Menu polling bug: lines 40–60 sample INKEY$ three separate times in sequence rather than capturing it once to a variable. If a key is pressed between checks, it may be missed, and the program falls through to redraw the menu at line 60 causing a flicker loop. Saving INKEY$ to a variable at the top of the loop would be more reliable.
  • No input validation: the program does not check that the message is 32 characters or fewer, nor that all characters are uppercase letters. Lowercase or punctuation in the message or keyword will produce incorrect output or out-of-range CHR$ arguments.
  • Decoder symmetry flaw: the encoder subtracts 65 when c(n) <= 155 and 91 when c(n) > 155. The decoder mirrors this with +65 when c(n) >= 0 and +91 when c(n) < 0. This is internally consistent for the two-branch wrap, but it is not a standard modular arithmetic Vigenère and will only correctly round-trip text encoded by this same program.
  • Array re-dimensioning: DIM a(s), DIM b(s), DIM c(s) are declared fresh each time the encoder or decoder is entered (since s may differ between runs), which correctly resets them.

Image Gallery

Source Code

    5 REM Vignere Cipher by T.S.Thomas
   10 REM *******************
   11 REM **   MAIN PROG   **
   12 REM *******************
   20 BORDER 0:INK 7:PAPER 0:CLS 
   25 POKE 23658,8:POKE 23609,100
   27 PRINT AT 2,9;"VIGNERE CIPHER"
   30 PRINT AT 5,0;"PLEASE SELECT A FUNCTION:"; TAB 1;" "; TAB 1;"E - Encode"; TAB 1;"D - Decode"; TAB 1;"S - Stop"
   40 IF INKEY$="E" OR INKEY$="e" THEN GO TO 100
   50 IF INKEY$="D" OR INKEY$="d" THEN GO TO 300
   55 IF INKEY$="S" OR INKEY$="s" THEN GO TO 1000
   60 GO TO 30
   99 REM 
  100 REM *******************
  101 REM **    ENCODER    **
  102 REM *******************
  103 REM 
  104 CLS 
  105 PRINT AT 2,9;"VIGNERE CIPHER"
  106 PRINT AT 3,13;"ENCODER"
  107 PRINT AT 5,0;"ENTER A 32 CHARACTER OR LESS "; TAB 0;"MESSAGE IN CAPITAL LETTERS"
  110 INPUT "ENTER KEYWORD: "; LINE k$
  115 PRINT AT 8,1;"KEYWORD = ";k$
  120 INPUT "ENTER MESSAGE: "; LINE m$
  125 PRINT AT 10,1;"MESSAGE = ";m$
  130 LET s= LEN m$
  140 LET h$=k$
  150 LET h$=h$+k$
  155 IF LEN h$<s THEN GO TO 150
  160 DIM a(s):DIM b(s)
  165 DIM c(s)
  170 FOR n=1 TO s
  175 LET a(n)= CODE m$(n)
  180 LET b(n)= CODE h$(n)
  190 LET c(n)=a(n)+b(n)
  200 NEXT n
  210 FOR n=1 TO s
  215 PRINT AT 13,0;"CIPHERED MESSAGE BELOW:"
  220 IF c(n) <=155 THEN PRINT AT 14,n; CHR$ (c(n)-65)
  230 IF c(n)>155 THEN PRINT AT 14,n; CHR$ (c(n)-91)
  240 NEXT n
  241 PRINT AT 16,0;"PRESS ANY KEY TO CONTINUE       "; TAB 0;"                                " 
  244 PAUSE 0
  245 GO TO 10
  299 REM 
  300 REM *******************
  301 REM **    DECODER    **
  302 REM *******************
  303 REM 
  304 CLS 
  305 PRINT AT 2,9;"VIGNERE CIPHER"
  306 PRINT AT 3,13;"DECODER"
  307 PRINT AT 5,0;"ENTER A 32 CHARACTER OR LESS "; TAB 0;"MESSAGE IN CAPITAL LETTERS"
  310 INPUT "ENTER KEYWORD: "; LINE k$
  315 PRINT AT 8,1;"KEYWORD = ";k$
  320 INPUT "ENTER MESSAGE: "; LINE m$
  325 PRINT AT 10,1;"MESSAGE = ";m$
  330 LET s= LEN m$
  340 LET h$=k$
  350 LET h$=h$+k$
  355 IF LEN h$<s THEN GO TO 350
  360 DIM a(s):DIM b(s)
  365 DIM c(s)
  370 FOR n=1 TO s
  375 LET a(n)= CODE m$(n)
  380 LET b(n)= CODE h$(n)
  390 LET c(n)=a(n)-b(n)
  400 NEXT n
  410 FOR n=1 TO s
  415 PRINT AT 13,0;"DECIPHERED MESSAGE BELOW:"
  420 IF c(n)<0 THEN PRINT AT 14,n; CHR$ (c(n)+91)
  430 IF c(n) >=0 THEN PRINT AT 14,n; CHR$ (c(n)+65)
  440 NEXT n
  441 PRINT AT 16,0;"PRESS ANY KEY TO CONTINUE       "; TAB 0;"                                " 
  444 PAUSE 0
  445 GO TO 10
 1000 STOP 

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.