Lesson 2 of 5Exploring computer science
Exploring computer science · Lesson 2 · 45 minutes
Secret codes – Caesar and Vigenère
What you'll learn
- Understand and program the Caesar cipher
- See why Caesar is easy to crack
- Encrypt more securely with a keyword using Vigenère
Secret messages
More than 2000 years ago, people already wanted to write messages that strangers couldn’t read. The Roman general Julius Caesar is said to have used a simple trick for this. Today your phone and your browser encrypt all the time – with much stronger methods, but with the same basic idea.
The Caesar cipher
Every letter is shifted by a fixed number in the alphabet. With a shift of 3, A becomes D, B becomes E – and after Z it starts again at A. % 26 takes care of the “start again”:
def caesar(text, shift):
result = ""
for character in text:
if "A" <= character <= "Z":
number = ord(character) - ord("A") # A = 0, B = 1, …
number = (number + shift) % 26
result = result + chr(number + ord("A"))
else:
result = result + character
return result
secret = caesar("MEET AT EIGHT", 3)
print(secret)
print(caesar(secret, -3))You decrypt with the same function: just shift back by -3.
Cracking Caesar
There are only 25 useful shifts. A computer tries them all in a fraction of a second. That’s called brute force. Can you find the message?
def caesar(text, shift):
result = ""
for character in text:
if "A" <= character <= "Z":
result = result + chr((ord(character) - ord("A") + shift) % 26 + ord("A"))
else:
result = result + character
return result
secret = "XLI XVIEWYVI MW FILMRH XLI KCQ"
for attempt in range(1, 26):
print(attempt, caesar(secret, -attempt))One line makes sense – so Caesar is not secure.
Vigenère: with a keyword
In the 16th century, the Frenchman Blaise de Vigenère had a better idea: every letter is shifted by a different amount. A keyword says how far. With the key KEY, the first letter is shifted by K (10), the second by E (4), the third by Y (24) – and then it starts again with K:
| Text | H | E | L | L | O |
|---|---|---|---|---|---|
| Key | K | E | Y | K | E |
| Shift | 10 | 4 | 24 | 10 | 4 |
| Secret | R | I | J | V | S |
The two L’s now become different letters (J and V). That makes cracking much harder. With the remainder operator % you repeat the key again and again:
key = "KEY"
for number in range(7):
print(number, key[number % len(key)])Good to know: Vigenère is cracked today too – with statistics about frequent letters. Modern encryption like AES calculates with bits instead of letters and is so strong that not even all the computers in the world together could crack it with brute force.
Your task
Your turn
Write vigenere(text, key, direction). The text consists of capital letters, spaces and punctuation. Every letter is shifted by the value of the matching key letter (A = 0, B = 1, … Z = 25). The key repeats – but only letters use up a key letter. All other characters stay as they are. direction is 1 to encrypt and -1 to decrypt.
def vigenere(text, key, direction):
result = ""
number = 0 # which key letter is next?
for character in text:
result = result + character
return result
secret = vigenere("HELLO WORLD", "KEY", 1)
print(secret)
print(vigenere(secret, "KEY", -1))- Something to think about
Shift
=ord(key[number % len(key)])-ord("A"). New letter: (ord(character)-ord("A")+shift)%26. - Which command helps?
Only increase number when a letter was really encrypted.
Multiply the shift by direction – with -1 it shifts back.
- Gap code – fill in the ___
def vigenere(text, key, direction): result = "" number = 0 # which key letter is next? for character in text: if ___: shift = ___ new = ___ result = ___ number = ___ else: result = result + character return result secret = vigenere("HELLO WORLD", "KEY", 1) print(secret) print(vigenere(secret, "KEY", -1))
Solve it without hints to earn a ⭐ on your progress page.
Show solution🔒 Unlocks after all hints or 2 checks
Try it yourself first – mistakes teach you the most. Here is one possible solution:
def vigenere(text, key, direction):
result = ""
number = 0 # which key letter is next?
for character in text:
if "A" <= character <= "Z":
shift = ord(key[number % len(key)]) - ord("A")
new = (ord(character) - ord("A") + direction * shift) % 26
result = result + chr(new + ord("A"))
number = number + 1
else:
result = result + character
return result
secret = vigenere("HELLO WORLD", "KEY", 1)
print(secret)
print(vigenere(secret, "KEY", -1))