clubs:python_club:python_club_ex_crypt
Home | clubs :: cloud club :: python_club :: 3D-Printing | projects :: Proxmox | Kubernetes | scripting | utilities | games
Table of Contents
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
[1] code:python show
#!/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)
clubs/python_club/python_club_ex_crypt.txt · Last modified: by 127.0.0.1
