Cryptography
Encryption vs Encoding vs Hashing: What Each One Does
Separate encoding, encryption and hashing with Base64, SHA-256 and OpenSSL labs. Learn why Base64 is not protection and hashes are one-way.
The Caesar cipher shifts each letter a fixed number of places. Encrypt HELLO to KHOOR by hand, reverse it, and see why it fails.
The Caesar cipher is a substitution cipher. It replaces each letter with another letter a fixed number of positions away in the alphabet. Shift every letter three places forward and HELLO becomes KHOOR. The name comes from Julius Caesar, who is traditionally said to have used a shift like this in his own messages. It is simple enough to work by hand, and that simplicity is why it offers almost no security.
Write the alphabet in one row. Write the same alphabet shifted by three in a second row, wrapping around after Z:
Plain: ABCDEFGHIJKLMNOPQRSTUVWXYZ
Shift: DEFGHIJKLMNOPQRSTUVWXYZABCTo encrypt, find each plaintext letter in the top row and copy the letter directly below it. H becomes K, E becomes H, L becomes O, and O becomes R. So HELLO becomes KHOOR. The key is the shift amount, here 3.
Spaces, digits and punctuation are not in the A to Z alphabet. A teaching version can leave them unchanged, and the Python code below does that.
Decryption is the same table read in reverse. Shift each letter three places backward, which is the same as shifting it 23 places forward:
KHOOR → HELLOFor a given key, each plaintext letter maps to exactly one ciphertext letter and the reverse mapping is just as unambiguous. That is why the cipher can be undone once you know the key.
The English alphabet has 26 letters, so shifts repeat every 26 positions. A shift of 29 does the same thing as a shift of 3:
29 mod 26 = 3A shift of −3 does the same thing as a shift of 23. When you write code, take the shift modulo 26 so that any integer works.
This function shifts only the letters A to Z and a to z, leaves everything else alone, and wraps around with modulo 26. It uses ord and chr to convert between letters and numbers:
def caesar(text, shift):
out = []
for ch in text:
if ch.isascii() and ch.isalpha():
base = ord('A') if ch.isupper() else ord('a')
out.append(chr((ord(ch) - base + shift) % 26 + base))
else:
out.append(ch)
return ''.join(out)
print(caesar("HELLO", 3))
print(caesar("KHOOR", -3))
print(caesar("KHOOR", 23))
print(caesar("HELLO", 29))
print(caesar("ATTACK AT DAWN", 3))
print(caesar(caesar("Hello, World!", 13), 13))
print(caesar("Hello, World!", 13))
print(caesar("hello, world", 3))
print(caesar("KHOOR", 26 - 3) == caesar("KHOOR", -3))
print(sum(1 for s in range(1, 26) if caesar("KHOOR", s) == "HELLO"))
print(caesar("HELLO", 3) == caesar("HELLO", 29))Output from running that script:
KHOOR
HELLO
HELLO
KHOOR
DWWDFN DW GDZQ
Hello, World!
Uryyb, Jbeyq!
khoor, zruog
True
1
TrueThe output confirms the earlier sections. Shifts of −3 and 23 agree, and so do 3 and 29. Of the shifts 1 to 25, only one turns KHOOR back into HELLO. Applying shift 13 twice returns the original text, which is the ROT13 case described below.
With a 26-letter alphabet, there are only 25 shifts that change the text. An attacker can try every one of them and check which result is readable. For English text, the readable result is easy to spot, so the attack takes almost no effort.
Letter frequencies also survive the shift. In English, E is common and Z is rare, so a ciphertext where one letter appears far more often than others is a strong hint. Even without trying every shift, the letter counts point to the key.
The cipher is useful for learning the vocabulary of cryptography: plaintext, ciphertext, key, substitution and brute force. It must not protect passwords, customer data, API keys or private files. Real encryption uses standardized algorithms, properly generated keys and careful key management. The NIST glossary entry for cryptography gives the formal definitions of the field.
ROT13 is a Caesar cipher with a shift of 13. It is its own inverse: applying it twice returns the original text, because 13 + 13 = 26 and a full trip around the alphabet changes nothing. The output of ROT13 on Hello, World! is Uryyb, Jbeyq!, as shown above.
ROT13 is used to hide spoilers or punchlines from a casual glance. It offers no real protection, because anyone who knows the method can read it in seconds.
Encrypt ATTACK AT DAWN by hand with a shift of 3, keeping the spaces. Compare your answer with this:
DWWDFN DW GDZQThen change the shift in the Python function and run it on the same text. Try shift 0, shift 26 and shift 13, and predict each result before you run it. Keep your test text synthetic or your own, and keep the exercise on your own machine.
When you are ready, the next article, Caesar cipher in Python, builds on this function with input handling and tests.
Further reading: the NIST glossary entry for cryptography and the Python documentation for ord and chr.
Cryptography
Separate encoding, encryption and hashing with Base64, SHA-256 and OpenSSL labs. Learn why Base64 is not protection and hashes are one-way.
Cryptography
Why fast hashes fail for passwords, what salts and work factors do, and how to hash and verify with Argon2id in Python using argon2-cffi.
Cryptography
Public and private keys from zero: what a signature proves, why the private key stays secret, and an Ed25519 lab where a changed file fails.