please upgrade and revise also add a visual for indicating brute force progress in real time. import os
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import threading
import itertools
import base64
from cryptography.fernet import Fernet

class Crypt14Decryptor:
    def __init__(self, master):
        self.master = master
        master.title("Crypt14 Decryptor with Analysis")

        self.label = tk.Label(master, text="Select .crypt14 files for analysis:")
        self.label.pack()

        self.filepath_entry = tk.Entry(master, width=50)
        self.filepath_entry.pack()

        self.browse_button = tk.Button(master, text="Browse", command=self.browse_files)
        self.browse_button.pack()

        self.analyze_button = tk.Button(master, text="Analyze Files", command=self.analyze_files)
        self.analyze_button.pack()

        self.analysis_result = tk.Label(master, text="", wraplength=400)
        self.analysis_result.pack()

        self.key_label = tk.Label(master, text="Enter decryption key or enable brute-force:")
        self.key_label.pack()

        self.key_entry = tk.Entry(master, show='*', width=50)
        self.key_entry.pack()

        self.brute_force_var = tk.IntVar()
        self.brute_force_check = tk.Checkbutton(master, text="Enable Brute-force", variable=self.brute_force_var)
        self.brute_force_check.pack()

        self.decrypt_button = tk.Button(master, text="Decrypt Selected File", command=self.start_decrypt)
        self.decrypt_button.pack()

        self.progress = ttk.Progressbar(master, length=200, mode='determinate')
        self.progress.pack()

        self.file_list = []
        self.common_patterns = set()

    def browse_files(self):
        filenames = filedialog.askopenfilenames(filetypes=[("Crypt14 files", "*.crypt14")])
        self.filepath_entry.delete(0, tk.END)
        self.file_list = filenames
        self.filepath_entry.insert(0, ", ".join(os.path.basename(fn) for fn in self.file_list))

    def analyze_files(self):
        if not self.file_list:
            messagebox.showerror("Error", "Please select .crypt14 files for analysis.")
            return

        analysis_summary = "File Analysis:\n"
        total_size = 0
        pattern_counter = {}

        for filepath in self.file_list:
            file_size = os.path.getsize(filepath)
            total_size += file_size
            filename_root = os.path.splitext(os.path.basename(filepath))[0]
            for c in filename_root:
                if c in pattern_counter:
                    pattern_counter[c] += 1
                else:
                    pattern_counter[c] = 1

        self.common_patterns = {c for c, count in pattern_counter.items() if count > 1}

        analysis_summary += f"Total Files: {len(self.file_list)}\n"
        analysis_summary += f"Total Size: {total_size} bytes\n"
        analysis_summary += f"Common Patterns in Names: {', '.join(self.common_patterns) if self.common_patterns else 'None'}\n"

        self.analysis_result.config(text=analysis_summary)

    def start_decrypt(self):
        selected_key = self.key_entry.get().strip()

        if self.brute_force_var.get():
            if not self.file_list:
                messagebox.showerror("Error", "No files selected to decrypt.")
                return
            threading.Thread(target=self.brute_force_decrypt, args=(self.file_list[-1],)).start()
        else:
            if not selected_key:
                messagebox.showerror("Error", "Please provide a decryption key.")
                return

            if not self.file_list:
                messagebox.showerror("Error", "No files selected to decrypt.")
                return

            if len(selected_key) != 44:
                messagebox.showerror("Error", "Invalid key length. Fernet keys must be 44 characters long.")
                return

            threading.Thread(target=self.decrypt_file, args=(self.file_list[-1], selected_key)).start()

    def decrypt_file(self, filepath, selected_key):
        try:
            key = selected_key.encode()
            with open(filepath, 'rb') as file:
                encrypted_data = file.read()
            
            fernet = Fernet(key)

            try:
                decrypted_data = fernet.decrypt(encrypted_data)
            except Exception as e:
                messagebox.showerror("Error", f"Decryption failed: {str(e)}")
                return

            output_file = filepath.replace('.crypt14', '.decrypted')
            with open(output_file, 'wb') as file:
                file.write(decrypted_data)

            messagebox.showinfo("Success", f"File decrypted successfully: {output_file}")
        except Exception as e:
            messagebox.showerror("Error", f"An error occurred during decryption: {str(e)}")

    def brute_force_decrypt(self, filepath):
        if not self.common_patterns:
            messagebox.showerror("Error", "No common patterns found to use for brute-force.")
            return

        # Generate permutations of your pattern subset
        base_set = list(self.common_patterns) + ["A", "B", "C", "D"]  # Example to fill up pattern; adjust as needed
        base_set = base_set[:32]  # Ensure we have 32 characters for our key base

        for permutation in itertools.permutations(base_set, 32):
            try:
                key_candidate_bytes = bytes([ord(c) for c in permutation])
                key_candidate = base64.urlsafe_b64encode(key_candidate_bytes).decode()[:44]

                if len(key_candidate) == 44:
                    self.decrypt_file(filepath, key_candidate)
                    break
            except Exception:
                continue

if __name__ == "__main__":
    root = tk.Tk()
    decryptor = Crypt14Decryptor(root)
    root.mainloop()