Howdy, history buffs and secret code enthusiasts! Today, we’re diving into the fascinating world of Caesar’s Cipher, one of the oldest and simplest forms of encryption.
So, picture this: it’s ancient Rome, and Julius Caesar needs to send super-secret messages to his generals on the battlefield. What does he do? Well, he comes up with a genius idea! He shifts each letter in his message a certain number of places down the alphabet. For example, with a shift of 3, “A” becomes “D,” “B” becomes “E,” and so on.
This sneaky technique, known as Caesar’s Cipher (or Caesar’s Shift), allowed Caesar to keep his messages safe from prying eyes.
So, let’s say you would like to encrypt the message Hello, World! with a shift (or key) of 1 – yeah, I know, even a 3 year old could decipher that, but this makes the illustration below easier to make, ok? Don’t judge me – this is what would happen:

And you would have the encrypted (LOL) message: Ifmmp, Xpsme!
In cryptography, the original message is called Plain Text and the encrypted message is called Cipher Text.
Ok, I did mentioned this was created in the Ancient Rome, right? Today this is definitively not a safe way to encrypt anything, especially anything digital because it’s easy to break by brute force.
, it’s still a good and fun exercise if you are learning to code. So let’s dig into it!
First, let’s think a bit about how we can implement this in plain English
- Get a message to be encrypted
- get a key between 1 and 25
- iterate through the message provided and shift each letter by the shift/key value provided
- encrypt the message by replacing each original letter in the message with the shifted letter
- Return the result
To get into the actual code I would like to first introduce you to something called ASCII Codes. If you haven’t heard of it, ASCII, an acronym for American Standard Code for Information Interchange, is a character encoding standard for electronic communication. ASCII codes represent text in computers, telecommunications equipment, and other devices.
ASCII Chart
Here’s the basic chart:

So, as you can see, each character has a correspondent number. There’s a decimal, hexadecimal, octal (and a binary not showing here) conversion columns and the character column. For now we will use the char and the dec columns only.
Note that A corresponds to the number 65 in the Dec column, Z to the number 90, a to 97 and z to 122. These are important numbers for us right now.
So, based on this, we can use these numbers to make the shift we want. We can convert the letters in the message into the correspondent numbers, add the shift and the convert them back to the letters corresponding to the new number, et voilà.
Does it make sense?
Let’s break it down. The word Hello would be equal to 72-101-108-108-111
The shift will be 4 so the result would be: 76 – 105 – 112 – 112 – 115

Then you convert it back from numbers to letters and you get: Lipps
All good, pretty straightforward, right? (Not really, and you will find out why later, but for this first iteration let’s pretend it is).
The actual code (sort of)
Starting from a pretty basic premise, we have a variable message that contains the message to be encrypted, the key variable that contains the shift, and a variable called result, which for now it’s an empty string and it’s what’s gonna hold the final result.
message = 'Hello, World!'
key = 3
result = ''
Next, we can iterate through each character of the message an do some magic. First we use a Python built-in method called ord(). This is how it works:
Given a string representing one Unicode character, return an integer representing the Unicode code point of that character. For example,
ord('a')returns the integer97andord('€')(Euro sign) returns8364. (source)
We then save the corresponding code for each character in a variable called
asscii_char. Now, the character in the message is an int, so we can perform arithmetic operations on them.On line 10, we create a new variable that will hold the shifted numeric code, so the encrypted code. We called it
new_ascii_charand set its value to the original ascii code plus the key (shift).Then we go the opposite direction using another built-in method in Python called
chr()which converts an integer into the corresponding unicode character.Return the string representing a character whose Unicode code point is the integer i. For example,
chr(97)returns the string'a', whilechr(8364)returns the string'€'. (source)We save the new unicode char into a variable called
new_char. Last but not least we append each new char into the variable we created at the top of the code,result.

Just as a visual aid, I am printing each variable in the loop and then I print the final result. This way you can see the correspondance:
Output for the code above has the original character, the corresponded ASCII code, the new ASCII code after the shift and the corresponded character in that order:
H 72 75 K
e 101 104 h
l 108 111 o
l 108 111 o
o 111 114 r
, 44 47 /
32 35 #
W 87 90 Z
o 111 114 r
r 114 117 u
l 108 111 o
d 100 103 g
! 33 36 $
Khoor/#Zruog$
Well, it works, at a very basic level. But something doesn’t quite add up. The final result is: Khoor/#Zruog$
So the code did not account for a few things spaces and special characters (, and !).
So, can we add a check to make sure we are only shifting the characters between A and Z?
Python built-in methods to the rescue, we can use char.isalpha() and that would do the trick. It simply check if a character is between A-Z or a-z.
So, we can wrap the logic we have now in an if statement, checking if each character is part of the alphabet, if it is, we apply the shift logic and append to the result. If it’s not, we append to the result as it is!

And the output is: Khoor, Zruog!
Much better, right?
what if we change the key a little bit, let’s say to… 8. We would get the encrypted message like this: Olssv, ^vysk!
Why? Because while we had a small shift, everything would stay within the range between 65 and 90 (for that specific message).
So, same message and a shift of 8 we would have the following output:
Pmttw, _wztl!
Even though we checked for alphabetic characters, we ended up with the _ in the beginning of the second word because the uppercase W shifted by 8 is equal to the underscore character (dec 95). We don’t want that. We need the whole thing to loop back to the letter A once it gets to Z.
What now?
For now, we can force the loop by subtracting 26 from the shifted code it it is greater than 90, which is the dec code for Z.
But this only solve part of the problem and actually creates more. Because, it fixes the issue for our W but all other characters are lowercase, so when you subtract 26 it fixes the uppercase characters but it messes up the lowercase ones.
We can be lazy a force the message to uppercase and “fix” the issue with one simple method:

And then we would have the right encrypted message, although, all in caps, so you might think the person sending the message to you is screaming at you, but it’s just the lazy code: PMTTW, EWZTL!
We can, handle this with yet another check ( this is getting convoluted, but it’s just to illustrate the steps) if each of the character is either upper or lowercase.

And it works!! The output for this code is finally: Pmttw, Ewztl!
We can now clean the code a bit:

Or even better, you can extract everything into a function so you can reuse it:

And that’s it. There are some things you can do, like ask for the user’s input for both the message and they key, verify if the key is between 1 and 25, use the decoder method to encrypt the message, etc.

