I am currently working on a Python script for AES encryption and decryption using the Crypto library. The encryption part seems to be working fine, but when I try to decrypt the text, the result is an empty string. I've reviewed my code, but I can't identify the issue. I would appreciate any insights or suggestions to help me debug and resolve this problem.
import hashlib
from Crypto.Cipher import AES
from Crypto import Random
from base64 import b64encode, b64decode
class AESCipher(object):
def __init__(self, key=None):
# Initialize the AESCipher object with a key, defaulting to a randomly generated key
self.block_size = AES.block_size
if key:
self.key = hashlib.sha256(key.encode()).digest()
else:
self.key = Random.new().read(self.block_size)
def encrypt(self, plain_text):
# Encrypt the provided plaintext using AES in CBC mode
plain_text = self.__pad(plain_text)
iv = Random.new().read(self.block_size)
cipher = AES.new(self.key, AES.MODE_CBC, iv)
encrypted_text = cipher.encrypt(plain_text)
# Combine IV and encrypted text, then base64 encode for safe representation
return b64encode(iv + encrypted_text).decode("utf-8")
def decrypt(self, encrypted_text):
# Decrypt the provided ciphertext using AES in CBC mode
encrypted_text = b64decode(encrypted_text)
iv = encrypted_text[:self.block_size]
cipher = AES.new(self.key, AES.MODE_CBC, iv)
plain_text = cipher.decrypt(encrypted_text[self.block_size:])
return self.__unpad(plain_text)
def get_key(self):
# Get the base64 encoded representation of the key
return b64encode(self.key).decode("utf-8")
def __pad(self, plain_text):
# Add PKCS7 padding to the plaintext
number_of_bytes_to_pad = self.block_size - len(plain_text) % self.block_size
padding_bytes = bytes([number_of_bytes_to_pad] * number_of_bytes_to_pad)
padded_plain_text = plain_text.encode() + padding_bytes
return padded_plain_text
@staticmethod
def __unpad(plain_text):
# Remove PKCS7 padding from the plaintext
last_byte = plain_text[-1]
return plain_text[:-last_byte] if isinstance(last_byte, int) else plain_text
def save_to_notepad(text, key, filename):
# Save encrypted text and key to a file
with open(filename, 'w') as file:
file.write(f"Key: {key}\nEncrypted text: {text}")
print(f"Text and key saved to {filename}")
def encrypt_and_save():
# Take user input, encrypt, and save to a file
user_input = ""
while not user_input:
user_input = input("Enter the plaintext: ")
aes_cipher = AESCipher() # Randomly generated key
encrypted_text = aes_cipher.encrypt(user_input)
key = aes_cipher.get_key()
filename = input("Enter the filename (including .txt extension): ")
save_to_notepad(encrypted_text, key, filename)
def decrypt_from_file():
# Decrypt encrypted text from a file using a key
filename = input("Enter the filename to decrypt (including .txt extension): ")
with open(filename, 'r') as file:
lines = file.readlines()
key = lines[0].split(":")[1].strip()
encrypted_text = lines[1].split(":")[1].strip()
aes_cipher = AESCipher(key)
decrypted_bytes = aes_cipher.decrypt(encrypted_text)
# Decoding only if the decrypted bytes are not empty
decrypted_text = decrypted_bytes.decode("utf-8") if decrypted_bytes else ""
print("Decrypted Text:", decrypted_text)
def encrypt_and_decrypt_in_command_line():
# Encrypt and then decrypt user input in the command line
user_input = ""
while not user_input:
user_input = input("Enter the plaintext: ")
aes_cipher = AESCipher()
encrypted_text = aes_cipher.encrypt(user_input)
key = aes_cipher.get_key()
print("Key:", key)
print("Encrypted Text:", encrypted_text)
decrypted_bytes = aes_cipher.decrypt(encrypted_text)
decrypted_text = decrypted_bytes.decode("utf-8") if decrypted_bytes else ""
print("Decrypted Text:", decrypted_text)
# Menu Interface
while True:
print("\nMenu:")
print("1. Encrypt and save to file")
print("2. Decrypt from file")
print("3. Encrypt and decrypt in command line")
print("4. Exit")
choice = input("Enter your choice (1, 2, 3, or 4): ")
if choice == '1':
encrypt_and_save()
elif choice == '2':
decrypt_from_file()
elif choice == '3':
encrypt_and_decrypt_in_command_line()
elif choice == '4':
print("Exiting the program. Goodbye!")
break
else:
print("Invalid choice. Please enter 1, 2, 3, or 4.")
AESCipher.get_key
method encodes the key as a base64
string.
Here is the relevant code:
def get_key(self):
# Get the base64 encoded representation of the key
return b64encode(self.key).decode("utf-8")
When you provide a key in the AESCipher
constructor, you need to decode the key instead of computing a digest.
Your constructor should look as follows:
class AESCipher(object):
def __init__(self, key=None):
# Initialize the AESCipher object with a key,
# defaulting to a randomly generated key
self.block_size = AES.block_size
if key:
self.key = b64decode(key.encode())
else:
self.key = Random.new().read(self.block_size)