Skip to main content

How to Implement Vigenère Cipher in Batch Script

The Vigenère cipher is a polyalphabetic encryption method that uses a keyword to shift letters in a message, applying a different Caesar shift for each character based on the corresponding key letter. Unlike a simple cipher that uses the same shift for every character, Vigenère repeats the keyword and combines it with your plaintext to produce encrypted text.

This guide shows you how to implement the Vigenère cipher entirely in a Windows Batch script, using basic Batch techniques like string parsing, alphabet indexing, and modulo arithmetic to encrypt and decrypt messages with a keyword.

Understanding the Vigenère Cipher

Before we write the code, let us break down how the cipher mathematically operates.

Unlike a Caesar cipher which shifts every letter by the same amount, the Vigenère cipher shifts each letter based on a "Keyword."

  1. The Plaintext: The message you want to encrypt (e.g., HELLO).
  2. The Keyword: A secret word used to dictate the specific shift values (e.g., KEY).
  3. The Alignment: The keyword is repeated to match the length of the plaintext (e.g., KEYKE).
  4. The Math: Each letter is converted to a number where A=0, B=1 ... Z=25. The encrypted letter index is calculated as: (PlaintextIndex + KeywordIndex) % 26

For example:

  • H (7) + K (10) = 17 (R)
  • E (4) + E (4) = 8 (I)
  • L (11) + Y (24) = 35 % 26 = 9 (J)

Setting Up the Batch Script

Batch does not natively understand that "A" is the 1st letter of the alphabet and "Z" is the 26th. Therefore, we must create a mapping array manually.

@echo off
setlocal enabledelayedexpansion
title Vigenere Cipher Tool

:: Create the Alphabet Map
set "ALPHABET=ABCDEFGHIJKLMNOPQRSTUVWXYZ"
for /L %%i in (0,1,25) do (
set "char=!ALPHABET:~%%i,1!"
rem Map letter to index: letter_A=0, letter_B=1...
set "letter_!char!=%%i"
rem Map index to letter: index_0=A, index_1=B...
set "index_%%i=!char!"
)
info

By establishing a two-way mapping array (letter_A=0 and index_0=A), we can easily convert any character to its mathematical index, perform the Vigenère shift, and immediately convert the resulting number back into a character.

Implementing the Encryption Logic

To properly evaluate variables inside variables (like grabbing index !text_pos! of string !PLAINTEXT!), we avoid the slow call set command and instead use a FOR loop trick. This evaluates the inner variable securely in a single execution pass.

We also include an uppercasing block, as our array only maps uppercase letters.

@echo off
setlocal enabledelayedexpansion

:: 1. Define variables
set "plaintext=HELLO WORLD"
set "keyword=SECRET"
set "alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZ"

echo Plaintext: %plaintext%
echo Keyword: %keyword%

:: 2. Calculate the length of the keyword
set "lenKey=0"
:lenLoop
if "!keyword:~%lenKey%,1!" neq "" (
set /a lenKey+=1
goto lenLoop
)

:: 3. Setup variables for the encryption loop
set "ciphertext="
set "pLen=0"
set "kIdx=0"

:: 4. Main Encryption Loop
:encLoop
:: Get current plaintext character
set "char=!plaintext:~%pLen%,1!"
if "!char!" equ "" goto endLoop

:: If it is a space, append a space and skip encryption for this char
if "!char!" equ " " (
set "ciphertext=!ciphertext! "
set /a pLen+=1
goto encLoop
)

:: Find the numeric index of the plaintext letter (0-25)
set "pVal=-1"
for /L %%i in (0,1,25) do (
if "!char!" equ "!alpha:~%%i,1!" set "pVal=%%i"
)

:: Find the numeric index of the current keyword letter (0-25)
set /a "kPos=kIdx %% lenKey"
set "kChar=!keyword:~%kPos%,1!"
set "kVal=-1"
for /L %%i in (0,1,25) do (
if "!kChar!" equ "!alpha:~%%i,1!" set "kVal=%%i"
)

:: 5. Calculate new encrypted letter (pVal + kVal) mod 26
set /a "cVal=(pVal + kVal) %% 26"

:: Extract the new letter from the alphabet using a FOR loop trick
for %%V in (!cVal!) do set "cipherChar=!alpha:~%%V,1!"

