Breaking a Caesar cipher by trying every shift

Tip: Choose Save as PDF in the print dialog to download. Use A4 paper size.

Breaking a Caesar cipher by trying every shift

Name:
Date:
Class:

Quick Questions

Shade in the A or B circle for each question.

1. How many shifts must you try to brute-force a Caesar cipher on the English alphabet?
A 25 shifts (1 to 25)
B Millions of shifts
2. Which result tells you that you have found the correct shift?
A The text is the longest one
B The text reads as sensible English
3. A brute-force attack on a Caesar cipher uses which approach?
A Guess one shift and give up
B Decrypt with every possible shift
4. Why is a Caesar cipher weak against brute force?
A It has a very short key space of only 25 keys
B It has far too many keys to check
5. You try shift 3 and get 'XQDOJ TKHL'. What do you do next?
A Reject it as gibberish and try shift 4
B Accept it as the answer

Match the Pairs

Draw a line connecting each item on the left to its match on the right.

Left columnRight column
1for shift in range(1, 26): AThe shift is not printed, so the attacker cannot tell which key produced the readable text.
2print(shift, decrypt(cipher, shift)) BShows each shift next to its decrypted text so a person can spot which one reads as sensible
3A brute-force attack tries every possible Caesar shift, from 1 to 25 Cfor shift in range(1, 26):
4The attacker picks the shift whose result reads as sensible text, such as real English words DLoops through all 25 possible Caesar shifts so each one can be tried on the ciphertext
5for shift in range(1, 25): Erange(1, 25) stops at 24, so shift 25 is never tried and the correct key could be missed.
6print(decrypt(cipher, shift)) Fprint(shift, decrypt(cipher, shift))

Definitions

brute-force attack

Fill in the Blanks

Complete each line of code by filling in the missing parts.

1.
for shift in _____(1, 26): print(shift)
2.
for shift in range(1, __): guess = decrypt(text, shift) print(shift, guess)
3.
shifts = list(range(1, 26)) print(___(shifts))
4.
if "THE" __ guess: print(shift, guess)
5.
new = chr((ord(c) - 65 - shift) _ 26 + 65)

Spot the Error

Shade in the letter of the line that contains an error.

Question 1
A c = "KHOOR"
B for key in range(1, 26):
C p = decrypt(c, key)
D print(key, c)
Question 2
A text = "WKLV"
B for key in range(1, 26):
C p = decrypt(key, text)
D print(key, p)
Question 3
A msg = "ZRUOG"
B for k in range(1, 25):
C guess = decrypt(msg, k)
D print(k, guess)
Question 4
A def shift_back(ch, k):
B n = ord(ch) - 65
C n = (n - k) % 25
D return chr(n + 65)
Question 5
A c = KHOOR
B for k in range(1, 26):
C print(k, decrypt(c, k))

Answer Key

Breaking a Caesar cipher by trying every shift
Section A: Quick Questions
Q1
A — 25 shifts (1 to 25)
Q2
B — The text reads as sensible English
Q3
B — Decrypt with every possible shift
Q4
A — It has a very short key space of only 25 keys
Q5
A — Reject it as gibberish and try shift 4
Section B: Match the Pairs
Q1
for shift in range(1, 26): → Loops through all 25 possible Caesar shifts so each one can be tried on the ciphertext
Q2
print(shift, decrypt(cipher, shift)) → Shows each shift next to its decrypted text so a person can spot which one reads as sensible
Q3
A brute-force attack tries every possible Caesar shift, from 1 to 25 → for shift in range(1, 26):
Q4
The attacker picks the shift whose result reads as sensible text, such as real English words → print(shift, decrypt(cipher, shift))
Q5
for shift in range(1, 25): → range(1, 25) stops at 24, so shift 25 is never tried and the correct key could be missed.
Q6
print(decrypt(cipher, shift)) → The shift is not printed, so the attacker cannot tell which key produced the readable text.
Section C: Definitions
Q1
brute-force attack — Trying every possible key, such as all 25 Caesar shifts, then choosing the result that reads as sensible text. A short key leaves few shifts to try, so the cipher is weak.
Section D: Fill in the Blanks
Q1
for shift in range(1, 26): print(shift)
Q2
for shift in range(1, 26): guess = decrypt(text, shift) print(shift, guess)
Q3
shifts = list(range(1, 26)) print(len(shifts))
Q4
if "THE" in guess: print(shift, guess)
Q5
new = chr((ord(c) - 65 - shift) % 26 + 65)
Section E: Spot the Error
Q1
D — The loop prints the original ciphertext c every time, so the student never sees the 25 decrypted attempts. It should print p, the decrypted text, so they can spot the readable one.
Q2
C — The arguments are the wrong way round. decrypt expects the ciphertext first and the shift second, so it should be decrypt(text, key).
Q3
B — range(1, 25) stops at 24, so shift 25 is never tried. A brute-force attack must try every shift from 1 to 25, so it should be range(1, 26).
Q4
C — The alphabet has 26 letters, so the wrap-around must use MOD 26. Using % 25 gives the wrong letters, so the right shift would never show readable text. It should be % 26.
Q5
A — The ciphertext is text, so it needs quotes. Without them Python treats KHOOR as a variable name and gives an error. It should be c = "KHOOR".