commit 04b358021a2b6ee728a7221103979bb74cbc89e7 Author: devoalda Date: Fri Apr 21 22:15:14 2023 +0800 Initial Commit diff --git a/Ciphers/CaesarCipher/CaesarCipher.py b/Ciphers/CaesarCipher/CaesarCipher.py new file mode 100644 index 0000000..0694e2f --- /dev/null +++ b/Ciphers/CaesarCipher/CaesarCipher.py @@ -0,0 +1,205 @@ +import os +import secrets +from collections import deque +from typing import IO + + +class CaesarCipher: + def __init__(self, shift: int, pad: deque = None, file_name: str = None, use_pad: bool = False, + file: IO[str] = None): + """ + Constructor for CaesarCipher class + :param shift: value to shift the alphabet by + :type shift: int + :param pad: pad to use for encryption/decryption + :type pad: deque + :param file_name: path to file containing pad + :type file_name: str + :param use_pad: True: use pad, False: generate pad + :type use_pad: bool + """ + + self.shift = shift + self.default_pad_length = 100 + self.file_type_dict = { + '.txt': { + 'function': self.convert_txt_to_list, + 'default_file_name': 'pad.txt' + }, + '.csv': { + 'function': self.convert_csv_to_list, + 'default_file_name': 'pad.csv' + } + } + + if use_pad is False: + self.pad = deque([0] * self.default_pad_length) + else: + if file_name: + file_name, file_extension = os.path.splitext(file_name) + print(f'{file_name}, {file_extension}') + if file_extension in self.file_type_dict: + self.file_type_dict[file_extension]["function"](file_name + file_extension) + if file: + self.read_file(file) + else: + self.pad = pad if pad else self.gen_pad(self.default_pad_length) + + def read_file(self, file: IO[str]) -> None: + """ + Read file object into deque, space delimited or comma delimited + :param file: file object to read + :type file: IO[str] + """ + # Try space delimited, then comma delimited + try: + self.pad = deque([int(num) for num in filter(str.isdigit, file.read().split(' '))]) + print(f'Space Pad: {self.pad}') + except ValueError: + self.pad = deque([int(num) for num in filter(str.isdigit, file.read().split(','))]) + print(f'comma Pad: {self.pad}') + except Exception as e: + print(f'Error reading file: {e}') + + def get_pad(self) -> int: + """ + Get the next value from the pad + :return: next value from the pad + :rtype: int + """ + + try: + pad_val = self.pad.popleft() + except (IndexError, AttributeError): + print(f'Error! Please pass the pad/pad file as an argument!') + self.gen_pad() + pad_val = self.pad.popleft() + + return pad_val + + def encrypt(self, plain_text: str) -> str: + """ + Encrypt plain_text using the Caesar Cipher + :param plain_text: text to encrypt + :type plain_text: str + :return: cipher text + :rtype: str + """ + + result = "" + for char in plain_text: + if not char.isalpha(): + result += char + else: + pad_val = self.get_pad() + result += chr((ord(char) + self.shift - 65 + pad_val) % 26 + 65) if char.isupper() else chr( + (ord(char) + self.shift - 97 + pad_val) % 26 + 97) + print(f'Result: {result}') + return result + + def decrypt(self, cipher_text: str) -> str: + """ + Decrypt cipher_text using the Caesar Cipher + :param cipher_text: text to decrypt + :type cipher_text: str + :return: plain text + :rtype: str + """ + + result = "" + for char in cipher_text: + if not char.isalpha(): + result += char + else: + pad_val = self.get_pad() + result += chr((ord(char) - self.shift - 65 - pad_val) % 26 + 65) if char.isupper() else chr( + (ord(char) - self.shift - 97 - pad_val) % 26 + 97) + return result + + def gen_pad(self, length: int = None) -> None: + """ + Generates a pad of random numbers, stores it in self.pad, and writes it to all default files (pad.txt, pad.csv) + :param length: length of pad to generate, defaults to 100 + :type length: int + :return: None + """ + + length = length if length else self.default_pad_length + pad = deque() + for i in range(length): + pad.append(secrets.randbelow(length)) + + self.pad = pad + # write to all default files + for key, value in self.file_type_dict.items(): + self.write_pad_to_file(value['default_file_name']) + + def write_pad_to_file(self, file_name: str = None) -> None: + """ + Writes the pad to a file. If no file name is provided, the default file name is used. + :param file_name: name of file to write pad to + :type file_name: str + :return: None + """ + + file_name = file_name if file_name else self.file_type_dict[os.path.splitext(file_name)[1]]['default_file_name'] + with open(file_name, 'w') as f: + if file_name.endswith('.csv'): + for i in self.pad: + f.write(f'{i},') + else: + for i in self.pad: + f.write(f'{i} ') + + def convert_txt_to_list(self, file_name: str = None) -> None: + """ + Parses a text file containing a pad and stores it in object + :param file_name: name of text file to read pad from + :type file_name: str + :return: None + """ + + file_name = file_name if file_name else self.file_type_dict[os.path.splitext(file_name)[1]]['default_file_name'] + try: + with open(file_name, 'r') as f: + pad = f.readline() + pad = [int(i) for i in pad.split(' ') if i.strip()] + self.pad = deque(pad) + + except FileNotFoundError: + print(f'File {file_name} not found. Please check the file name and try again.') + exit(1) + + def convert_csv_to_list(self, file_name: str = None) -> None: + """ + Parses a csv file containing a pad and stores it in object + :param file_name: name of csv file to read pad from + :return: None + """ + + file_name = file_name if file_name else self.file_type_dict[os.path.splitext(file_name)[1]]['default_file_name'] + try: + with open(file_name, 'r') as f: + pad = f.readline() + pad = [int(x) for x in pad.split(',') for x in x.split(' ') if x.strip()] + self.pad = deque(pad) + + except FileNotFoundError: + print(f'File {file_name} not found. Please check the file name and try again.') + exit(1) + + +if __name__ == "__main__": + text = "Hello World, this is a test!" + + cipher = CaesarCipher(40, use_pad=False) + enc = cipher.encrypt(text) + + decipher = CaesarCipher(40, use_pad=False) + dec = decipher.decrypt(enc) + + print(f'Original: {text}') + print(f'Encrypted: {enc}') + print(f'Decrypted: {dec}') + + assert text == dec, "Decrypted text does not match original text." diff --git a/app.py b/app.py new file mode 100644 index 0000000..447fa45 --- /dev/null +++ b/app.py @@ -0,0 +1,98 @@ +import io +import base64 + +from flask import Flask, render_template, request, jsonify + +from Ciphers.CaesarCipher.CaesarCipher import CaesarCipher + +app = Flask(__name__) + + +@app.route('/') +def index(): + return render_template('base.html') + + +@app.route('/b64', methods=['POST']) +def b64(): + if 'b64_plaintext_input' in request.form: + text = request.form['b64_plaintext_input'] + ciphertext_input = False + elif 'b64_ciphertext_input' in request.form: + text = request.form['b64_ciphertext_input'] + ciphertext_input = True + else: + return jsonify({'error': 'No input provided'}) + + result = {} + if ciphertext_input: + base64_bytes = text.encode("ascii") + sample_string_bytes = base64.b64decode(base64_bytes) + result['cleartext'] = str(sample_string_bytes, "ascii") + else: + sample_string_bytes = text.encode("ascii") + base64_bytes = base64.b64encode(sample_string_bytes) + # print(f'Encoded string: {base64_bytes.decode("ascii")}') + result['ciphertext'] = str(base64_bytes.decode("ascii")) + + return jsonify(result) + + +@app.route('/encrypt_decrypt', methods=['POST']) +def encrypt_decrypt(): + if 'plaintext_input' in request.form: + text = request.form['plaintext_input'] + ciphertext_input = False + elif 'ciphertext_input' in request.form: + text = request.form['ciphertext_input'] + ciphertext_input = True + else: + return jsonify({'error': 'No input provided'}) + + key = int(request.form['key']) + + result = {} + if ciphertext_input: + pad_file = request.files.get('pad_file') + if pad_file: + pad = io.StringIO(pad_file.stream.read().decode('utf-8')) + cipher = CaesarCipher(shift=key, use_pad=True, file=pad) + else: + cipher = CaesarCipher(shift=key, use_pad=False) + + result['cleartext'] = cipher.decrypt(text) + + if pad_file: + pad.seek(0) + new_cipher = CaesarCipher(shift=key, use_pad=True, file=pad) + encrypted_text = new_cipher.encrypt(result['cleartext']) + else: + new_cipher = CaesarCipher(shift=key, use_pad=False) + encrypted_text = new_cipher.encrypt(result['cleartext']) + + result['ciphertext'] = encrypted_text + else: + pad_file = request.files.get('pad_file') + if pad_file: + pad = io.StringIO(pad_file.stream.read().decode('utf-8')) + cipher = CaesarCipher(shift=key, use_pad=True, file=pad) + else: + cipher = CaesarCipher(shift=key, use_pad=False) + + result['ciphertext'] = cipher.encrypt(text) + + if pad_file: + pad.seek(0) + new_cipher = CaesarCipher(shift=key, use_pad=True, file=pad) + decrypted_text = new_cipher.decrypt(result['ciphertext']) + else: + new_cipher = CaesarCipher(shift=key, use_pad=False) + decrypted_text = new_cipher.decrypt(result['ciphertext']) + + result['cleartext'] = decrypted_text + + return jsonify(result) + + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=3000, debug=True) diff --git a/templates/CaesarDecrypt.html b/templates/CaesarDecrypt.html new file mode 100644 index 0000000..5f31866 --- /dev/null +++ b/templates/CaesarDecrypt.html @@ -0,0 +1,142 @@ +
+
+ + +
+ +
+ + + + + + + +
+
+
+ + +
+
+ Upload pad file: + + + +
+
+
+
+
+ +
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+ + \ No newline at end of file diff --git a/templates/CaesarEncrypt.html b/templates/CaesarEncrypt.html new file mode 100644 index 0000000..3fb60a7 --- /dev/null +++ b/templates/CaesarEncrypt.html @@ -0,0 +1,138 @@ +
+
+ + +
+ +
+ + + + + + + +
+
+
+ + +
+
+ + + +
+
+
+
+
+ + +
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+ + + + diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..2d34f81 --- /dev/null +++ b/templates/base.html @@ -0,0 +1,88 @@ + + + + + + + + + + + Cipher App + + +
+

Cipher App

+

Made with Flask

+

By: Devoalda

+
+
+

Caesar Cipher

+ +
+
+ + +
+ {% include "CaesarEncrypt.html" %} +
+
+
+ +
+ {% include "CaesarDecrypt.html" %} +
+
+
+
+ +
+

Base 64 Encoding

+
+ +
+ +
+
+ +
+ {% include "base64Encode.html" %} +
+
+
+ +
+ {% include "base64Decode.html" %} +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/templates/base64Decode.html b/templates/base64Decode.html new file mode 100644 index 0000000..de1d048 --- /dev/null +++ b/templates/base64Decode.html @@ -0,0 +1,30 @@ +
+
+ + +
+ + +
+
+
+ + diff --git a/templates/base64Encode.html b/templates/base64Encode.html new file mode 100644 index 0000000..84daa4c --- /dev/null +++ b/templates/base64Encode.html @@ -0,0 +1,31 @@ +
+
+ + +
+ + +
+
+
+ +