CS1400 Assignment 5: Encryption

You should pass off each part of this assignment to a lab assistant or the professor before the end of the day on each due date.

Objectives

Assignment Overview

In this assignment, you will create an application that allows the user to encrypt or decrypt files. You must support the three specified encryption/decryption schemes, and you are encouraged to add your own for fun.

Download a working (but not viewable) copy of the completed assignment: encrypt.pyc. Do not try to open it. Just double click on it to execute it.

If you have questions, discuss them with your instructor.

Assignment Details

When a user first launches your program, they should be presented with a brief program desription, and a start-menu of choices such as:

This program encrypts and decrypts messages, using multiple encryption methods.
Input files must be in the same directory as this program.
Output files will be created in this same directory.

Do you want to encrypt or decrypt?
(e)ncrypt
(d)ecrypt
(q)uit

‘q’

If the user enters ‘q’, then your program should immediately quit.

‘e’

If the user chooses ‘e’, then your program should present them with a menu of encryption/decryption methods, such as:

Which method do you want to use?
(c)aesarian fixed offset
(p)seudo-random offset
(s)ubstitution cipher

Regardless of their chosen scheme, the user should then be prompted to enter the name of the file they want to encrypt (which should already exist in the same directory as your python code), followed by the name of the file they want to store the encrypted data into, followed by the password they want to use for encrypting (which same password must be used for later decrypting). The encrypted data file should appear in the same directory, but be unreadable to an evesdropper without a fair amount of effort. The user should be notified when the process is complete, and then presented again with the initial start-menu.

’d’

If the user chooses ’d’ from the start-menu, then your program should present them with the same menu of decryption options as was presented for encrypting, as explained above. Prompt them for the file to decrypt (which must already exist in the same directory as your python code), the name of the file to put the decrypted data into, and their password (which must match the password used to encrypt, or the results will be garbage). The decrypted data file should appear in their same directory, and its contents should match the original file before it was encrypted. Notify the user when the process is complete, and then present the initial start-menu.

Implementation Details

main()

Create a main() function which will be relatively small. Most work should be coded inside other functions.

Begin main() by specifying the alphabet of characters your program will support, such as:

 alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,.?! \t\n\r"

Next, main() should call PrintDescription(), which function you need to implement.

Then, main() should start up a while True: loop.

Inside the while loop, first present the user with the start-menu by calling the function StartMenu(), which you must write.

StartMenu()

StartMenu() should print their options as listed above. Ensure that the user enters ‘e’ or ’d’ or ‘q’ by using a while loop to make them redo any bad entry. StartMenu() should then return their choice back to the main() function, where a variable of main() should catch that return value.

More main()

If they chose ‘q’ then have your main() function break out of the while loop, effectively ending your program.

If the user chooses ‘e’ or ’d’, present them with another menu of encryption/decryption methods by calling MethodMenu(), which you must write.

MethodMenu()

MethodMenu() should print their options as listed above, ensure they enter a valid choice, then return their choice back to the main() function, where a variable of main() should catch that return value.

More main()

Continue the while loop by prompting the user for the input file, the output file, and the password, as explained above.

Open their input and output files with these commands, assuming your variables are named as below:

fin = open(source_file, "rb")
fout = open(destination_file, "wb")

Note that your program will crash at this point, if the user enters an input file name that does not exist in the same directory as your python program. (For an optional challenge, research the python try command to fix this potential crash.)

Seeding (or activating) the random number generator with different passwords causes different sets of pseudo-random numbers to be generated. However, if a message is encoded and decoded with the same password, then the same set of ‘random appearing’ numbers will be generated, allowing the decryption algorithm to exactly undo what the encryption algorithm did.
To activate the the user’s chosen password, call:

random.seed(password)

Use an if/elif/else chain to call the proper one of the three encryption/decryption functions. The first of the three encryption/decryption functions (The Caesarian method) is provided for you in full below.
You may copy/paste it into your python file, but be sure to take time to study how it works. Note that any character of the input file not found in the alphabet will be discarded. Be sure that when you call Caesarian() from main(), you give it exactly what it needs to do its job.

You cannot finish the if/elif/else chain until part 2 of the assignment, where you will implement the other two encryption methods yourself. For now, if they don’t choose Ceasarian, then don’t do anything. Use the pass command to do nothing.

Finish the while loop by closing the input and output files with:

fin.close()
fout.close()

and by printing an encouraging message to the user indicating that their desired file has been successfully created.

The while loop just described will repeat until the user chooses ‘q’ from the start-menu, so the user can encrypt and decrypt several files without having to restart your program.

