Vigenere cipher in Python

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

Vigenere cipher in Python

Name:
Date:
Class:

Quick Questions

Shade in the A or B circle for each question.

1. A Vigenere loop uses key[i % len(key)] with key = "CAT". Which keyword letter is used for position i = 4?
A A (4 % 3 = 1, so key[1])
B T (the keyword just stops at the last letter)
2. Why does the Vigenere loop use i % len(key) instead of just i?
A So the index wraps back to 0 when the message is longer than the keyword
B So the keyword is made shorter before encrypting
3. Which line picks a different shift for each letter by cycling through the keyword?
A shift = ord(key[0]) - 65
B shift = ord(key[i % len(key)]) - 65
4. With key = "KEY" (length 3), what does i % len(key) give when i = 3?
A 3
B 0
5. The message is "HI THERE". To keep the keyword in step, which letters should move the keyword position on?
A Only the letters, so the space is skipped
B Every character, including the space

Match the Pairs

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

Left columnRight column
1key[i % len(key)] Aif ch.isalpha(): k = key[j % len(key)] j += 1
2shift = ord(k) - 65 BTurns an uppercase keyword letter into a shift number from 0 to 25 (A is 0, B is 1, and so on).
3Only letters use up the keyword, so a counter j goes up only when the character is a letter and spaces are skipped. CPicks the keyword letter for position i and wraps back to the start of the keyword when i passes its length.
4To decrypt a Vigenere message, subtract the keyword shift instead of adding it, and wrap with % 26. Dj goes up for spaces and punctuation as well as letters, so the keyword gets out of step with the letters being encrypted.
5k = key[i] EThere is no % len(key), so the index runs past the end of the keyword on a long message and causes an IndexError.
6k = key[j % len(key)] j += 1 # runs for every character Fchr((ord(ch) - 65 - shift) % 26 + 65)

Definitions

key[i % len(key)]

Fill in the Blanks

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

1.
k = key[i _ len(key)]
2.
k = key[i % ___(key)]
3.
if ch.isalpha(): k = key[_ % len(key)] n = n + 1
4.
shift = ord(key[i % len(key)]) - 65 new = (ord(ch) - 65 _ shift) % 26
5.
shift = ___(key[i % len(key)]) - 65 new = (ord(ch) - 65 + shift) % 26 + 65

Spot the Error

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

Question 1
A for i in range(len(msg)):
B c = msg[i]
C s = key[i / len(key)]
D k = ord(s) - 65
Question 2
A for i in range(len(msg)):
B s = key[i % len(key)]
C k = ord(s) + 65
D x = ord(msg[i]) - 65 + k
E out += chr(x % 26 + 65)
Question 3
A for i in range(len(msg)):
B s = key[i % len(key)]
C k = ord(s) - 65
D x = ord(msg[i]) - 65 + k
E plain += chr(x % 26 + 65)
Question 4
A j = 0
B for ch in msg:
C if ch.isalpha():
D s = key[j % len(msg)]
E j += 1
F k = ord(s) - 65
Question 5
A key = LEMON
B j = 0
C for ch in msg:
D if ch.isalpha():
E s = key[j % len(key)]
F j += 1

Answer Key

Vigenere cipher in Python
Section A: Quick Questions
Q1
A — A (4 % 3 = 1, so key[1])
Q2
A — So the index wraps back to 0 when the message is longer than the keyword
Q3
B — shift = ord(key[i % len(key)]) - 65
Q4
B — 0
Q5
A — Only the letters, so the space is skipped
Section B: Match the Pairs
Q1
key[i % len(key)] → Picks the keyword letter for position i and wraps back to the start of the keyword when i passes its length.
Q2
shift = ord(k) - 65 → Turns an uppercase keyword letter into a shift number from 0 to 25 (A is 0, B is 1, and so on).
Q3
Only letters use up the keyword, so a counter j goes up only when the character is a letter and spaces are skipped. → if ch.isalpha(): k = key[j % len(key)] j += 1
Q4
To decrypt a Vigenere message, subtract the keyword shift instead of adding it, and wrap with % 26. → chr((ord(ch) - 65 - shift) % 26 + 65)
Q5
k = key[i] → There is no % len(key), so the index runs past the end of the keyword on a long message and causes an IndexError.
Q6
k = key[j % len(key)] j += 1 # runs for every character → j goes up for spaces and punctuation as well as letters, so the keyword gets out of step with the letters being encrypted.
Section C: Definitions
Q1
key[i % len(key)] — Picks the keyword letter for position i and wraps back to the start with %, so each message letter gets its own shift. This is how a Vigenere cipher loop cycles the keyword.
Section D: Fill in the Blanks
Q1
k = key[i % len(key)]
Q2
k = key[i % len(key)]
Q3
if ch.isalpha(): k = key[n % len(key)] n = n + 1
Q4
shift = ord(key[i % len(key)]) - 65 new = (ord(ch) - 65 - shift) % 26
Q5
shift = ord(key[i % len(key)]) - 65 new = (ord(ch) - 65 + shift) % 26 + 65
Section E: Spot the Error
Q1
C — / gives a decimal, which cannot be used as an index. Use % so i wraps back to the start of the keyword: key[i % len(key)].
Q2
C — The shift is the keyword letter's position in the alphabet (A=0 to Z=25), so you subtract 65: ord(s) - 65. Adding 65 gives a huge, wrong shift.
Q3
D — Decrypting undoes the shift, so you subtract k. Adding it shifts the letter forward again and gives the wrong plaintext.
Q4
D — The keyword must wrap using its own length. Using len(msg) does not cycle the keyword and can go out of range. It should be key[j % len(key)].
Q5
A — The keyword is a string, so it needs quotes. Without them Python looks for a variable called LEMON and raises a NameError. It should be key = "LEMON".