:: Append to ciphertext and increase counters
set "ciphertext=!ciphertext!!cipherChar!"
set /a pLen+=1
set /a kIdx+=1

goto encLoop

:endLoop
echo Ciphertext: !ciphertext!
pause

Implementing the Decryption Logic

Decryption follows the exact same process, but the mathematical formula changes to reverse the shift. Because Batch handles negative modulo operations poorly, we add 26 before performing the modulo to ensure a positive result.

Decryption Formula: (CiphertextIndex - KeywordIndex + 26) % 26

@echo off
setlocal enabledelayedexpansion

set "CIPHERTEXT=ZINCS PGVNU"
set "KEYWORD=SECRET"

:: --- FIX: Create the Alphabet Dictionary mappings ---
:: This sets letter_A=0 ... letter_Z=25 AND index_0=A ... index_25=Z
set "alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZ"
for /L %%i in (0,1,25) do (
for %%a in ("!alpha:~%%i,1!") do (
set "letter_%%~a=%%i"
set "index_%%i=%%~a"
)
)
:: ----------------------------------------------------

set "DECRYPTED="
set "key_pos=0"
set "text_pos=0"

:DECRYPT_LOOP
:: Get current ciphertext character
for %%P in (!text_pos!) do set "char=!CIPHERTEXT:~%%P,1!"
if "!char!"=="" goto END_DECRYPT

:: Lookup its numeric value using our dictionary
set "c_val="
for %%C in ("!char!") do set "c_val=!letter_%%~C!"

:: If it's a space or symbol (not in dictionary), skip decryption
if not defined c_val (
set "DECRYPTED=!DECRYPTED!!char!"
set /a text_pos+=1
goto DECRYPT_LOOP
)

:: Get keyword character
for %%K in (!key_pos!) do set "keychar=!KEYWORD:~%%K,1!"
if "!keychar!"=="" (
set "key_pos=0"
set "keychar=!KEYWORD:~0,1!"
)
for %%K in ("!keychar!") do set "k_val=!letter_%%~K!"

:: Perform Decryption Math: (C - K + 26) % 26
set /a "p_val=(c_val - k_val + 26) %% 26"

:: Convert number back to letter using our dictionary
for %%V in (!p_val!) do set "plainchar=!index_%%V!"
set "DECRYPTED=!DECRYPTED!!plainchar!"

:: Increment positions
set /a text_pos+=1
set /a key_pos+=1
goto DECRYPT_LOOP

:END_DECRYPT
echo Ciphertext: %CIPHERTEXT%
echo Keyword: %KEYWORD%
echo Decrypted: !DECRYPTED!
pause

Common Wrong Cases and Best Practices

A major stumbling block when performing string indexing mathematically in Batch is handling "space" characters or punctuation.

The Wrong Way: Ignoring Spaces in Input

If your script attempts to evaluate a space using the alphabet map without verification, it breaks the mathematical evaluation:

:: The script looks up the numeric value of a space
:: It evaluates to empty/undefined.
set "p_val="

:: The script naively attempts math
set /a "c_val=(p_val + k_val) %% 26"

What Happens: Because you are explicitly referencing the variable name inside set /a, Batch natively treats any undefined variable as 0. Therefore, the math invisibly becomes (0 + k_val) % 26. The space is mathematically treated as the letter "A" (Index 0). Your script will output a corrupted letter in place of the space, misaligning the keyword for the remainder of the sentence.

note

If you were to use strict delayed expansion like !p_val!, the script would instantly crash with a "Missing operand" error.

The Correct Way: Safely Bypassing Non-Alphabetic Characters

As seen in the primary code block above, you must check if the character actually successfully resolved to an alphabet index (if not defined p_val). If it is a space or punctuation, you append it directly to the ciphertext unmodified and skip the mathematical evaluation. Crucially, you do not advance key_pos, ensuring the keyword alignment stays mathematically sound with the actual letters.

Conclusion

Building a Vigenère Cipher in Windows Batch Script is a phenomenal exercise in data mapping and algorithmic flow. By translating characters into numerical indexes dynamically via variables, you can accomplish surprising feats of computation native to the command prompt.

Remember to construct strict validation boundaries around your textual inputs, force uppercase normalization, and ensure that spaces do not corrupt your modulo arithmetic arrays. With these tools, you can successfully encrypt and decrypt data robustly on any Windows environment natively.