For this assignment, we’re going to be experimenting with basic cryptography. Cryptography is a field at the intersection of math and computer science that studies ways of securely communicating information. Throughout history, it has played an important role in a variety of cultures in a variety of contexts. We’ll experiment with some basic encryption techniques, but there is a wealth of information on modern encryption out there (Wikipedia is a good place to start if you’re interested). In cryptography, the two main functions are encryption, where we take a plaintext message and encrypt it into the cyphertext, and decryption, where we take the encrypted cyphertext and extract the original plaintext message. In this assignment, we’ll experiment with a few different ways of doing both of these operations.
An important skill for any programmer is the ability to utilize and extend previously written code. For this assignment, I’m going to give you some code to get you started. This program has some variables and functions written for you already and you will be filling in some of the details.
Right-click on the above link, select “Save as…”, and save the file for this
assignment. Then open the saved file with Thonny. This file does not have any
syntax errors, however, until you fill in some of the details not all of the
functions will run (i.e. the keygen
function will throw an error).
To get you warmed up we’re going to try a very simple method for encryption. You have a friend who says they have a great idea for encrypting a message. To encrypt it, you repeat each letter 3 times. To decrypt it, you reverse the process. For example: “secret message” would become “ssseeecccrrreeettt mmmeeessssssaaagggeee”
Write a function called fools_encrypt
that takes a message as a parameter and
returns the message encrypted using this scheme.
If you want a challenge (not required), try to write a function named
fools_decrypt
that decrypts this. For example, you could execute:
>>> fools_decrypt("ssseeecccrrreeettt mmmeeessssssaaagggeee")
'secret message'
>>> secret = fools_encrypt("secret message")
>>> secret
'ssseeecccrrreeettt mmmeeessssssaaagggeee'
>>> fools_decrypt(secret)
'secret message'
If you’re not up for the challenge but want to test decrypting the results of your encryption function, you can copy my sample solution decryption function into your file: fools_decrypt.py (although really give it a try before downloading the sample code).
Now, let’s try to implement Caesar’s encryption scheme. If you need a review of
how it works, take a look at the prelab again. In the starter, I’ve given you a
function called shift_letter
. Play with this function and try some different
letters (lowercase letters only) and different number offsets to make sure you
understand how it works. Notice that you can also pass it negative numbers to
shift the other direction.
Once you’re comfortable with how shift_letter
works, write a function called
caesar_encrypt
that takes two parameters: the message to be encrypted and the
size of the shift for the encryption. You will very likely want to utilize the
shift_letter
function.
One of the nice things about this encryption scheme is that we can use the same function for encrypting and decrypting a message. Before reading on, think about how we could do this…
To decrypt a message, we can use our caesar_encrypt
function, but now, give
it a negative number. Encrypt a message or two and make sure that you can
decrypt them.
Decrypt the following message with number offset 5:
htruzyjwexhnjshjenxestertwjefgtzyehtruzyjwxeymfsefxywtstrcenxefgtzyeyjqjxhtujx
It’s a quote from a famous computer scientist (Dijsktra). You don’t have to write it down, but it’s a good check to make sure you’ve got things working.
Warning: our encryption schemes will only work for lowercase letters (specifically the letters a-z and space), so make sure that your message doesn’t have any other characters otherwise, it won’t work correctly.
Caesar’s method is just an example of a more general type of encryption scheme called substitution ciphers. For a general substitution cipher, a key is used. The key has all of the same letters as the alphabet, but the order has been shuffled.
When encrypting, you encrypt one letter at a time. For each letter in the message you find that letter in the alphabet and then replace it with the corresponding letter in the key. For example, say you have following alphabet and key (I’ve put the indices in to make it easier to understand):
alphabet: a b c d e f g h i j k l m n o p q r s t u v w x y z ' '
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
key: h v i e k s y r b d a j q w n c x m g u f l t p ' ' o z
and you see the character ‘k’, you look that up in the alphabet and notice that it is at index 10. You then use this index in the key to get ‘a’ as the letter. This process is repeated for each letter in the message until you have encrypted the entire message. Make sure you understand this process before moving on to the coding.
Before we can actually encrypt anything, we first need to generate a key. We
could do this by hand, but it’s difficult to do. In the starter code, I’ve
included a helper function named keygen
for generating the kind of keys
needed by your substitution encryption and decryption functions. This function
takes any string as a parameter and generates a random key based on that input
string (think of it like a password). I’ve given you all the code for this
function except it relies on the splice
function, which needs to be
implemented. Fill in the details of the splice
function.
When you’re done, you should be able to generate random keys using the keygen
function. Try out a few examples and make sure that it is a permutation of all
of the letters in the alphabet and that you get the same thing back if you give
it the same password. For example:
>>> keygen("doglover")
'deyvhaflcirmtjsgoxbpzukwnq '
>>> keygen("doglover")
'deyvhaflcirmtjsgoxbpzukwnq '
Note: due to various computer-specific factors you may not get the exact same
keys as I have included here. If, on your computer, you call keygen
twice with
the same string, however, you should get the same string back.
Now that you can generate random keys, you’re ready to encrypt something. Write
a function called subst_encrypt
that takes two parameters: the message to be
encrypted and the key (not the password). The function should return the
message encrypted using the key. Notice that there is a constant called
ALPHABET which has all of the letters and space in order. You’ll likely need to
use this.
For a general substitution cipher we also need to write a decryption method.
Write a function called subst_decrypt
that takes two parameters: the encrypted
message and the key (not the password). The function should return the message
decrypted using the key (i.e. the original message before encryption). This
function should be very similar to the encryption function with just one or two
minor changes (it’s the same basic idea, but in the other direction). When
you’re done, you can generate a new key then encrypt and decrypt messages. For
example:
>>> key = keygen("mypassword")
>>> key
'jf rdesquztkwhoipcbamlvxgny'
>>> encrypted = subst_encrypt("this is a secret message", key)
>>> encrypted
'aqubyubyjybd cdaywdbbjsd'
>>> subst_decrypt(encrypted, key)
'this is a secret message'
As before, keygen
might work differently on your machine, so your encrypted
text might look different.
Decrypt the following message using the password “i like cs”
ao us jauaoiwpuxsrtauxusrrf xwuiju g wuiduqrtuxh uyhrwpuqrtuxh urwfqurddusquxusia
Note: If it doesn’t work, check to see if you random key is
'xscl dpoimkfzwrevhjatgynqbu'
. If it’s not, it’s most likely just a difference
in computers. Try your decrypt message function with this key then to make sure
it works.
Again, you don’t have to write it down, but it’s a good check to make sure you’ve got things working.
At a minimum your submission should have:
fools_encrypt
that takes a message as a parameter and
returns the message encrypted using the scheme described in the Guide section.caesar_encrypt
that takes two parameters, the message to be
encrypted and the size of the shift for the encryption, and implements
Caesar’s encryption method.splice
function.subst_encrypt
that takes two parameters, the message to
be encrypted and the key, and performs substitution encryption.subst_decrypt
that takes two parameters, the encrypted
message and the key, and performs substitution decryption.[1 point] Caesar’s method can actually be written using our code for the
general substitution cypher. Write a function named shift
that takes as input
a number. The function should return a key that is the in-order alphabet shifted
up by the number input. For example:
>>> shift(3)
'defghijklmnopqrstuvwxyz abc'
If you then use this key with your subst_encrypt
function you should get
the same answer as if you’d used your caesar_encrypt
method with the
number offset.
Write a pair of functions my_encrypt
and my_decrypt
that implement your
own encryption algorithm. You may rely on whatever input you would like, but
make it clear in the documentation how they should be run. Points will be
awarded based on difficulty and creativity. For example, a better (more secure)
version of our substitution would evolve the key with each letter (termed a
polyalphabetic cipher). Think about how you could deterministically evolve your
substitution key.
When you’re done you should have three different encryption/decryption methods and a method for generating random keys. Make sure that your program is properly commented:
In addition, make sure that you’ve used good coding style (including meaningful variable names, constants where relevant, vertical white space, removing “dead code” that doesn’t do anything, removing testing code, etc.).
Submit your program via Gradescope. Your program program file must be named lab3_encryption.py. You can submit multiple times, with only the most recent submission (before the due date) graded. Note that the tests performed by Gradescope are limited. Passing all of the visible tests does not guarantee that your submission correctly satisfies all of the requirements of the assignment.
Features | Points |
---|---|
fools_encrypt |
4 |
caesar_encrypt |
4 |
splice |
4 |
subst_encrypt |
4 |
subst_decrypt |
4 |
Code design and style | 5 |
Creativity points | 2 |
Total | 27 |
I have received several questions in office hours about how keygen
is used.
keygen
is a helper function for generating valid keys for your
subst_encrypt
and subst_decrypt
functions. You should not use keygen
within the subst_encrypt
and subst_decrypt
functions. Instead, as shown in
the lab examples, both of those functions take the key, generated previously by
keygen
, as a parameter. For example: