2

How can I write a Vigenère encryption in Qbasic without the use of arrays?
I understand the math to encrypt a message:

Ca = Ma + Kb (mod 26)

And to decrypt a message:

Ma = Ca – Kb (mod 26). 

I'm struggling with the syntax as I haven't found much information online.

β.εηοιτ.βε
  • 33,893
  • 13
  • 69
  • 83
  • 3
    Welcome to Stack Overflow. Please read about [asking questions](https://stackoverflow.com/help/asking). Please [edit] the question to include a [mre]. – Jason Aller Oct 07 '19 at 15:47

2 Answers2

2

You can solve this easily without using any arrays.

Below is my all-(Q)BASIC solution.

The MID$ function extracts one character from a string, and the ASC function converts the character into its ASCII code. Subtracting 65 produces a number in the range [0,25]. The encrypted number is turned back into a character using the CHR$ function. Hereafter the MID$ statement is used to put the encrypted character back in the string.
Because of the different lengths between the message and the encryption key, a separate iteration variable (j%) is needed to repeatedly walk through the key string.

msg$ = "ENCRYPTION"
PRINT msg$
key$ = "CLINTON"
k% = LEN(key$)
j% = 1
FOR i% = 1 TO LEN(msg$)
  a% = (ASC(MID$(msg$, i%, 1)) - 65) + (ASC(MID$(key$, j%, 1)) -65)
  MID$(msg$, i%) = CHR$(65 + a% + 26 * (a% > 25))
  j% = j% + 1 + k% * (j% = k%)
NEXT i%
PRINT msg$

The above snippet could do without one - 65 and one + 65, but I've left these in for clarity.

The decryption process is quite similar. 3 little changes are all that it takes:

j% = 1
FOR i% = 1 TO LEN(msg$)
  a% = (ASC(MID$(msg$, i%, 1)) - 65) - (ASC(MID$(key$, j%, 1)) -65)
  MID$(msg$, i%) = CHR$(65 + a% - 26 * (a% < 0))
  j% = j% + 1 + k% * (j% = k%)
NEXT i%
PRINT msg$

Running both snippets in a row produces:

ENCRYPTION
GYKERDGKZV
ENCRYPTION


What about a version of the code that can deal with spaces, punctuation marks, and accented characters?

The code is very similar and even a bit simpler:

msg$ = "This is any text that needs encrypting. So sayeth Sep Roland!"
PRINT msg$
key$ = "Blaise de Vigenère"
k% = LEN(key$)
j% = 1
FOR i% = 1 TO LEN(msg$)
  a% = ASC(MID$(msg$, i%, 1)) + ASC(MID$(key$, j%, 1))
  MID$(msg$, i%) = CHR$(a% + 256 * (a% > 255))
  j% = j% + 1 + k% * (j% = k%)
NEXT i%
PRINT msg$

j% = 1
FOR i% = 1 TO LEN(msg$)
  a% = ASC(MID$(msg$, i%, 1)) - ASC(MID$(key$, j%, 1))
  MID$(msg$, i%) = CHR$(a% - 256 * (a% < 0))
  j% = j% + 1 + k% * (j% = k%)
NEXT i%
PRINT msg$

I will not reproduce any output here because that would be a real pita...


Are these strange embedded conditions correct?

(a% + 26 * (a% > 25))

Consider the equivalent simple code:

IF a% > 25 THEN
  a% = a% - 26
ENDIF

If the a% variable is greater than 25, we need to subtract 26.
Nonetheless the (a% + 26 * (a% > 25)) form uses addition.

This so happens because a TRUE condition evaluates to -1.

  • If a% > 25 is TRUE we get (a% + 26 * -1) -> a% - 26
  • If a% > 25 is FALSE we get (a% + 26 * 0) -> a%
Sep Roland
  • 33,889
  • 7
  • 43
  • 76
1

You can simply get the ASCII value of the char as a number and then subtract the character value of A. You would get a number in the range [0, 26). Then you'd perform encryption / decryption as you've stated. To get back a valid character value then reverse and add the value of A. This works because the letters of the English alphabet (the ABC) are listed in order in ASCII.

To get the ciphertext or plaintext simply iterate over all the characters in the string (possibly after checking that it doesn't contain any other characters) and append the encrypted / decrypted character to a new string, and finally return that. Viola, no arrays, just strings, characters and numerical values.

That's all folks.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263