CS 105 - Lab 9
Total Page:16
File Type:pdf, Size:1020Kb
CS 105 - Lab 9 Today, you will be implementing three different ciphers! There's a very weak Caesar cipher, a similarly weak Transpositional cipher, and a stronger but not impenetrable Vigenere cipher. Let's get into it. Part 1: ROT13 The first cipher that we're going to implement is a simple one that is trivial to break if you know a ciphertext is using it. ROT13, also called the Caesar cipher, was developed in ancient Rome and is a simple substitution cipher. ROT13 is terrible for encryption, but is used as a classic example for weak encryption. Let's make it in Python! Open up Spyder and create a file called rot13encrypt.py. # ROT13 encrypter # define our alphabet alphabet = list('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz') # get a phrase as user input phrase = input('Enter a phrase to encode: ') # for each character in our phrase for character in phrase: # if the character is a letter in our alphabet, shift it by 13 # and add it to our encrypted string index = alphabet.index(character) print(alphabet[index-13], end='') Run this script and input your first name only. What is the output? Try re-running the program with your first name, a space, and your last name. The program should crash. Write down the error that you receive. Why do you think the program doesn't work with punctuation such as spaces? # ROT13 encrypter # define our alphabet alphabet = list('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz') # get a phrase as user input phrase = input('Enter a phrase to encode: ') # for each character in our phrase for character in phrase: # if the character is a letter in our alphabet, shift it by 13 # and add it to our encrypted string try: index = alphabet.index(character) print(alphabet[index-13], end='') # otherwise, add the symbol to our encrypted string without processing it except ValueError: print(character, end='') Modify the program to include try... except blocks that will prevent the program from crashing. If you haven't used try statements before, their purpose is quite literally to try to execute some code that might generate errors that you've planned for. The error we've planned for in this case is ValueError, which happens when we try to find the index of a character that isn't in a list. Now, create a new file called rot13decode.py that decodes ROT13 back into plaintext. You'll need to shift 13 characters to the right instead of the left. Be aware that you may get an error if you shift past the end of the alphabet. You can fix the problem of shifting off the list by employing a solution like the following: my_list[index + shift_amount % len(my_list)]. Of course, you'll need to change this formula to meet the needs of the problem we're trying to solve (shifting alphabet by 13). Part 2 - Transposition Cipher Now we're going to look at a different type of cipher which involves moving characters around rather than substitutions of letters. If you've ever played the newspaper game Jumble you have used a Transposition cipher. The one that we're going to work with today is the Rail Fence cipher. The Rail Fence cipher is also known as the Zig Zag Cipher, as it hides its text in a diagonal pattern. Read about how it works at http://crypto.interactive-maths.com/rail-fence-cipher.html#intro If you read the above message diagonally, you'll see that it reads "DEFENDTHEEASTWALLXX". We're going to make our own version of this cipher but excluding the x's. Following the tutorial on the page listed above, decode the following message: ACDTAKTANTAW. Use the grid and write your final answer to the right. Now, encode the message PYTHONRULES!. Put your message on the right. Remember that symbols can be used in transpotition ciphers since we aren't doing any substitutions. The rail cipher encoder is pretty easy to write in Python if you keep the same number of rails each time, though the decoder is a bit more difficult. Today you'll just be writing the encoder. # rail fence cipher encoder # input a message message = # make a list called rails with three blank strings rails = # make a zig-zag path for them to follow rail_path = [0,1,2,1] for index, letter in enumerate(message): # for each letter, add it to the correct rail on the path rails[rail_path[index % 4]] += letter # create a string of all three rails concatenated together (rail 0 + rail 1 + rail 2) out = print(out) Fill in the remaining code in Spyder and save this as rail_encode.py. Run it and make sure that PYTHONRULES! is the same on this program as your manual encoding of it. What would you say the weaknesses of this ciper are, even if you can use more or less than 3 rails? Part 3 - Vigenere Cipher You already learned in class about the basics of the Vigenere cipher. Now its time to make it in code! If you don't remember, the Vigenere Cipher is an alphanumeric cipher that combines multiple Caesar ciphers into one. You start off with two values, a plaintext message and a codeword. For example, let's use ATTACKATDAWN as the plaintext message and LEMON as the codeword. The codeword wraps around the plaintext if it's not long enough as shown: Plain: ATTACKATDAWN Code: LEMONLEMONLE Now, for each combination of (plaintext letter, codeword letter), we find the intersection of the two letters on the substitution matrix and write down the letters. In our example, the result would be: (A,L) = L (T,E) = X (T,M) = F (A,O) = O (C,N) = P and so on. According to Wikipedia, this can be done mathematically: Write your first and last name using the Vigenere cipher and the key . Don't use spaces. COMPSCI This is the way we're going to do our program: with numbers! A few things to note: If we have an alphabet string alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', we can get a numeric value from 0 to 25 with alphabet.index(letter). For example, alphabet.index('a') = 0. Your program will first ask for a message and a temporary key, putting each into uppercase. The temporary key will then be stripped of all spaces, numbers, and punctuation marks. The key needs to be letters only. The way to do this is to use a for loop for each letter in the temporary key. Check if each letter is a letter by using letter.isalpha(). If the letter is a letter, add it to a new string called key. Now that we have a key and a message, iterate through each letter in the message: converting it to a number from 0 to 25. getting the proper key letter at the position in the message. adding the two together and modding by 26 Start with the skeleton code I provide: # Vigenere cipher # define our alphabet alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' # define our cipher encoder def vig_encode(message, temp_key): # strip numbers and whitespace from the key # create an empty key string key = '' # for each character in the temporary key for # if the character is a letter if # add the letter to the new key string # create a blank string out = '' # for each letter in the message for index, letter in enumerate(message): try: # get the letter's position in the alphabet m = # get the key's position in the alphabet (Key may be shorter than msg!) k = # add the two together and mod by 26 c = # print the result's position in the alphabet out += alphabet[c] except ValueError: # print the punctuation out += message[i] return out # input message and key, converting each to UPPERCASE. message = temp_key = print(vig_encode(message,temp_key)) Finish the skeleton code. Any line that ends with an = or has an if or a for statement and nothing after it you'll need to finish yourself. Write down the program's output for FURMANPALADINS with codeword PURPLE. Change the encrpytion program to a decryption program. This can be done by changing one symbol. What is it that we're changing? What would you say are the weaknesses of this cipher? .