Brute-forcing a Caesar cipher in Python

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

Brute-forcing a Caesar cipher in Python

Name:
Date:
Class:

Quick Questions

Shade in the A or B circle for each question.

1. Which loop tries every Caesar shift from 1 to 25?
A for shift in range(1, 25):
B for shift in range(1, 26):
2. Why does the loop use range(1, 26) and not range(1, 25)?
A range() stops before the end value, so 26 is needed to include shift 25
B range() includes the end value, so 26 gives shifts 1 to 26
3. Which line prints the shift beside each attempt?
A print(decrypt(message, shift))
B print(shift, decrypt(message, shift))
4. What happens on each pass of the brute-force loop?
A It decrypts the message with the current shift and prints the result
B It encrypts the message again using the same shift every time
5. How do you spot the correct shift in the printed list?
A It is the attempt that reads as normal English
B It is the attempt with the largest shift number

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): Afor shift in range(1, 26): print(shift, decrypt(secret, shift))
2print(shift, decrypt(secret, shift)) Brange(1, 25) stops at 24, so shift 25 is never tried and the correct answer could be missed. It should be range(1, 26).
3To brute-force a Caesar cipher, try every shift from 1 to 25 and decrypt the message each time Cif "hello" in text: break
4The brute-force loop can stop as soon as a known word appears in the decrypted text DLoop that tries every possible Caesar shift from 1 to 25 in turn
5for shift in range(1, 25): EThe shift is not printed beside each result, so you cannot tell which shift produced the readable message. It should print shift as well.
6for shift in range(1, 26): print(decrypt(secret, shift)) FShows each shift number beside the message it produces, so you can spot the readable one

Definitions

for shift in range(1, 26):

Fill in the Blanks

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

1.
for shift in _____(1, 26): result = decrypt(message, shift) print(shift, result)
2.
for shift in range(1, __): result = decrypt(message, shift) print(shift, result)
3.
for shift in range(1, 26): result = decrypt(message, shift) print(_____, result)
4.
result = decrypt(message, shift) if "the" in result: _____
5.
for shift in range(1, 26): result = _______(message, shift) print(shift, result)

Spot the Error

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

Question 1
A msg = "KHOOR"
B for shift in range(1, 26):
C out = decrypt(msg, shift)
D print(shift, msg)
Question 2
A for shift in range(1, 26)
B out = decrypt(msg, shift)
C print(shift, out)
Question 3
A msg = "WKLV LV IXQ"
B for shift in range(1, 25):
C out = decrypt(msg, shift)
D print(shift, out)
Question 4
A for shift in range(26, 1):
B out = decrypt(msg, shift)
C print("Shift", shift, out)
Question 5
A for shift in range(1, 26):
B out = decrypt(msg, shift)
C if "THE" == out:
D print(shift, out)
E break

Answer Key

Brute-forcing a Caesar cipher in Python
Section A: Quick Questions
Q1
B — for shift in range(1, 26):
Q2
A — range() stops before the end value, so 26 is needed to include shift 25
Q3
B — print(shift, decrypt(message, shift))
Q4
A — It decrypts the message with the current shift and prints the result
Q5
A — It is the attempt that reads as normal English
Section B: Match the Pairs
Q1
for shift in range(1, 26): → Loop that tries every possible Caesar shift from 1 to 25 in turn
Q2
print(shift, decrypt(secret, shift)) → Shows each shift number beside the message it produces, so you can spot the readable one
Q3
To brute-force a Caesar cipher, try every shift from 1 to 25 and decrypt the message each time → for shift in range(1, 26): print(shift, decrypt(secret, shift))
Q4
The brute-force loop can stop as soon as a known word appears in the decrypted text → if "hello" in text: break
Q5
for shift in range(1, 25): → range(1, 25) stops at 24, so shift 25 is never tried and the correct answer could be missed. It should be range(1, 26).
Q6
for shift in range(1, 26): print(decrypt(secret, shift)) → The shift is not printed beside each result, so you cannot tell which shift produced the readable message. It should print shift as well.
Section C: Definitions
Q1
for shift in range(1, 26): — A loop that tries every Caesar shift from 1 to 25. Each pass decrypts the message and prints the shift beside the result, so you can spot the readable one.
Section D: Fill in the Blanks
Q1
for shift in range(1, 26): result = decrypt(message, shift) print(shift, result)
Q2
for shift in range(1, 26): result = decrypt(message, shift) print(shift, result)
Q3
for shift in range(1, 26): result = decrypt(message, shift) print(shift, result)
Q4
result = decrypt(message, shift) if "the" in result: break
Q5
for shift in range(1, 26): result = decrypt(message, shift) print(shift, result)
Section E: Spot the Error
Q1
D — This prints the original scrambled message every time, so you never see the decrypted attempts. It should be print(shift, out) to show the shift beside each result.
Q2
A — A for statement must end with a colon. It should be for shift in range(1, 26):
Q3
B — range(1, 25) stops at 24, so shift 25 is never tried. To try every shift from 1 to 25 you need range(1, 26).
Q4
A — range(26, 1) counts up from 26 and is empty, so the loop never runs. The start must be smaller than the stop: range(1, 26).
Q5
C — == only matches if the whole message is exactly THE. To stop when a known word appears anywhere in the text, use in: if "THE" in out: