How to Create a Simple Encryption/Decryption Tool Using XOR in Batch Script
Let's create a basic XOR (Exclusive OR) encryption and decryption tool using Windows Batch Script. While more modern languages boast extensive cryptographic libraries, writing an encryption script natively in the Command Prompt is an exceptional exercise in bitwise arithmetic, data manipulation, and hex translation.
The XOR cipher is a symmetric key algorithm. This means the exact same script and mathematical operation used to encrypt the data are also used to decrypt it back to its original form. By mastering this concept in Batch, mid-level developers can create fast, lightweight obfuscation utilities without relying on external executing environments or installing third-party tools.
Understanding the XOR Algorithm
At its core, XOR is a bitwise operator that compares two binary digits (bits). If the bits are exactly the same (0 and 0, or 1 and 1), it outputs 0. If they are different (1 and 0), it outputs 1.
When applying XOR encryption to text, every character of a plaintext message is converted to its ASCII numerical value (such as 65 for A). That value is then XORed against a "Key" value. The resulting number represents the encrypted ciphertext character.
The beauty of XOR lies in its reversibility. If you XOR the encrypted ciphertext back against the identical key, it flawlessly returns the original plaintext. No separate decryption algorithm is needed!
Example:
Plaintext: A (ASCII 65, Binary 01000001)
Key: * (ASCII 42, Binary 00101010)
XOR Result: (ASCII 107, Binary 01101011 which is k)
Decrypting: XORing k with * returns A.
Converting Characters to ASCII in Batch
Batch does not have a native ord() or chr() function to switch between letters and ASCII numbers. Therefore, our first step before performing XOR math is creating a lookup loop to convert a character into an integer.
@echo off
setlocal EnableDelayedExpansion
title Character to ASCII Conversion
set "char=A"
:: Build ASCII map safely (32–126)
set "ASCII_MAP= "
set "ASCII_MAP=!ASCII_MAP!""#$%%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
:: Initialize
set "ascii_val=-1"
for /L %%i in (0,1,94) do (
set "map_char=!ASCII_MAP:~%%i,1!"
if "!map_char!"=="!char!" (
set /a ascii_val=%%i + 32
)
)
echo The ASCII value for !char! is !ascii_val!
pause
Because Batch handles percent signs % and exclamation marks ! as special processing variables, creating a robust ASCII map requires doubling the percent sign %% inside the string to prevent misinterpretation. Characters like ! and ^ cannot be reliably stored in the map when delayed expansion is enabled, which limits the printable range slightly.
Implementing the Bitwise XOR Operation
Once we have our plaintext integer and our key integer, we apply the XOR operator (^). In Batch script math (set /a), the caret ^ is the bitwise XOR symbol.
Single Character Encryption Example
@echo off
setlocal enabledelayedexpansion
:: Assume we successfully mapped 'A' to 65
set /a "PT_VAL=65"
:: Our encryption key numeric value (e.g. 42 for '*')
set /a "KEY_VAL=42"
:: Perform the XOR encryption
set /a "CIPHER_VAL=PT_VAL ^ KEY_VAL"
echo Encrypted Value: !CIPHER_VAL!
:: Perform the decryption (Reversing the process)
set /a "DECRYPTED_VAL=CIPHER_VAL ^ KEY_VAL"
echo Decrypted Value: !DECRYPTED_VAL!
pause
Notice how passing CIPHER_VAL through the exact same equation with KEY_VAL yielded 65 again.
Writing the Full Encryption Loop
To encrypt an entire string or file, we must construct a loop that reads a character, converts it to an ASCII integer, performs the XOR operation against the key integer, and then converts the resulting integer back into a character.
Because the resulting XOR character might be an unprintable control character (like Null, Bell, or Escape), saving the raw characters to a file can corrupt the text file. A highly professional strategy is to store the encrypted output as a string of Hexadecimal values.
@echo off
setlocal enabledelayedexpansion
set "MESSAGE=SECRET MESSAGE"
:: Single integer key for simplicity
set /a "KEY=15"
:: Build the ASCII lookup map (printable range 32-126)
:: 1. Build ASCII map safely (32–126) in correct sequence
set "ASCII_MAP= "
set ^"ASCII_MAP=!ASCII_MAP!^!"
set ^"ASCII_MAP=!ASCII_MAP!^""
set "ASCII_MAP=!ASCII_MAP!#$%%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
:: Build the hex digit reference
set "HEX_DIGITS=0123456789ABCDEF"
set "ENCRYPTED_HEX="
set "count=0"
:: -------------------------------------------------------
:: ENCRYPT_LOOP
:: -------------------------------------------------------
:ENCRYPT_LOOP
call set "char=%%MESSAGE:~!count!,1%%"
if "!char!"=="" goto DISPLAY_RESULT
:: 2. Convert char to ASCII using lookup map
set "ascii_val=-1"
for /L %%i in (0, 1, 94) do (
set "map_char=!ASCII_MAP:~%%i,1!"
if "!map_char!"=="!char!" set /a "ascii_val=%%i + 32"
)
:: Skip characters not found in the map
if !ascii_val! equ -1 (
set /a count+=1
goto ENCRYPT_LOOP
)
:: 2. Perform XOR
set /a "cipher_val=ascii_val ^ KEY"
:: 3. Convert to two-digit Hexadecimal manually
set /a "hi=cipher_val / 16"
set /a "lo=cipher_val %% 16"
set "hex_val=!HEX_DIGITS:~%hi%,1!!HEX_DIGITS:~%lo%,1!"
:: Append the hex pair to our output string
set "ENCRYPTED_HEX=!ENCRYPTED_HEX!!hex_val! "
set /a count+=1
goto ENCRYPT_LOOP
:DISPLAY_RESULT
echo Original: !MESSAGE!
echo Encrypted: !ENCRYPTED_HEX!
pause
Common Wrong Cases and Best Practices
A widespread issue when creating an XOR encryptor in Batch arises from attempting to echo unprintable ASCII results directly back to the Command Prompt window.
The Wrong Way: Echoing Control Characters Directly
If you encrypt the letter A (65) using the key 65, the resulting XOR value is 0. ASCII 0 is the Null terminator. If you try to print or write 0 (or 7 for Bell, 8 for Backspace) as a raw character to the console natively, it behaves erratically.
Wrong Code Example:
@echo off
setlocal enabledelayedexpansion
set /a "p=65"
set /a "k=65"
set /a "raw_c=p ^ k"
:: Pretend we converted raw_c (0) back to character 'char_res'
set "final=!final!!char_res!"
:: Echoing Null or Bell characters directly outputs invisible junk or beeps loudly
echo !final!
The Command Prompt will literally ding at the user (Bell) or truncate the line (Null), breaking the visible execution of your script and corrupting any output redirected to (>>) text files.
The Correct Way: Outputting Encrypted Data as Format Safe Hex
To ensure encrypted data survives text file storage and looks professional on the console, you must convert the raw mathematical result into a Hexadecimal representation before saving.
Correct Code Example:
@echo off
setlocal enabledelayedexpansion
set "HEX_DIGITS=0123456789ABCDEF"
set /a "raw_c=65 ^ 12"
:: Convert to two-digit hex using division and modulo
set /a "hi=raw_c / 16"
set /a "lo=raw_c %% 16"
:: Use the hi and lo values as indexes into the hex digit string
call set "hex=%%HEX_DIGITS:~!hi!,1%%%%HEX_DIGITS:~!lo!,1%%"
echo Encrypted Byte: !hex!
Instead of a weird symbol or an invisible break, the console prints a clean, easily copyable string like 45. This string is totally safe to store, copy, and pass back into the script for decryption later without risking terminal crash.
Conclusion
Constructing an XOR Encryption and Decryption engine using Windows Batch Scripting is a brilliant demonstration of bitwise math and data structuring in an environment not historically built for secure cryptography. By implementing a solid ASCII map conversion, evaluating the binary logic properly with the caret ^ symbol, and standardizing your encrypted outputs as printable formats to avoid catastrophic command line control breaks, your standalone cipher script will function perfectly across any modern Windows machine natively.