[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)