Caesarian()

Here is the promised Caesarian function, fully implemented for you:

def Caesarian(fin, fout, encrypt_or_decrypt_choice, alphabet):
    # Determine the offset by generating a random number in the correct range.
    # This will be the same random number, if the password sent to random.seed is the same.
    offset = random.randrange(1,len(alphabet))
    if encrypt_or_decrypt_choice=='d':
        offset = -offset
    print "Using the secret offset of", offset

    # Read every line of the input file.
    for line1 in fin:
        # Alter each character of the line1, putting the result into line2.
        line2 = ""
        for c in line1:
            if c in alphabet:
                pos1 = alphabet.find(c)
                pos2 = (pos1+offset)%len(alphabet)
                line2 += alphabet[pos2]
        # Write each resulting line2 to the output file.
        fout.write(line2)

At this point, your program should be fully functional as long as the user chooses the Caesarian encryption method. Test your code to make sure it works!

This completes Part 1.

Part 2

For Part 2, you will implement two more encyption/decryption methods. The first, the Pseudo-random offset method, is much more secure than the Caesarian method, but the code looks very simliar. The second, the Substitution method, was used effectively for over a thousand years. Its code is similar to the Caesarian method, but requires more changes than the Pseudo-random offset method.

PseudoRandom()

The Pseudo-random-offset method is based on the truly random-offset method, which is provably impossible to break. That superior method works by creating in advance a booklet full of random numbers in the range of the alphabet size. These numbers must be truly random, meaning it is very difficult or impossible to get a computer to generate them for you. Flipping coins or rolling dice many many times has been used successfully. Then there is some amount of work needed to convert numbers in the 0-1 coin range or the 0-5 die range into the range of your alphabet, and you have your booklet! This booklet is then copied and predistributed to all parties who wish to communicate secretly. Suppose the parties have later separated, and one party wishes to send to the others the message, “Everyone attack Island 6 at dawn.” The first letter, E, is offset by the first number in the booklet. The second letter, ‘v’ is offset by the second number in the booklet, and so forth. Since every instance of every letter is offset by a different amount, there are no patterns that would allow a hacker to guess anything. And even if the hacker were told the solution to decrypting the first several letters, it would not help him at all with any subsequent letters.

Some problems with the truly random-offset method are that it is difficult and time consuming to generate these booklets, they are too long to remember and thus must be written down, and the message later to be encrypted can be no longer than the number of offsets in the booklet. Also, they must be distributed to all parties in advance, and if an enemy captured even one booklet, the whole system is crippled until everyone can meet together again.

We will use a modified version called Pseudo-random offset. We won’t need to pre-distribute a booket, just a password, and those are shorter and don’t need to be written down. The password is then used to seed the python random number generator, as described above. You should start with the Caesarian code, but instead of creating one offset at the beginning of the function, create a new one for every single character.

Note that our version is not secure, because a hacker need only find the pattern in the pseudo-random sequence, which is relatively easy. However, it is still hard enough to break that it should work fine between you and your friends.

Substitution()

The Substitution method does not use an offset, but instead starts by making a table which assigns every source character to a unique random destination character. For example, the letters in the following alphabet might map to the letters in the second, ‘substitution alphabet’:

original alphabet     : abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,.?! \t\n\r
substitution alphabet : CGAo3BxwhZz7 p,4gmr9OW6JilQ1tf!RV5SvbN\tD.TIcy0L2M\nX\r?8HsknaKdUuqjEYPeF

Thus, all ‘a’ characters encrypt to ‘C’, ‘b’ maps to ‘G’, and so forth. For decrypting, just go in the backwards direction.

Normally, the original alphabet is publicly known, and the substitution alphabet is the secret key. For us, the user’s password is the key, and it is used to seed the random number generator, which in turn allows our code to create unique substitution alphabets per unique passwords. The following steps should help guide you to write python code that forms substitution alphabets, given an alphabet and a random seed:

# Make a temporary empty LIST called alphabetList
# Append to alphabetList all characters in the alphabet STRING.
# Shuffle it with random.shuffle(alphabetList)
# Make an empty STRING called substitutionAlphabet
# Move all characters from alphabetList to substitutionAlphabet

The Substitution method worked great for many centuries, until it was finally cracked using the idea of frequency analysis. That is, the encrypted character that appears most frequently probably maps back to an ‘e’, and so forth. It is useless today for any serious encryption.

Always remember to test your code!

Optional challenges

Implement a fourth encryption/decryption method of your own creation.

Implement try as explained above to prevent crashing on a bad file name.

Last Updated 03/20/2013