2012 April 11,

CS 111: Assignment: Ciphers

Carleton College, Spring 2012

Prof. Joshua R. Davis, , Goodsell 106B, x4473

Introduction

In this assignment, you will practice with some basic ciphers for encrypting data. For simplicity, we assume that the data are strings over the alphabet A, B, C, ..., Z. (There are no spaces, punctuation, lower-case letters, etc.)

You must work on this assignment individually, and hand in your own solutions, although as usual you are encouraged to talk with other students. (See the syllabus or ask questions, if you're unsure of what's allowed.) This assignment is due Friday at 11:59 PM. It will consist of a single Python file, ciphers.py, to be submitted electronically.

Rot13

In class, we discussed the Rot13 cipher, which works by shifting each letter in the alphabet by 13 places, with the end of the alphabet wrapping around to the start as necessary. For example, A encrypts to N, and T encrypts to G. Our code was:

def encryptRot13(s):
    r = ""
    for c in s:
        index = ord(c) - ord("A")
        index = (index + 13) % 26
        r += chr(index + ord("A"))
    return r

def decryptRot13(s):
    return encryptRot13(s)

You don't need to include the Rot13 cipher in your assignment. I recapitulated it here, just in case it can help you write your own code.

Caesar Cipher

The Caesar cipher is a little more complicated that the Rot13 cipher, because it requires a password. The password is a single letter, such as Q. The two parties who are communicating with each other agree on the password ahead of time, often in person (because they don't want to transmit the password insecurely).

When either party wants to send a message to the other, he encrypts the message by adding the password to each letter of the message. But what does it mean, to add a letter such as Q to another letter? Well, we can index the letters of the alphabet from 0 to 25, with A being 0, B being 1, and so on. In this indexing system, Q is 16. To add Q to a letter is to shift that letter 16 places to the right in the alphabet, wrapping around as in Rot13. So, for example, F encrypts to T and T encrypts to E, if the password is Q.

The receiving party decrypts the message using the same password. What exactly is the algorithm for decrypting?

Your task in this part of the assignment is to implement the following two functions in ciphers.py.

# Returns a string encrypted by the Caesar cipher.
# Input: String of upper-case Roman letters (A, ..., Z) to encrypt. 
# A single upper-case Roman letter, to serve as the key.
# Output: Encrypted string.
def encryptCaesar(s, key):

# Returns a string decrypted by the Caesar cipher.
# Input: String of upper-case Roman letters (A, ..., Z) to decrypt. 
# A single upper-case Roman letter, to serve as the key.
# Output: Decrypted string.
def decryptCaesar(r, key):

For example, the following code should print BABAR.

plaintext = "BABAR"
key = "P"
print decryptCaesar(encryptCaesar(plaintext, key), key)

Repeated Pad

In this part of the assignment, you will implement the repeated pad cipher discussed in class. This is much like the Caesar cipher, but uses a key word instead of a single key character. You add the message to the key word to get the encrypted message. If the key word is not long enough, then you repeat the key word as many times as necessary.

Your task in this part of the assignment is to implement the following two functions in ciphers.py.

# Returns a string encrypted by the Caesar cipher.
# Input: String of upper-case Roman letters (A, ..., Z) to encrypt. 
# A string of upper-case Roman letters, to serve as the key.
# Output: Encrypted string.
def encryptRepeatedPad(s, key):

# Returns a string decrypted by the Caesar cipher.
# Input: String of upper-case Roman letters (A, ..., Z) to decrypt. 
# A string of upper-case Roman letters, to serve as the key.
# Output: Decrypted string.
def decryptRepeatedPad(r, key):

For example, the following code should print SECRETDOLPHINATTACKATNOON.

plaintext = "SECRETDOLPHINATTACKATNOON"
key = "GNIJIEB"
print decryptRepeatedPad(encryptRepeatedPad(plaintext, key), key)

Substitution Cipher

The following code implements part of a substitution cipher. This cipher is treated in our textbook. The version here is somewhat different. The substitution itself is represented as a list of the 26 upper-case Roman letters (A - Z) in some mixed-up order. Each entry indicates how to encrypt a certain letter of the alphabet, by its position in the list. For example, the following substitution says that A encrypts as T, B encrypts as H, C encrypts as E, and so on.

sub = ["T", "H", "E", "Q", "U", "I", "C", "K", "S", "L", "V", "R", "F", "O", "X", "J", "M", "P", "D", "A", "Z", "Y", "B", "W", "N", "G"]

Any given substitution has a corresponding inverse substitution, which is simply the substitution that decrypts each letter. In the example above, the inverse substitution is:

inv = ["T", "W", "G", "S", "C", "M", "Z", "B", "F", "P", "H", "J", "Q", "Y", "N", "R", "D", "L", "I", "A", "E", "K", "X", "O", "V", "U"]

Why? Well, for example, look at the end of the original substitution. It says that Z encrypts as G. Now look at inv[6]. It says that letter #6, which is G, decrypts as Z. Work out some more examples like this for yourself, to understand this idea. Then paste the following code into your file ciphers.py. The encryptSub and decryptSub functions are finished, and you should not alter them. Your job is to implement the inverseSub function.

# Decrypts a given string using a given substitution cipher.
# All strings are over the 26 upper-case Roman letters (A-Z).
# Input: String to decrypt. Substitution.
# Output: Decrypted string.
def encryptSub(s, sub):
    r = ""
    for i in range(len(s)):
        index = ord(s[i]) - ord("A")
        r = r + sub[index]
    return r

# Inverts the given substitution cipher.
# Input: Substitution.
# Output: Inverse substitution.
def inverseSub(sub):
    # Remove pass and implement this function.
    pass

# Decrypts a given string using a given substitution cipher.
# All strings are over the 26 upper-case Roman letters (A-Z).
# Input: String to decrypt. Substitution.
# Output: Decrypted string.
def decryptSub(r, sub):
    return encryptSub(r, inverseSub(sub))

Submitting your Work

Follow the same polishing process as in the previous assignment: Comment your code, remove junk, etc.

When your assignment is completely finished, tested, and polished, you will submit it electronically, following the directions at our Technical Issues page. Submit your work by 11:59 PM on Friday. It will be graded according to these criteria: