Skip to content

susdah/Final-project-CS50-Python-Cipher

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NAME OF PROJECT: CIPHER

Files available in project folder:

  1. project.py: Contains the program, as described below.
  2. test_project.py: Contains 5 test functions for the class and functions described below.
  3. README.md: That is this file.
  4. text.txt: This is an example text that can be used to demo the program. It is not required and you can use any text file you wish.

Description:

Cipher is a program that encrypts and decrypts text using a key. Imagine two friends who want to share messages, but do not want others to be able to read what it says. Person A can use this program to encrypt the message, send the encrypted text to Person B, who then uses the same program to decrypt it. They both must use the same key that they agree upon beforehand. The key is taken from the user each time, and not stored in the program. This means that if you lose the key you cannot decrypt an encrypted text.

The functions for taking a key from the user and using it to encrypt and decrypt the text are all stored together in a class. I chose to structure it this way as these three things belong together. A text encrypted by this program can only be decrypted by the decryption function in the same program. A class also allows for a more versatile usage. You can write a function that uses this class to take the text input as a command-line prompt, or as text or anything really.

For this project I have chosen to use class Cipher in a function that takes inputs as a text file with the message the user wishes to encrypt/decrypt, then outputs another text file with the result.

class Cipfer:

encryption_key(self) is a function that prompts the user to input a key of unlimited length. It uses a regular expression to check that the input only contains printable ASCII characters with HEX 21 - 7E. If not, an error message is displayed and the program exits. I selected this range as it contains most printable characters used in the english language, and it does not make sence to have non-printable characters in what many users might think of as a password.

This function also creates a list of the ASCII codes (codes 33 - 126, same as HEX 21 - 7E) for each character in the key, and that list is later used in both the encrypt() and decrypt() functions.

encrypt(self, message) takes text as a parameter and uses the list of codes from encryption_key() to encrypt it. The function iterates over the list of codes from the key, as well as the text itself. The first character in the text is encrypted using the first character from the key, the second character from the list is encrypted using the second character in the key, and so on. When the key is shorter than the message, it loops back over the key. This means each character in the message is encrypted using a different character from the key to the ones surrounding it, making it impossible to decipher the encryption using a simple frequency analysis.

The function only encrypts printable ASCII characters, as listed here: https://www.ascii-code.com/characters/printable-characters. I selected to stick within this range as this covers most printable characters used in the english language, and this class is only meant to be used to encrypt non-safety-critical text in english, like secret messages between friends. Things like emojis and special charters like å, ä or ö (taken from the Swedish alphabet) can be left as they are without compromising the purpose of any program where this class is used.

decrypt(self, encrypted) does the exact same thing as the encrypt function, but in reverse. The only real difference is that the ASCII number for the character in they key is subtracted instead of added to the ASCII number of the character in the text.

main():

The main() function calls three other functions to let the user select if they wish to encrypt or decrypt a text, select a file to be read, use class Cipher to input a key and perfom the selected action, and output a .txt file with the result. I chose to add these three steps as their own functions rather than write it all in the same main function as I find it often is best practice to do so. As separate functions I could use them in multiple parts of my program, even if I have chosen not to do that this time.

mode_selection() prompts the user to type 'e' or 'd' to select if they wish to encryt or decrypt, and checks the input using a regular expression. The program exits if the input is incorrect.

file_selection() promts the user to type in the name the file they wish to use, and returns it as a file object to main() where Cipher is used to enrypt to decrypt the text depending on the user's previous selection.

printing_file(output_file) takes an argument from main() with the encrypted or decrypted text and prints it to a .txt file. The user is promted to input a file name they wish to name the output, but the file format is hard coded in to the function. I have chosen to hard-code the file format .txt as this program is only meant to handle text, and I want it to be clear in my code which file format the returned file will be saved in.

test_project.py:

This file is for testing the functions in project.py. It contains 5 test functions, one to test encryption_key, one to test the encrypt and decrypt functions combined, one to test mode_selection, one to test file_selection and finally one to test printing_file. The reason behind testing both the encrypt and decrypt functions in the same test, is that they belong together. You cannot decrypt a file without first having encrytped it, so the test encrypts and decrypts on consecutive lines, then maches the decrypted text with the input to check it is the same.

This file also contains an explanation with links to documentation for the fictures, methods and functions that I used to make sure the test can run without input from a user. I also had to replace the input a user eould have provided, as well as replace files with a temporary directory for testing. All this syntax was new to me and I had to spend a lot of time reading documentation.

List of links to documentation used for project.py and test_project.py:

  1. enumerate(): https://docs.python.org/3/library/functions.html#enumerate
  2. ord(): https://docs.python.org/3/library/functions.html#ord
  3. ACII codes: https://www.ascii-code.com/characters/printable-characters
  4. Unicode: https://docs.python.org/3/howto/unicode.html
  5. list(): https://docs.python.org/3/library/stdtypes.html#list
  6. chr(): https://docs.python.org/3/library/functions.html#chr
  7. monkeypatch: https://docs.pytest.org/en/stable/how-to/monkeypatch.html
  8. monkeypatch.setattr: https://docs.pytest.org/en/stable/reference/reference.html#pytest.MonkeyPatch.setattr
  9. builtins: https://docs.python.org/3/library/builtins.html
  10. lambda: https://realpython.com/python-lambda/
  11. tmp_path: https://docs.pytest.org/en/stable/how-to/tmp_path.html

About

Final project CS50 Python

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages