Home » Tutorials » How to Encrypt and Decrypt Files in Python

How to Encrypt and Decrypt Files in Python

In our digital world, keeping our info safe is super important. Think of encryption and decryption like the trusty guardians of a castle, keeping the bad guys out but letting you through the gate whenever you need.

Today, you will learn how to encrypt and decrypt files using Python, it’s all about making your files accessible only to you. So, let’s get started and turn those files into fortresses!

Table of Contents

Necessary Libraries

Make sure to install the tkinter and cryptography libraries via the terminal or your command prompt for the code to function properly:

$ pip install tk
$ pip install cryptography

Imports

First, we import the tkinter library to create a graphical user interface (GUI). Then, we import filedialog and messagebox from tkinter, allowing us to select files for encryption or decryption and to use message boxes.

Following that, we import the Fernet class for encryption purposes. Finally, we import the os module, giving us the ability to interact with the operating system.

import tkinter as tk
from tkinter import filedialog, messagebox
from cryptography.fernet import Fernet
import os

Encrypt and Decrypt Files Functions

After importing the required libraries and modules, it’s time to define our functions – the heart of our Script:

generate_key and Loading Functions

When the user clicks the “Generate Key” button, the generate_key() function creates a random encryption key. It then creates a file named key.key where it stores the encryption key, thanks to the write_key_to_file() function.

The load_key_from_file() function plays its role when the user decides to encrypt or decrypt a file. This function loads the encryption key from the key.key file. However, if the user has never generated an encryption key, and thus the key.key file doesn’t exist, an error message will inform the user that the file storing the key doesn’t exist.

def generate_key(key_filename='key.key'):
   return Fernet.generate_key()


def write_key_to_file(key, filename='key.key'):
   with open(filename, 'wb') as f:
       f.write(key)


def load_key_from_file(filename='key.key'):
   if os.path.exists(filename):
       with open(filename, 'rb') as f:
           return f.read()
   else:
       raise FileNotFoundError(f"Key file '{filename}' not found.")

File Encryption Function

First, this function grabs the encryption key that’s already loaded and the filename the user has picked. It then opens the file, reads its contents, and encrypts the data using the Fernet cipher, which is set up with that encryption key.

After encryption, it writes the encrypted data to a new file, appending the .encryption extension to the filename. This process ensures that the original file remains preserved, and the function ultimately returns the filename of the encrypted file.

def encrypt_file(key, filename):
   cipher = Fernet(key)
   with open(filename, 'rb') as f:
       data = f.read()
       encrypted_data = cipher.encrypt(data)
   encrypted_filename = filename + '.encrypted'
   with open(encrypted_filename, 'wb') as f:
       f.write(encrypted_data)
   return encrypted_filename

File Decryption Function

This one retrieves the loaded decryption key and the filename selected by the user. It then proceeds to read the chosen file and decrypt its data using the Fernet cipher, which we initialized with the generated decryption key. Once decryption is complete, it writes the decrypted data to a new file, removing the “.encryption” extension.

Finally, it returns the filename of the decrypted file, thereby preserving the original file.

def decrypt_file(key, encrypted_filename):
   cipher = Fernet(key)
   with open(encrypted_filename, 'rb') as f:
       encrypted_data = f.read()
       decrypted_data = cipher.decrypt(encrypted_data)
   decrypted_filename = os.path.splitext(encrypted_filename)[0]
   with open(decrypted_filename, 'wb') as f:
       f.write(decrypted_data)
   return decrypted_filename

Event Handlers

Basically, this is the feedback given to the user when he clicks the buttons. For example, when the user generates an encryption key, a message indicating the success of the process and that the key is stored in the key.key file will appear. The same applies to the encryption and decryption processes: if they are successful, a message indicating that will be displayed; otherwise, an error message will appear.

So, all in all, this function triggers the key generation and loading functions, along with the file encryption and decryption functions (depending on the button clicked by the user), while providing feedback on whether these operations are successful or not. This is done by checking if the encryption key is successfully generated, stored, and loaded, and if the encryption and decryption processes are successful.

def generate_key_handler():
   key = generate_key()
   write_key_to_file(key)
   messagebox.showinfo("Key Generated", "Key generated and saved to 'key.key'")


def encrypt_file_handler():
   try:
       key = load_key_from_file()
       filename = filedialog.askopenfilename(title="Select File to Encrypt")
       if filename:
           encrypted_filename = encrypt_file(key, filename)
           messagebox.showinfo("File Encrypted", f"File encrypted successfully.\nEncrypted file: {encrypted_filename}")
   except Exception as e:
       messagebox.showerror("Error", f"An error occurred: {e}")


def decrypt_file_handler():
   try:
       key = load_key_from_file()
       filename = filedialog.askopenfilename(title="Select File to Decrypt")
       if filename:
           decrypted_filename = decrypt_file(key, filename)
           messagebox.showinfo("File Decrypted", f"File decrypted successfully.\nDecrypted file: {decrypted_filename}")
   except Exception as e:
       messagebox.showerror("Error", f"An error occurred: {e}")

Main Program Execution

Lastly, this part ensures that the script is run directly and not imported as a module. However, that’s not all; it also creates the main window, sets its geometry and title, and makes it non-resizable.

Additionally, it creates buttons where each one calls a specific function: the first one, named “Generate Key“, calls the generate_key_handler() function; the second, named “Encrypt File“, calls the encrypt_file_handler() function; and the last, named “Decrypt File“, calls the decrypt_file_handler() function. The final job of this part is to keep the main window running and responsive to the user.

if __name__ == "__main__":
   root = tk.Tk()
   root.title("File Encryptor - The Pycodes")
   root.geometry("350x200")
   root.resizable(False,False)


   generate_key_button = tk.Button(root, text="Generate Key", command=generate_key_handler)
   generate_key_button.pack(pady=10)


   encrypt_button = tk.Button(root, text="Encrypt File", command=encrypt_file_handler)
   encrypt_button.pack(pady=5)


   decrypt_button = tk.Button(root, text="Decrypt File", command=decrypt_file_handler)
   decrypt_button.pack(pady=5)

   root.mainloop()

Example

Be sure to encrypt and decrypt with the same key, otherwise, it will not work.

Full Code

import tkinter as tk
from tkinter import filedialog, messagebox
from cryptography.fernet import Fernet
import os


def generate_key(key_filename='key.key'):
   return Fernet.generate_key()


def write_key_to_file(key, filename='key.key'):
   with open(filename, 'wb') as f:
       f.write(key)


def load_key_from_file(filename='key.key'):
   if os.path.exists(filename):
       with open(filename, 'rb') as f:
           return f.read()
   else:
       raise FileNotFoundError(f"Key file '{filename}' not found.")


def encrypt_file(key, filename):
   cipher = Fernet(key)
   with open(filename, 'rb') as f:
       data = f.read()
       encrypted_data = cipher.encrypt(data)
   encrypted_filename = filename + '.encrypted'
   with open(encrypted_filename, 'wb') as f:
       f.write(encrypted_data)
   return encrypted_filename


def decrypt_file(key, encrypted_filename):
   cipher = Fernet(key)
   with open(encrypted_filename, 'rb') as f:
       encrypted_data = f.read()
       decrypted_data = cipher.decrypt(encrypted_data)
   decrypted_filename = os.path.splitext(encrypted_filename)[0]
   with open(decrypted_filename, 'wb') as f:
       f.write(decrypted_data)
   return decrypted_filename


def generate_key_handler():
   key = generate_key()
   write_key_to_file(key)
   messagebox.showinfo("Key Generated", "Key generated and saved to 'key.key'")


def encrypt_file_handler():
   try:
       key = load_key_from_file()
       filename = filedialog.askopenfilename(title="Select File to Encrypt")
       if filename:
           encrypted_filename = encrypt_file(key, filename)
           messagebox.showinfo("File Encrypted", f"File encrypted successfully.\nEncrypted file: {encrypted_filename}")
   except Exception as e:
       messagebox.showerror("Error", f"An error occurred: {e}")


def decrypt_file_handler():
   try:
       key = load_key_from_file()
       filename = filedialog.askopenfilename(title="Select File to Decrypt")
       if filename:
           decrypted_filename = decrypt_file(key, filename)
           messagebox.showinfo("File Decrypted", f"File decrypted successfully.\nDecrypted file: {decrypted_filename}")
   except Exception as e:
       messagebox.showerror("Error", f"An error occurred: {e}")


if __name__ == "__main__":
   root = tk.Tk()
   root.title("File Encryptor - The Pycodes")
   root.geometry("350x200")
   root.resizable(False,False)


   generate_key_button = tk.Button(root, text="Generate Key", command=generate_key_handler)
   generate_key_button.pack(pady=10)


   encrypt_button = tk.Button(root, text="Encrypt File", command=encrypt_file_handler)
   encrypt_button.pack(pady=5)


   decrypt_button = tk.Button(root, text="Decrypt File", command=decrypt_file_handler)
   decrypt_button.pack(pady=5)


   root.mainloop()

Happy Coding!

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top