{{tag>projects cloud club computing virtualization machines VMs AWS Azure GCP}} [[python_club|About the Club]]\\ ==== Python Club Topics - Exercise: Encryption & Decryption ==== ==== Exercise: Encryption and Decryption ==== - Output: The user will request a cyper ( encryption/decryption method ) and input a string of text. For the encryption process, the user will enter the string in plain text. For the decryption process, the user will enter the encrypted text. The program will then supply the resulting string, opposite of what was entered. - What you learn from the example: - Cryptography cyphers ( encryption/decryption method ) - Create a choice menu - Error handling - Use a class / object - Input validation ==== Solution ==== #!/usr/bin/env python3 ''' Encryption and Decryption Tool =============================== A command-line tool that provides various encryption and decryption methods: - Caesar cipher (shift cipher) - Vigenère cipher - Base64 encoding/decoding - Fernet symmetric encryption (using cryptography library) Features: - Multiple encryption/decryption methods - Input validation for messages and keys - Error handling for invalid inputs - File operations for saving/loading encrypted messages - Secure key management for Fernet encryption ''' import os import sys import base64 import json import getpass from pathlib import Path from typing import Dict, Any, Tuple, Optional, Union, List # Try to import cryptography, show helpful error if not installed try: from cryptography.fernet import Fernet from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC CRYPTOGRAPHY_AVAILABLE = True except ImportError: CRYPTOGRAPHY_AVAILABLE = False class TextColors: '''ANSI color codes for terminal output styling.''' HEADER = '\033[95m' BLUE = '\033[94m' CYAN = '\033[96m' GREEN = '\033[92m' WARNING = '\033[93m' FAIL = '\033[91m' ENDC = '\033[0m' BOLD = '\033[1m' UNDERLINE = '\033[4m' def clear_screen(): '''Clear the terminal screen.''' os.system('cls' if os.name == 'nt' else 'clear') def print_header(text: str): '''Print a formatted header.''' print(f'\n{TextColors.HEADER}{TextColors.BOLD}{text}{TextColors.ENDC}') def print_success(text: str): '''Print a success message.''' print(f'{TextColors.GREEN}{text}{TextColors.ENDC}') def print_warning(text: str): '''Print a warning message.''' print(f'{TextColors.WARNING}{text}{TextColors.ENDC}') def print_error(text: str): '''Print an error message.''' print(f'{TextColors.FAIL}{text}{TextColors.ENDC}') def input_with_validation(prompt: str, validator=None, error_msg: str = 'Invalid input') -> str: ''' Get user input with validation. Args: prompt: The input prompt to display validator: A function that returns True if input is valid error_msg: Message to display if validation fails Returns: The validated user input ''' while True: user_input = input(prompt) if validator is None or validator(user_input): return user_input print_error(error_msg) def caesar_cipher_encrypt(text: str, shift: int) -> str: ''' Encrypt text using Caesar cipher (shift cipher). Args: text: The plaintext to encrypt shift: The shift value (how many positions to shift each character) Returns: The encrypted text ''' result = '' for char in text: if char.isalpha(): ascii_offset = ord('A') if char.isupper() else ord('a') # Convert to 0-25, apply shift, mod 26, convert back to ASCII shifted = (ord(char) - ascii_offset + shift) % 26 + ascii_offset result += chr(shifted) else: result += char return result def caesar_cipher_decrypt(text: str, shift: int) -> str: ''' Decrypt text using Caesar cipher (shift cipher). Args: text: The encrypted text shift: The shift value used for encryption Returns: The decrypted text ''' return caesar_cipher_encrypt(text, -shift) def vigenere_cipher_encrypt(text: str, key: str) -> str: ''' Encrypt text using Vigenère cipher. Args: text: The plaintext to encrypt key: The encryption key (a word or phrase) Returns: The encrypted text ''' result = '' key = key.upper() key_length = len(key) key_as_int = [ord(k) - ord('A') for k in key] key_index = 0 for char in text: if char.isalpha(): # Convert to 0-25, apply key shift, mod 26, convert back to ASCII ascii_offset = ord('A') if char.isupper() else ord('a') key_shift = key_as_int[key_index % key_length] shifted = (ord(char) - ascii_offset + key_shift) % 26 + ascii_offset result += chr(shifted) key_index += 1 else: result += char return result def vigenere_cipher_decrypt(text: str, key: str) -> str: ''' Decrypt text using Vigenère cipher. Args: text: The encrypted text key: The encryption key used for encryption Returns: The decrypted text ''' result = '' key = key.upper() key_length = len(key) key_as_int = [ord(k) - ord('A') for k in key] key_index = 0 for char in text: if char.isalpha(): # Convert to 0-25, apply negative key shift, mod 26, convert back to ASCII ascii_offset = ord('A') if char.isupper() else ord('a') key_shift = key_as_int[key_index % key_length] shifted = (ord(char) - ascii_offset - key_shift) % 26 + ascii_offset result += chr(shifted) key_index += 1 else: result += char return result def base64_encode(text: str) -> str: ''' Encode text using Base64 encoding. Args: text: The plaintext to encode Returns: The Base64 encoded text ''' text_bytes = text.encode('utf-8') encoded_bytes = base64.b64encode(text_bytes) return encoded_bytes.decode('utf-8') def base64_decode(encoded_text: str) -> str: ''' Decode Base64 encoded text. Args: encoded_text: The Base64 encoded text Returns: The decoded text ''' try: encoded_bytes = encoded_text.encode('utf-8') decoded_bytes = base64.b64decode(encoded_bytes) return decoded_bytes.decode('utf-8') except Exception as e: raise ValueError(f'Invalid Base64 string: {str(e)}') def derive_key_from_password(password: str, salt: Optional[bytes] = None) -> Tuple[bytes, bytes]: ''' Derive a secure key from a password using PBKDF2. Args: password: The password to derive the key from salt: Optional salt for key derivation, generated if not provided Returns: A tuple of (key, salt) ''' if not salt: salt = os.urandom(16) kdf = PBKDF2HMAC( algorithm=hashes.SHA256(), length=32, salt=salt, iterations=100000, ) key = base64.urlsafe_b64encode(kdf.derive(password.encode('utf-8'))) return key, salt def fernet_encrypt(text: str, password: str) -> Dict[str, Union[str, bytes]]: ''' Encrypt text using Fernet symmetric encryption. Args: text: The plaintext to encrypt password: The password to derive the encryption key from Returns: A dictionary containing the encrypted text and salt ''' # Derive a key from the password key, salt = derive_key_from_password(password) # Create a Fernet cipher with the derived key cipher = Fernet(key) # Encrypt the text encrypted_bytes = cipher.encrypt(text.encode('utf-8')) encrypted_text = encrypted_bytes.decode('utf-8') # Return the encrypted text and salt (needed for decryption) return { 'encrypted_text': encrypted_text, 'salt': salt } def fernet_decrypt(encrypted_data: Dict[str, Union[str, bytes]], password: str) -> str: ''' Decrypt text that was encrypted using Fernet. Args: encrypted_data: Dictionary containing the encrypted text and salt password: The password used for encryption Returns: The decrypted text ''' encrypted_text = encrypted_data['encrypted_text'] salt = encrypted_data['salt'] # Derive the same key using the password and stored salt key, _ = derive_key_from_password(password, salt) # Create a Fernet cipher with the derived key cipher = Fernet(key) try: # Decrypt the text decrypted_bytes = cipher.decrypt(encrypted_text.encode('utf-8')) return decrypted_bytes.decode('utf-8') except Exception as e: raise ValueError(f'Decryption failed: {str(e)}. This could be due to an incorrect password or corrupted data.') def save_to_file(data: Dict[str, Any], filename: str): ''' Save encrypted data to a file. Args: data: The data to save filename: The file to save to ''' # Convert binary salt to hex string for JSON serialization if 'salt' in data and isinstance(data['salt'], bytes): data = data.copy() # Create a copy to avoid modifying the original data['salt'] = data['salt'].hex() with open(filename, 'w') as f: json.dump(data, f) def load_from_file(filename: str) -> Dict[str, Any]: ''' Load encrypted data from a file. Args: filename: The file to load from Returns: The loaded data ''' with open(filename, 'r') as f: data = json.load(f) # Convert hex string back to bytes if 'salt' in data and isinstance(data['salt'], str): data['salt'] = bytes.fromhex(data['salt']) return data def handle_caesar_cipher(): '''Handle Caesar cipher encryption/decryption.''' print_header('Caesar Cipher (Shift Cipher)') print_warning('Note: Caesar cipher is not secure for sensitive information.') operation = input_with_validation( 'Choose operation (1=Encrypt, 2=Decrypt): ', lambda x: x in ['1', '2'], 'Please enter 1 or 2.' ) text = input('Enter the text: ') shift = input_with_validation( 'Enter the shift value (1-25): ', lambda x: x.isdigit() and 1 ⇐ int(x) ⇐ 25, 'Please enter a number between 1 and 25.' ) shift = int(shift) if operation == '1': result = caesar_cipher_encrypt(text, shift) print_success(f'\nEncrypted text: {result}') else: result = caesar_cipher_decrypt(text, shift) print_success(f'\nDecrypted text: {result}') save_option = input_with_validation( '\nDo you want to save the result to a file? (y/n): ', lambda x: x.lower() in ['y', 'n'], 'Please enter 'y' or 'n'.' ) if save_option.lower() == 'y': filename = input('Enter filename to save: ') data = { 'method': 'caesar', 'result': result, 'shift': shift, 'operation': 'encrypt' if operation == '1' else 'decrypt' } save_to_file(data, filename) print_success(f'Result saved to {filename}') def handle_vigenere_cipher(): '''Handle Vigenère cipher encryption/decryption.''' print_header('Vigenère Cipher') print_warning('Note: Vigenère cipher is not secure for sensitive information.') operation = input_with_validation( 'Choose operation (1=Encrypt, 2=Decrypt): ', lambda x: x in ['1', '2'], 'Please enter 1 or 2.' ) text = input('Enter the text: ') key = input_with_validation( 'Enter the key (letters only): ', lambda x: x.isalpha() and len(x) > 0, 'Key must contain only letters and cannot be empty.' ) if operation == '1': result = vigenere_cipher_encrypt(text, key) print_success(f'\nEncrypted text: {result}') else: result = vigenere_cipher_decrypt(text, key) print_success(f'\nDecrypted text: {result}') save_option = input_with_validation( '\nDo you want to save the result to a file? (y/n): ', lambda x: x.lower() in ['y', 'n'], 'Please enter 'y' or 'n'.' ) if save_option.lower() == 'y': filename = input('Enter filename to save: ') data = { 'method': 'vigenere', 'result': result, 'key': key, 'operation': 'encrypt' if operation == '1' else 'decrypt' } save_to_file(data, filename) print_success(f'Result saved to {filename}') def handle_base64(): '''Handle Base64 encoding/decoding.''' print_header('Base64 Encoding/Decoding') print_warning('Note: Base64 is an encoding, not encryption. It provides no security.') operation = input_with_validation( 'Choose operation (1=Encode, 2=Decode): ', lambda x: x in ['1', '2'], 'Please enter 1 or 2.' ) if operation == '1': text = input('Enter the text to encode: ') try: result = base64_encode(text) print_success(f'\nBase64 encoded: {result}') except Exception as e: print_error(f'Encoding error: {str(e)}') return else: encoded_text = input('Enter the Base64 text to decode: ') try: result = base64_decode(encoded_text) print_success(f'\nDecoded text: {result}') except ValueError as e: print_error(f'{str(e)}') return except Exception as e: print_error(f'Decoding error: {str(e)}') return save_option = input_with_validation( '\nDo you want to save the result to a file? (y/n): ', lambda x: x.lower() in ['y', 'n'], 'Please enter 'y' or 'n'.' ) if save_option.lower() == 'y': filename = input('Enter filename to save: ') data = { 'method': 'base64', 'result': result, 'operation': 'encode' if operation == '1' else 'decode' } save_to_file(data, filename) print_success(f'Result saved to {filename}') def handle_fernet(): '''Handle Fernet encryption/decryption.''' if not CRYPTOGRAPHY_AVAILABLE: print_error('Fernet encryption requires the 'cryptography' library.') print_error('Please install it with: pip install cryptography') return print_header('Fernet Symmetric Encryption') print_success('Note: Fernet provides strong encryption suitable for sensitive data.') operation = input_with_validation( 'Choose operation (1=Encrypt, 2=Decrypt): ', lambda x: x in ['1', '2'], 'Please enter 1 or 2.' ) if operation == '1': # Encryption text = input('Enter the text to encrypt: ') password = getpass.getpass('Enter a strong password: ') confirm_password = getpass.getpass('Confirm password: ') if password != confirm_password: print_error('Passwords do not match!') return if len(password) < 8: print_warning('Warning: Password is less than 8 characters. This may not be secure.') proceed = input_with_validation( 'Continue anyway? (y/n): ', lambda x: x.lower() in ['y', 'n'], 'Please enter 'y' or 'n'.' ) if proceed.lower() != 'y': return try: encrypted_data = fernet_encrypt(text, password) print_success('\nText encrypted successfully!') # Ask to save to file save_option = input_with_validation( 'Do you want to save the encrypted data to a file? (y/n): ', lambda x: x.lower() in ['y', 'n'], 'Please enter 'y' or 'n'.' ) if save_option.lower() == 'y': filename = input('Enter filename to save: ') save_to_file(encrypted_data, filename) print_success(f'Encrypted data saved to {filename}') print_warning(f'Keep this file and your password safe. You will need both to decrypt.') except Exception as e: print_error(f'Encryption error: {str(e)}') else: # Decryption load_option = input_with_validation( 'Load encrypted data from file? (y/n): ', lambda x: x.lower() in ['y', 'n'], 'Please enter 'y' or 'n'.' ) if load_option.lower() == 'y': try: filename = input('Enter filename to load: ') encrypted_data = load_from_file(filename) if 'encrypted_text' not in encrypted_data or 'salt' not in encrypted_data: print_error('Invalid file format. File does not contain required encryption data.') return except FileNotFoundError: print_error(f'File not found: {filename}') return except json.JSONDecodeError: print_error(f'Invalid JSON in file: {filename}') return except Exception as e: print_error(f'Error loading file: {str(e)}') return else: encrypted_text = input('Enter the encrypted text: ') salt_hex = input('Enter the salt (hex format): ') try: salt = bytes.fromhex(salt_hex) encrypted_data = { 'encrypted_text': encrypted_text, 'salt': salt } except ValueError: print_error('Invalid salt format. Must be a hexadecimal string.') return password = getpass.getpass('Enter the password used for encryption: ') try: decrypted_text = fernet_decrypt(encrypted_data, password) print_success('\nDecryption successful!') print_success(f'Decrypted text: {decrypted_text}') except ValueError as e: print_error(f'{str(e)}') except Exception as e: print_error(f'Decryption error: {str(e)}') def load_encrypted_file(): '''Load an encrypted file and process it.''' print_header('Load Encrypted File') try: filename = input('Enter the filename to load: ') data = load_from_file(filename) if 'method' not in data: print_error('Invalid file format. Cannot determine encryption method.') return method = data['method'] print_success(f'File loaded successfully. Method: {method}') if method == 'caesar': shift = data.get('shift') if shift is None: print_error('Invalid file: missing shift value for Caesar cipher.') return if data.get('operation') == 'encrypt': # If it was encrypted, we now decrypt text = data.get('result', '') result = caesar_cipher_decrypt(text, shift) print_success(f'Decrypted text: {result}') else: # If it was decrypted, we show it result = data.get('result', '') print_success(f'Decrypted text: {result}') elif method == 'vigenere': key = data.get('key') if key is None: print_error('Invalid file: missing key for Vigenère cipher.') return if data.get('operation') == 'encrypt': # If it was encrypted, we now decrypt text = data.get('result', '') result = vigenere_cipher_decrypt(text, key) print_success(f'Decrypted text: {result}') else: # If it was decrypted, we show it result = data.get('result', '') print_success(f'Decrypted text: {result}') elif method == 'base64': result = data.get('result', '') operation = data.get('operation', '') print_success(f'{'Encoded' if operation == 'encode' else 'Decoded'} text: {result}') else: print_warning('This file needs to be decrypted with the appropriate method.') print_warning('Please use the main menu to select the correct decryption option.') except FileNotFoundError: print_error(f'File not found.') except json.JSONDecodeError: print_error(f'Invalid JSON in file.') except Exception as e: print_error(f'Error loading file: {str(e)}') def main_menu(): '''Display the main menu and handle user choices.''' while True: clear_screen() print_header('Encryption and Decryption Tool') print('Select an option:') print(f' 1. {TextColors.CYAN}Caesar Cipher{TextColors.ENDC} (Shift Cipher)') print(f' 2. {TextColors.CYAN}Vigenère Cipher{TextColors.ENDC}') print(f' 3. {TextColors.CYAN}Base64{TextColors.ENDC} Encoding/Decoding') print(f' 4. {TextColors.CYAN}Fernet{TextColors.ENDC} Symmetric Encryption') print(f' 5. {TextColors.CYAN}Load{TextColors.ENDC} Encrypted File') print(f' 6. {TextColors.CYAN}Exit{TextColors.ENDC}') choice = input_with_validation( '\nEnter your choice (1-6): ', lambda x: x in ['1', '2', '3', '4', '5', '6'], 'Please enter a number between 1 and 6.' ) if choice == '1': handle_caesar_cipher() elif choice == '2': handle_vigenere_cipher() elif choice == '3': handle_base64() elif choice == '4': handle_fernet() elif choice == '5': load_encrypted_file() elif choice == '6': clear_screen() print_success('Thank you for using the Encryption and Decryption Tool!') print_success('Goodbye!') sys.exit(0) input('\nPress Enter to return to the main menu…') def check_dependencies(): '''Check if required dependencies are installed.''' missing_deps = [] if not CRYPTOGRAPHY_AVAILABLE: missing_deps.append('cryptography') if missing_deps: print_warning('Some optional dependencies are missing:') for dep in missing_deps: print(f' - {dep}') print('\nYou can install them with:') print(f' pip install {' '.join(missing_deps)}') print('\nNote: The program will still run, but some features may be unavailable.') input('\nPress Enter to continue…') if __name__ == '__main__': try: clear_screen() print_header('Welcome to the Encryption and Decryption Tool') print('This program provides various methods to encrypt and decrypt messages.') print('Some methods are for educational purposes only and are not secure.') check_dependencies() print('\nReady to begin!') input('Press Enter to continue…') main_menu() except KeyboardInterrupt: print('\n\nProgram interrupted. Exiting…') sys.exit(0) #!/usr/bin/env python3 ''' Encryption and Decryption Tool =============================== A command-line tool that provides various encryption and decryption methods: - Caesar cipher (shift cipher) - Vigenère cipher - Base64 encoding/decoding - Fernet symmetric encryption (using cryptography library) Features: - Multiple encryption/decryption methods - Input validation for messages and keys - Error handling for invalid inputs - File operations for saving/loading encrypted messages - Secure key management for Fernet encryption ''' import os import sys import base64 import json import getpass from pathlib import Path from typing import Dict, Any, Tuple, Optional, Union, List # Try to import cryptography, show helpful error if not installed try: from cryptography.fernet import Fernet from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC CRYPTOGRAPHY_AVAILABLE = True except ImportError: CRYPTOGRAPHY_AVAILABLE = False class TextColors: '''ANSI color codes for terminal output styling.''' HEADER = '\033[95m' BLUE = '\033[94m' CYAN = '\033[96m' GREEN = '\033[92m' WARNING = '\033[93m' FAIL = '\033[91m' ENDC = '\033[0m' BOLD = '\033[1m' UNDERLINE = '\033[4m' def clear_screen(): '''Clear the terminal screen.''' os.system('cls' if os.name == 'nt' else 'clear') def print_header(text: str): '''Print a formatted header.''' print(f'\n{TextColors.HEADER}{TextColors.BOLD}{text}{TextColors.ENDC}') def print_success(text: str): '''Print a success message.''' print(f'{TextColors.GREEN}{text}{TextColors.ENDC}') def print_warning(text: str): '''Print a warning message.''' print(f'{TextColors.WARNING}{text}{TextColors.ENDC}') def print_error(text: str): '''Print an error message.''' print(f'{TextColors.FAIL}{text}{TextColors.ENDC}') def input_with_validation(prompt: str, validator=None, error_msg: str = 'Invalid input') -> str: ''' Get user input with validation. Args: prompt: The input prompt to display validator: A function that returns True if input is valid error_msg: Message to display if validation fails Returns: The validated user input ''' while True: user_input = input(prompt) if validator is None or validator(user_input): return user_input print_error(error_msg) def caesar_cipher_encrypt(text: str, shift: int) -> str: ''' Encrypt text using Caesar cipher (shift cipher). Args: text: The plaintext to encrypt shift: The shift value (how many positions to shift each character) Returns: The encrypted text ''' result = '' for char in text: if char.isalpha(): ascii_offset = ord('A') if char.isupper() else ord('a') # Convert to 0-25, apply shift, mod 26, convert back to ASCII shifted = (ord(char) - ascii_offset + shift) % 26 + ascii_offset result += chr(shifted) else: result += char return result def caesar_cipher_decrypt(text: str, shift: int) -> str: ''' Decrypt text using Caesar cipher (shift cipher). Args: text: The encrypted text shift: The shift value used for encryption Returns: The decrypted text ''' return caesar_cipher_encrypt(text, -shift) def vigenere_cipher_encrypt(text: str, key: str) -> str: ''' Encrypt text using Vigenère cipher. Args: text: The plaintext to encrypt key: The encryption key (a word or phrase) Returns: The encrypted text ''' result = '' key = key.upper() key_length = len(key) key_as_int = [ord(k) - ord('A') for k in key] key_index = 0 for char in text: if char.isalpha(): # Convert to 0-25, apply key shift, mod 26, convert back to ASCII ascii_offset = ord('A') if char.isupper() else ord('a') key_shift = key_as_int[key_index % key_length] shifted = (ord(char) - ascii_offset + key_shift) % 26 + ascii_offset result += chr(shifted) key_index += 1 else: result += char return result def vigenere_cipher_decrypt(text: str, key: str) -> str: ''' Decrypt text using Vigenère cipher. Args: text: The encrypted text key: The encryption key used for encryption Returns: The decrypted text ''' result = '' key = key.upper() key_length = len(key) key_as_int = [ord(k) - ord('A') for k in key] key_index = 0 for char in text: if char.isalpha(): # Convert to 0-25, apply negative key shift, mod 26, convert back to ASCII ascii_offset = ord('A') if char.isupper() else ord('a') key_shift = key_as_int[key_index % key_length] shifted = (ord(char) - ascii_offset - key_shift) % 26 + ascii_offset result += chr(shifted) key_index += 1 else: result += char return result def base64_encode(text: str) -> str: ''' Encode text using Base64 encoding. Args: text: The plaintext to encode Returns: The Base64 encoded text ''' text_bytes = text.encode('utf-8') encoded_bytes = base64.b64encode(text_bytes) return encoded_bytes.decode('utf-8') def base64_decode(encoded_text: str) -> str: ''' Decode Base64 encoded text. Args: encoded_text: The Base64 encoded text Returns: The decoded text ''' try: encoded_bytes = encoded_text.encode('utf-8') decoded_bytes = base64.b64decode(encoded_bytes) return decoded_bytes.decode('utf-8') except Exception as e: raise ValueError(f'Invalid Base64 string: {str(e)}') def derive_key_from_password(password: str, salt: Optional[bytes] = None) -> Tuple[bytes, bytes]: ''' Derive a secure key from a password using PBKDF2. Args: password: The password to derive the key from salt: Optional salt for key derivation, generated if not provided Returns: A tuple of (key, salt) ''' if not salt: salt = os.urandom(16) kdf = PBKDF2HMAC( algorithm=hashes.SHA256(), length=32, salt=salt, iterations=100000, ) key = base64.urlsafe_b64encode(kdf.derive(password.encode('utf-8'))) return key, salt def fernet_encrypt(text: str, password: str) -> Dict[str, Union[str, bytes]]: ''' Encrypt text using Fernet symmetric encryption. Args: text: The plaintext to encrypt password: The password to derive the encryption key from Returns: A dictionary containing the encrypted text and salt ''' # Derive a key from the password key, salt = derive_key_from_password(password) # Create a Fernet cipher with the derived key cipher = Fernet(key) # Encrypt the text encrypted_bytes = cipher.encrypt(text.encode('utf-8')) encrypted_text = encrypted_bytes.decode('utf-8') # Return the encrypted text and salt (needed for decryption) return { 'encrypted_text': encrypted_text, 'salt': salt } def fernet_decrypt(encrypted_data: Dict[str, Union[str, bytes]], password: str) -> str: ''' Decrypt text that was encrypted using Fernet. Args: encrypted_data: Dictionary containing the encrypted text and salt password: The password used for encryption Returns: The decrypted text ''' encrypted_text = encrypted_data['encrypted_text'] salt = encrypted_data['salt'] # Derive the same key using the password and stored salt key, _ = derive_key_from_password(password, salt) # Create a Fernet cipher with the derived key cipher = Fernet(key) try: # Decrypt the text decrypted_bytes = cipher.decrypt(encrypted_text.encode('utf-8')) return decrypted_bytes.decode('utf-8') except Exception as e: raise ValueError(f'Decryption failed: {str(e)}. This could be due to an incorrect password or corrupted data.') def save_to_file(data: Dict[str, Any], filename: str): ''' Save encrypted data to a file. Args: data: The data to save filename: The file to save to ''' # Convert binary salt to hex string for JSON serialization if 'salt' in data and isinstance(data['salt'], bytes): data = data.copy() # Create a copy to avoid modifying the original data['salt'] = data['salt'].hex() with open(filename, 'w') as f: json.dump(data, f) def load_from_file(filename: str) -> Dict[str, Any]: ''' Load encrypted data from a file. Args: filename: The file to load from Returns: The loaded data ''' with open(filename, 'r') as f: data = json.load(f) # Convert hex string back to bytes if 'salt' in data and isinstance(data['salt'], str): data['salt'] = bytes.fromhex(data['salt']) return data def handle_caesar_cipher(): '''Handle Caesar cipher encryption/decryption.''' print_header('Caesar Cipher (Shift Cipher)') print_warning('Note: Caesar cipher is not secure for sensitive information.') operation = input_with_validation( 'Choose operation (1=Encrypt, 2=Decrypt): ', lambda x: x in ['1', '2'], 'Please enter 1 or 2.' ) text = input('Enter the text: ') shift = input_with_validation( 'Enter the shift value (1-25): ', lambda x: x.isdigit() and 1 ⇐ int(x) ⇐ 25, 'Please enter a number between 1 and 25.' ) shift = int(shift) if operation == '1': result = caesar_cipher_encrypt(text, shift) print_success(f'\nEncrypted text: {result}') else: result = caesar_cipher_decrypt(text, shift) print_success(f'\nDecrypted text: {result}') save_option = input_with_validation( '\nDo you want to save the result to a file? (y/n): ', lambda x: x.lower() in ['y', 'n'], 'Please enter 'y' or 'n'.' ) if save_option.lower() == 'y': filename = input('Enter filename to save: ') data = { 'method': 'caesar', 'result': result, 'shift': shift, 'operation': 'encrypt' if operation == '1' else 'decrypt' } save_to_file(data, filename) print_success(f'Result saved to {filename}') def handle_vigenere_cipher(): '''Handle Vigenère cipher encryption/decryption.''' print_header('Vigenère Cipher') print_warning('Note: Vigenère cipher is not secure for sensitive information.') operation = input_with_validation( 'Choose operation (1=Encrypt, 2=Decrypt): ', lambda x: x in ['1', '2'], 'Please enter 1 or 2.' ) text = input('Enter the text: ') key = input_with_validation( 'Enter the key (letters only): ', lambda x: x.isalpha() and len(x) > 0, 'Key must contain only letters and cannot be empty.' ) if operation == '1': result = vigenere_cipher_encrypt(text, key) print_success(f'\nEncrypted text: {result}') else: result = vigenere_cipher_decrypt(text, key) print_success(f'\nDecrypted text: {result}') save_option = input_with_validation( '\nDo you want to save the result to a file? (y/n): ', lambda x: x.lower() in ['y', 'n'], 'Please enter 'y' or 'n'.' ) if save_option.lower() == 'y': filename = input('Enter filename to save: ') data = { 'method': 'vigenere', 'result': result, 'key': key, 'operation': 'encrypt' if operation == '1' else 'decrypt' } save_to_file(data, filename) print_success(f'Result saved to {filename}') def handle_base64(): '''Handle Base64 encoding/decoding.''' print_header('Base64 Encoding/Decoding') print_warning('Note: Base64 is an encoding, not encryption. It provides no security.') operation = input_with_validation( 'Choose operation (1=Encode, 2=Decode): ', lambda x: x in ['1', '2'], 'Please enter 1 or 2.' ) if operation == '1': text = input('Enter the text to encode: ') try: result = base64_encode(text) print_success(f'\nBase64 encoded: {result}') except Exception as e: print_error(f'Encoding error: {str(e)}') return else: encoded_text = input('Enter the Base64 text to decode: ') try: result = base64_decode(encoded_text) print_success(f'\nDecoded text: {result}') except ValueError as e: print_error(f'{str(e)}') return except Exception as e: print_error(f'Decoding error: {str(e)}') return save_option = input_with_validation( '\nDo you want to save the result to a file? (y/n): ', lambda x: x.lower() in ['y', 'n'], 'Please enter 'y' or 'n'.' ) if save_option.lower() == 'y': filename = input('Enter filename to save: ') data = { 'method': 'base64', 'result': result, 'operation': 'encode' if operation == '1' else 'decode' } save_to_file(data, filename) print_success(f'Result saved to {filename}') def handle_fernet(): '''Handle Fernet encryption/decryption.''' if not CRYPTOGRAPHY_AVAILABLE: print_error('Fernet encryption requires the 'cryptography' library.') print_error('Please install it with: pip install cryptography') return print_header('Fernet Symmetric Encryption') print_success('Note: Fernet provides strong encryption suitable for sensitive data.') operation = input_with_validation( 'Choose operation (1=Encrypt, 2=Decrypt): ', lambda x: x in ['1', '2'], 'Please enter 1 or 2.' ) if operation == '1': # Encryption text = input('Enter the text to encrypt: ') password = getpass.getpass('Enter a strong password: ') confirm_password = getpass.getpass('Confirm password: ') if password != confirm_password: print_error('Passwords do not match!') return if len(password) < 8: print_warning('Warning: Password is less than 8 characters. This may not be secure.') proceed = input_with_validation( 'Continue anyway? (y/n): ', lambda x: x.lower() in ['y', 'n'], 'Please enter 'y' or 'n'.' ) if proceed.lower() != 'y': return try: encrypted_data = fernet_encrypt(text, password) print_success('\nText encrypted successfully!') # Ask to save to file save_option = input_with_validation( 'Do you want to save the encrypted data to a file? (y/n): ', lambda x: x.lower() in ['y', 'n'], 'Please enter 'y' or 'n'.' ) if save_option.lower() == 'y': filename = input('Enter filename to save: ') save_to_file(encrypted_data, filename) print_success(f'Encrypted data saved to {filename}') print_warning(f'Keep this file and your password safe. You will need both to decrypt.') except Exception as e: print_error(f'Encryption error: {str(e)}') else: # Decryption load_option = input_with_validation( 'Load encrypted data from file? (y/n): ', lambda x: x.lower() in ['y', 'n'], 'Please enter 'y' or 'n'.' ) if load_option.lower() == 'y': try: filename = input('Enter filename to load: ') encrypted_data = load_from_file(filename) if 'encrypted_text' not in encrypted_data or 'salt' not in encrypted_data: print_error('Invalid file format. File does not contain required encryption data.') return except FileNotFoundError: print_error(f'File not found: {filename}') return except json.JSONDecodeError: print_error(f'Invalid JSON in file: {filename}') return except Exception as e: print_error(f'Error loading file: {str(e)}') return else: encrypted_text = input('Enter the encrypted text: ') salt_hex = input('Enter the salt (hex format): ') try: salt = bytes.fromhex(salt_hex) encrypted_data = { 'encrypted_text': encrypted_text, 'salt': salt } except ValueError: print_error('Invalid salt format. Must be a hexadecimal string.') return password = getpass.getpass('Enter the password used for encryption: ') try: decrypted_text = fernet_decrypt(encrypted_data, password) print_success('\nDecryption successful!') print_success(f'Decrypted text: {decrypted_text}') except ValueError as e: print_error(f'{str(e)}') except Exception as e: print_error(f'Decryption error: {str(e)}') def load_encrypted_file(): '''Load an encrypted file and process it.''' print_header('Load Encrypted File') try: filename = input('Enter the filename to load: ') data = load_from_file(filename) if 'method' not in data: print_error('Invalid file format. Cannot determine encryption method.') return method = data['method'] print_success(f'File loaded successfully. Method: {method}') if method == 'caesar': shift = data.get('shift') if shift is None: print_error('Invalid file: missing shift value for Caesar cipher.') return if data.get('operation') == 'encrypt': # If it was encrypted, we now decrypt text = data.get('result', '') result = caesar_cipher_decrypt(text, shift) print_success(f'Decrypted text: {result}') else: # If it was decrypted, we show it result = data.get('result', '') print_success(f'Decrypted text: {result}') elif method == 'vigenere': key = data.get('key') if key is None: print_error('Invalid file: missing key for Vigenère cipher.') return if data.get('operation') == 'encrypt': # If it was encrypted, we now decrypt text = data.get('result', '') result = vigenere_cipher_decrypt(text, key) print_success(f'Decrypted text: {result}') else: # If it was decrypted, we show it result = data.get('result', '') print_success(f'Decrypted text: {result}') elif method == 'base64': result = data.get('result', '') operation = data.get('operation', '') print_success(f'{'Encoded' if operation == 'encode' else 'Decoded'} text: {result}') else: print_warning('This file needs to be decrypted with the appropriate method.') print_warning('Please use the main menu to select the correct decryption option.') except FileNotFoundError: print_error(f'File not found.') except json.JSONDecodeError: print_error(f'Invalid JSON in file.') except Exception as e: print_error(f'Error loading file: {str(e)}') def main_menu(): '''Display the main menu and handle user choices.''' while True: clear_screen() print_header('Encryption and Decryption Tool') print('Select an option:') print(f' 1. {TextColors.CYAN}Caesar Cipher{TextColors.ENDC} (Shift Cipher)') print(f' 2. {TextColors.CYAN}Vigenère Cipher{TextColors.ENDC}') print(f' 3. {TextColors.CYAN}Base64{TextColors.ENDC} Encoding/Decoding') print(f' 4. {TextColors.CYAN}Fernet{TextColors.ENDC} Symmetric Encryption') print(f' 5. {TextColors.CYAN}Load{TextColors.ENDC} Encrypted File') print(f' 6. {TextColors.CYAN}Exit{TextColors.ENDC}') choice = input_with_validation( '\nEnter your choice (1-6): ', lambda x: x in ['1', '2', '3', '4', '5', '6'], 'Please enter a number between 1 and 6.' ) if choice == '1': handle_caesar_cipher() elif choice == '2': handle_vigenere_cipher() elif choice == '3': handle_base64() elif choice == '4': handle_fernet() elif choice == '5': load_encrypted_file() elif choice == '6': clear_screen() print_success('Thank you for using the Encryption and Decryption Tool!') print_success('Goodbye!') sys.exit(0) input('\nPress Enter to return to the main menu…') def check_dependencies(): '''Check if required dependencies are installed.''' missing_deps = [] if not CRYPTOGRAPHY_AVAILABLE: missing_deps.append('cryptography') if missing_deps: print_warning('Some optional dependencies are missing:') for dep in missing_deps: print(f' - {dep}') print('\nYou can install them with:') print(f' pip install {' '.join(missing_deps)}') print('\nNote: The program will still run, but some features may be unavailable.') input('\nPress Enter to continue…') if __name__ == '__main__': try: clear_screen() print_header('Welcome to the Encryption and Decryption Tool') print('This program provides various methods to encrypt and decrypt messages.') print('Some methods are for educational purposes only and are not secure.') check_dependencies() print('\nReady to begin!') input('Press Enter to continue…') main_menu() except KeyboardInterrupt: print('\n\nProgram interrupted. Exiting…') sys.exit(0) #!/usr/bin/env python3 ''' Encryption and Decryption Tool =============================== A command-line tool that provides various encryption and decryption methods: - Caesar cipher (shift cipher) - Vigenère cipher - Base64 encoding/decoding - Fernet symmetric encryption (using cryptography library) Features: - Multiple encryption/decryption methods - Input validation for messages and keys - Error handling for invalid inputs - File operations for saving/loading encrypted messages - Secure key management for Fernet encryption ''' import os import sys import base64 import json import getpass from pathlib import Path from typing import Dict, Any, Tuple, Optional, Union, List # Try to import cryptography, show helpful error if not installed try: from cryptography.fernet import Fernet from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC CRYPTOGRAPHY_AVAILABLE = True except ImportError: CRYPTOGRAPHY_AVAILABLE = False class TextColors: '''ANSI color codes for terminal output styling.''' HEADER = '\033[95m' BLUE = '\033[94m' CYAN = '\033[96m' GREEN = '\033[92m' WARNING = '\033[93m' FAIL = '\033[91m' ENDC = '\033[0m' BOLD = '\033[1m' UNDERLINE = '\033[4m' def clear_screen(): '''Clear the terminal screen.''' os.system('cls' if os.name == 'nt' else 'clear') def print_header(text: str): '''Print a formatted header.''' print(f'\n{TextColors.HEADER}{TextColors.BOLD}{text}{TextColors.ENDC}') def print_success(text: str): '''Print a success message.''' print(f'{TextColors.GREEN}{text}{TextColors.ENDC}') def print_warning(text: str): '''Print a warning message.''' print(f'{TextColors.WARNING}{text}{TextColors.ENDC}') def print_error(text: str): '''Print an error message.''' print(f'{TextColors.FAIL}{text}{TextColors.ENDC}') def input_with_validation(prompt: str, validator=None, error_msg: str = 'Invalid input') -> str: ''' Get user input with validation. Args: prompt: The input prompt to display validator: A function that returns True if input is valid error_msg: Message to display if validation fails Returns: The validated user input ''' while True: user_input = input(prompt) if validator is None or validator(user_input): return user_input print_error(error_msg) def caesar_cipher_encrypt(text: str, shift: int) -> str: ''' Encrypt text using Caesar cipher (shift cipher). Args: text: The plaintext to encrypt shift: The shift value (how many positions to shift each character) Returns: The encrypted text ''' result = '' for char in text: if char.isalpha(): ascii_offset = ord('A') if char.isupper() else ord('a') # Convert to 0-25, apply shift, mod 26, convert back to ASCII shifted = (ord(char) - ascii_offset + shift) % 26 + ascii_offset result += chr(shifted) else: result += char return result def caesar_cipher_decrypt(text: str, shift: int) -> str: ''' Decrypt text using Caesar cipher (shift cipher). Args: text: The encrypted text shift: The shift value used for encryption Returns: The decrypted text ''' return caesar_cipher_encrypt(text, -shift) def vigenere_cipher_encrypt(text: str, key: str) -> str: ''' Encrypt text using Vigenère cipher. Args: text: The plaintext to encrypt key: The encryption key (a word or phrase) Returns: The encrypted text ''' result = '' key = key.upper() key_length = len(key) key_as_int = [ord(k) - ord('A') for k in key] key_index = 0 for char in text: if char.isalpha(): # Convert to 0-25, apply key shift, mod 26, convert back to ASCII ascii_offset = ord('A') if char.isupper() else ord('a') key_shift = key_as_int[key_index % key_length] shifted = (ord(char) - ascii_offset + key_shift) % 26 + ascii_offset result += chr(shifted) key_index += 1 else: result += char return result def vigenere_cipher_decrypt(text: str, key: str) -> str: ''' Decrypt text using Vigenère cipher. Args: text: The encrypted text key: The encryption key used for encryption Returns: The decrypted text ''' result = '' key = key.upper() key_length = len(key) key_as_int = [ord(k) - ord('A') for k in key] key_index = 0 for char in text: if char.isalpha(): # Convert to 0-25, apply negative key shift, mod 26, convert back to ASCII ascii_offset = ord('A') if char.isupper() else ord('a') key_shift = key_as_int[key_index % key_length] shifted = (ord(char) - ascii_offset - key_shift) % 26 + ascii_offset result += chr(shifted) key_index += 1 else: result += char return result def base64_encode(text: str) -> str: ''' Encode text using Base64 encoding. Args: text: The plaintext to encode Returns: The Base64 encoded text ''' text_bytes = text.encode('utf-8') encoded_bytes = base64.b64encode(text_bytes) return encoded_bytes.decode('utf-8') def base64_decode(encoded_text: str) -> str: ''' Decode Base64 encoded text. Args: encoded_text: The Base64 encoded text Returns: The decoded text ''' try: encoded_bytes = encoded_text.encode('utf-8') decoded_bytes = base64.b64decode(encoded_bytes) return decoded_bytes.decode('utf-8') except Exception as e: raise ValueError(f'Invalid Base64 string: {str(e)}') def derive_key_from_password(password: str, salt: Optional[bytes] = None) -> Tuple[bytes, bytes]: ''' Derive a secure key from a password using PBKDF2. Args: password: The password to derive the key from salt: Optional salt for key derivation, generated if not provided Returns: A tuple of (key, salt) ''' if not salt: salt = os.urandom(16) kdf = PBKDF2HMAC( algorithm=hashes.SHA256(), length=32, salt=salt, iterations=100000, ) key = base64.urlsafe_b64encode(kdf.derive(password.encode('utf-8'))) return key, salt def fernet_encrypt(text: str, password: str) -> Dict[str, Union[str, bytes]]: ''' Encrypt text using Fernet symmetric encryption. Args: text: The plaintext to encrypt password: The password to derive the encryption key from Returns: A dictionary containing the encrypted text and salt ''' # Derive a key from the password key, salt = derive_key_from_password(password) # Create a Fernet cipher with the derived key cipher = Fernet(key) # Encrypt the text encrypted_bytes = cipher.encrypt(text.encode('utf-8')) encrypted_text = encrypted_bytes.decode('utf-8') # Return the encrypted text and salt (needed for decryption) return { 'encrypted_text': encrypted_text, 'salt': salt } def fernet_decrypt(encrypted_data: Dict[str, Union[str, bytes]], password: str) -> str: ''' Decrypt text that was encrypted using Fernet. Args: encrypted_data: Dictionary containing the encrypted text and salt password: The password used for encryption Returns: The decrypted text ''' encrypted_text = encrypted_data['encrypted_text'] salt = encrypted_data['salt'] # Derive the same key using the password and stored salt key, _ = derive_key_from_password(password, salt) # Create a Fernet cipher with the derived key cipher = Fernet(key) try: # Decrypt the text decrypted_bytes = cipher.decrypt(encrypted_text.encode('utf-8')) return decrypted_bytes.decode('utf-8') except Exception as e: raise ValueError(f'Decryption failed: {str(e)}. This could be due to an incorrect password or corrupted data.') def save_to_file(data: Dict[str, Any], filename: str): ''' Save encrypted data to a file. Args: data: The data to save filename: The file to save to ''' # Convert binary salt to hex string for JSON serialization if 'salt' in data and isinstance(data['salt'], bytes): data = data.copy() # Create a copy to avoid modifying the original data['salt'] = data['salt'].hex() with open(filename, 'w') as f: json.dump(data, f) def load_from_file(filename: str) -> Dict[str, Any]: ''' Load encrypted data from a file. Args: filename: The file to load from Returns: The loaded data ''' with open(filename, 'r') as f: data = json.load(f) # Convert hex string back to bytes if 'salt' in data and isinstance(data['salt'], str): data['salt'] = bytes.fromhex(data['salt']) return data def handle_caesar_cipher(): '''Handle Caesar cipher encryption/decryption.''' print_header('Caesar Cipher (Shift Cipher)') print_warning('Note: Caesar cipher is not secure for sensitive information.') operation = input_with_validation( 'Choose operation (1=Encrypt, 2=Decrypt): ', lambda x: x in ['1', '2'], 'Please enter 1 or 2.' ) text = input('Enter the text: ') shift = input_with_validation( 'Enter the shift value (1-25): ', lambda x: x.isdigit() and 1 ⇐ int(x) ⇐ 25, 'Please enter a number between 1 and 25.' ) shift = int(shift) if operation == '1': result = caesar_cipher_encrypt(text, shift) print_success(f'\nEncrypted text: {result}') else: result = caesar_cipher_decrypt(text, shift) print_success(f'\nDecrypted text: {result}') save_option = input_with_validation( '\nDo you want to save the result to a file? (y/n): ', lambda x: x.lower() in ['y', 'n'], 'Please enter 'y' or 'n'.' ) if save_option.lower() == 'y': filename = input('Enter filename to save: ') data = { 'method': 'caesar', 'result': result, 'shift': shift, 'operation': 'encrypt' if operation == '1' else 'decrypt' } save_to_file(data, filename) print_success(f'Result saved to {filename}') def handle_vigenere_cipher(): '''Handle Vigenère cipher encryption/decryption.''' print_header('Vigenère Cipher') print_warning('Note: Vigenère cipher is not secure for sensitive information.') operation = input_with_validation( 'Choose operation (1=Encrypt, 2=Decrypt): ', lambda x: x in ['1', '2'], 'Please enter 1 or 2.' ) text = input('Enter the text: ') key = input_with_validation( 'Enter the key (letters only): ', lambda x: x.isalpha() and len(x) > 0, 'Key must contain only letters and cannot be empty.' ) if operation == '1': result = vigenere_cipher_encrypt(text, key) print_success(f'\nEncrypted text: {result}') else: result = vigenere_cipher_decrypt(text, key) print_success(f'\nDecrypted text: {result}') save_option = input_with_validation( '\nDo you want to save the result to a file? (y/n): ', lambda x: x.lower() in ['y', 'n'], 'Please enter 'y' or 'n'.' ) if save_option.lower() == 'y': filename = input('Enter filename to save: ') data = { 'method': 'vigenere', 'result': result, 'key': key, 'operation': 'encrypt' if operation == '1' else 'decrypt' } save_to_file(data, filename) print_success(f'Result saved to {filename}') def handle_base64(): '''Handle Base64 encoding/decoding.''' print_header('Base64 Encoding/Decoding') print_warning('Note: Base64 is an encoding, not encryption. It provides no security.') operation = input_with_validation( 'Choose operation (1=Encode, 2=Decode): ', lambda x: x in ['1', '2'], 'Please enter 1 or 2.' ) if operation == '1': text = input('Enter the text to encode: ') try: result = base64_encode(text) print_success(f'\nBase64 encoded: {result}') except Exception as e: print_error(f'Encoding error: {str(e)}') return else: encoded_text = input('Enter the Base64 text to decode: ') try: result = base64_decode(encoded_text) print_success(f'\nDecoded text: {result}') except ValueError as e: print_error(f'{str(e)}') return except Exception as e: print_error(f'Decoding error: {str(e)}') return save_option = input_with_validation( '\nDo you want to save the result to a file? (y/n): ', lambda x: x.lower() in ['y', 'n'], 'Please enter 'y' or 'n'.' ) if save_option.lower() == 'y': filename = input('Enter filename to save: ') data = { 'method': 'base64', 'result': result, 'operation': 'encode' if operation == '1' else 'decode' } save_to_file(data, filename) print_success(f'Result saved to {filename}') def handle_fernet(): '''Handle Fernet encryption/decryption.''' if not CRYPTOGRAPHY_AVAILABLE: print_error('Fernet encryption requires the 'cryptography' library.') print_error('Please install it with: pip install cryptography') return print_header('Fernet Symmetric Encryption') print_success('Note: Fernet provides strong encryption suitable for sensitive data.') operation = input_with_validation( 'Choose operation (1=Encrypt, 2=Decrypt): ', lambda x: x in ['1', '2'], 'Please enter 1 or 2.' ) if operation == '1': # Encryption text = input('Enter the text to encrypt: ') password = getpass.getpass('Enter a strong password: ') confirm_password = getpass.getpass('Confirm password: ') if password != confirm_password: print_error('Passwords do not match!') return if len(password) < 8: print_warning('Warning: Password is less than 8 characters. This may not be secure.') proceed = input_with_validation( 'Continue anyway? (y/n): ', lambda x: x.lower() in ['y', 'n'], 'Please enter 'y' or 'n'.' ) if proceed.lower() != 'y': return try: encrypted_data = fernet_encrypt(text, password) print_success('\nText encrypted successfully!') # Ask to save to file save_option = input_with_validation( 'Do you want to save the encrypted data to a file? (y/n): ', lambda x: x.lower() in ['y', 'n'], 'Please enter 'y' or 'n'.' ) if save_option.lower() == 'y': filename = input('Enter filename to save: ') save_to_file(encrypted_data, filename) print_success(f'Encrypted data saved to {filename}') print_warning(f'Keep this file and your password safe. You will need both to decrypt.') except Exception as e: print_error(f'Encryption error: {str(e)}') else: # Decryption load_option = input_with_validation( 'Load encrypted data from file? (y/n): ', lambda x: x.lower() in ['y', 'n'], 'Please enter 'y' or 'n'.' ) if load_option.lower() == 'y': try: filename = input('Enter filename to load: ') encrypted_data = load_from_file(filename) if 'encrypted_text' not in encrypted_data or 'salt' not in encrypted_data: print_error('Invalid file format. File does not contain required encryption data.') return except FileNotFoundError: print_error(f'File not found: {filename}') return except json.JSONDecodeError: print_error(f'Invalid JSON in file: {filename}') return except Exception as e: print_error(f'Error loading file: {str(e)}') return else: encrypted_text = input('Enter the encrypted text: ') salt_hex = input('Enter the salt (hex format): ') try: salt = bytes.fromhex(salt_hex) encrypted_data = { 'encrypted_text': encrypted_text, 'salt': salt } except ValueError: print_error('Invalid salt format. Must be a hexadecimal string.') return password = getpass.getpass('Enter the password used for encryption: ') try: decrypted_text = fernet_decrypt(encrypted_data, password) print_success('\nDecryption successful!') print_success(f'Decrypted text: {decrypted_text}') except ValueError as e: print_error(f'{str(e)}') except Exception as e: print_error(f'Decryption error: {str(e)}') def load_encrypted_file(): '''Load an encrypted file and process it.''' print_header('Load Encrypted File') try: filename = input('Enter the filename to load: ') data = load_from_file(filename) if 'method' not in data: print_error('Invalid file format. Cannot determine encryption method.') return method = data['method'] print_success(f'File loaded successfully. Method: {method}') if method == 'caesar': shift = data.get('shift') if shift is None: print_error('Invalid file: missing shift value for Caesar cipher.') return if data.get('operation') == 'encrypt': # If it was encrypted, we now decrypt text = data.get('result', '') result = caesar_cipher_decrypt(text, shift) print_success(f'Decrypted text: {result}') else: # If it was decrypted, we show it result = data.get('result', '') print_success(f'Decrypted text: {result}') elif method == 'vigenere': key = data.get('key') if key is None: print_error('Invalid file: missing key for Vigenère cipher.') return if data.get('operation') == 'encrypt': # If it was encrypted, we now decrypt text = data.get('result', '') result = vigenere_cipher_decrypt(text, key) print_success(f'Decrypted text: {result}') else: # If it was decrypted, we show it result = data.get('result', '') print_success(f'Decrypted text: {result}') elif method == 'base64': result = data.get('result', '') operation = data.get('operation', '') print_success(f'{'Encoded' if operation == 'encode' else 'Decoded'} text: {result}') else: print_warning('This file needs to be decrypted with the appropriate method.') print_warning('Please use the main menu to select the correct decryption option.') except FileNotFoundError: print_error(f'File not found.') except json.JSONDecodeError: print_error(f'Invalid JSON in file.') except Exception as e: print_error(f'Error loading file: {str(e)}') def main_menu(): '''Display the main menu and handle user choices.''' while True: clear_screen() print_header('Encryption and Decryption Tool') print('Select an option:') print(f' 1. {TextColors.CYAN}Caesar Cipher{TextColors.ENDC} (Shift Cipher)') print(f' 2. {TextColors.CYAN}Vigenère Cipher{TextColors.ENDC}') print(f' 3. {TextColors.CYAN}Base64{TextColors.ENDC} Encoding/Decoding') print(f' 4. {TextColors.CYAN}Fernet{TextColors.ENDC} Symmetric Encryption') print(f' 5. {TextColors.CYAN}Load{TextColors.ENDC} Encrypted File') print(f' 6. {TextColors.CYAN}Exit{TextColors.ENDC}') choice = input_with_validation( '\nEnter your choice (1-6): ', lambda x: x in ['1', '2', '3', '4', '5', '6'], 'Please enter a number between 1 and 6.' ) if choice == '1': handle_caesar_cipher() elif choice == '2': handle_vigenere_cipher() elif choice == '3': handle_base64() elif choice == '4': handle_fernet() elif choice == '5': load_encrypted_file() elif choice == '6': clear_screen() print_success('Thank you for using the Encryption and Decryption Tool!') print_success('Goodbye!') sys.exit(0) input('\nPress Enter to return to the main menu…') def check_dependencies(): '''Check if required dependencies are installed.''' missing_deps = [] if not CRYPTOGRAPHY_AVAILABLE: missing_deps.append('cryptography') if missing_deps: print_warning('Some optional dependencies are missing:') for dep in missing_deps: print(f' - {dep}') print('\nYou can install them with:') print(f' pip install {' '.join(missing_deps)}') print('\nNote: The program will still run, but some features may be unavailable.') input('\nPress Enter to continue…') if __name__ == '__main__': try: clear_screen() print_header('Welcome to the Encryption and Decryption Tool') print('This program provides various methods to encrypt and decrypt messages.') print('Some methods are for educational purposes only and are not secure.') check_dependencies() print('\nReady to begin!') input('Press Enter to continue…') main_menu() except KeyboardInterrupt: print('\n\nProgram interrupted. Exiting…') sys.exit(0)