The rotation cipher is often described using a mathematical formula. First, we start by matching each letter in the alphabet to a number as follows:
A = 0, B = 1, C = 2…Z = 25
The plaintext can then be written as a series of numbers:
Plaintext: P Y T H O N
Plaintext as numbers: 15 24 19 7 14 13
If the key is “R” (or 17), we can encrypt the message by adding the corresponding number to each number in the plaintext.
(15 + 17) (24 + 17) (19 + 17) (7 + 17) (14 + 17) (13 + 17)
The problem is that many of these numbers will be greater than 25, which means they will not have a letter to correspond to. Consider, for example, the first letter, which is encrypted as (15 + 17) = 32, which does not correspond to a letter in the alphabet. What we want in this case is for it to go up to Z (25), then loop back around to A (0) and go from there. To do this we use the modulus operator (%). This takes the remainder that you get when you divide two numbers.
(15 + 17) % 26 = 32 % 26 = 6 because 32/26 = 1 remainder 6
So our now our ciphertext becomes:
6 15 10 24 5 4
which corresponds to:
G P K Y F E
To decrypt, all we have to do is take the ciphertext values and subtract the key value, remembering include % 26. This leads to the following encryption and decryption formulas where m represents one letter of plaintext, c represents one letter of ciphertext, and k represents the key.
c := (m + k) % 26
m:= (c – k) % 26
So far, the formula is good for encrypting and decrypting messages for which the alphabet goes from 0 to 25. But in programming, the ASCII values for capital letters start at 65. To account for this, we will add and subtract 65 from the values as follows:
c:= (m – 65 + k) % 26 + 65
m:= (c – 65 – k) % 26 + 65
This essentially brings the values down to the 1-25 range, adds or subtracts the key, calculates the new value, then adds 65 again to put it back into ASCII range.
Programming Activity
Part A
- The goal of this project is to write a Python program that will allow them to set up a Rotation Cipher with any key and use it to encrypt and decrypt any messages.
- Two useful functions they will need are ord() and chr(), which change ASCII values to characters and vice versa. For example, ord(‘A’) will yield 65, and chr(65) will yield ‘A’.
- This project can be good practice for classes and objects. Create a class called RotationCipher that has one instance variable (key) and several methods, including the __init__, setKey for changing the key, encrypt, and decrypt. Discuss with the students what each method should do.
- Note: The formula given for encryption and decryption restricts the possible characters to capital letters. This means that any spaces in the plaintext should be removed before encryption.
- Example Code:
#!/usr/bin/python class RotationCipher: def __init__(self, key): self.key = ord(key) - 65 def setKey(self, key): self.key = ord(key) - 65 def encrypt(self, message): encrypted = "" message = message.replace(" ", "") for letter in message: encrypted += chr((ord(letter) - 65 + self.key) % 26 + 65) return encrypted def decrypt(self, message): decrypted = "" message = message.replace(" ", "") for letter in message: decrypted += chr((ord(letter) - 65 - self.key) % 26 + 65) return decrypted #This portion is a user interface to interact with the class and methods RC = RotationCipher("A") cmd = "" while cmd != "quit": cmd = raw_input(">>") if cmd == "setKey": key = raw_input("\nKey: ") RC.setKey(key) elif cmd == "encrypt": message = raw_input("\nPlaintext: ") CT = RC.encrypt(message) print CT elif cmd == "decrypt": ciphertext = raw_input("\nCiphertext: ") PT = RC.decrypt(ciphertext) print PT
Part B
- As was mentioned above, the key space for this encryption system is very small (only 26 possibilities in the English alphabet). Even a human, given enough time, would be able to break it by brute-force (for example, using a decoder ring), and a computer could try all 26 possibilities in a very short amount of time.
- The goal of this part is to write a short program to break the cipher. The program should be separate from Part A since someone breaking the cipher should not have access to any of the Rotation Cipher information.
- Discuss with the students how they might go about breaking the cipher, pointing them back to what they did with the decoder rings.
- Give the students a lengthy portion of ciphertext, and ask them to write a program to break it. If they come up with the correct plaintext (and the key), then their code is probably right.
- Example Code:
#!/usr/bin/python ciphertext = raw_input("Enter the ciphertext: ") key = 0 ciphertext = ciphertext.replace(" ", "") while key < 26: message = "" for letter in ciphertext: message += chr((ord(letter) - 65 - key) % 26 + 65) print message + "\n" key += 1