#!/usr/bin/env python3
# ==============================================================================
# DAE - Double At Email
# Python Decryption Tool (Cross-Platform)
# Task L - Client-Side eHead/eBody Decryption
# ==============================================================================
# Version: 2.0 (Task F Protocol)
# Author: DAE Development Team
# Date: 2026-01-31
# ==============================================================================
# This script helps users decrypt DAE encrypted emails
# without needing to use the web interface.
# Works on Windows, macOS, and Linux.
# ==============================================================================

import os
import sys
import base64
import gzip
import hashlib
from pathlib import Path
from datetime import datetime
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding, rsa
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend

# Try to import tkinter for file dialogs (may not be available on all systems)
try:
    import tkinter as tk
    from tkinter import filedialog, messagebox, simpledialog
    HAS_TKINTER = True
except ImportError:
    HAS_TKINTER = False
    print("WARNING: tkinter not available. Running in console-only mode.")

# ==============================================================================
# CONFIGURATION
# ==============================================================================
SCRIPT_VERSION = "2.0"
DAE_WEBSITE = "https://doubleat.email"

# ==============================================================================
# UTILITIES
# ==============================================================================

def print_banner():
    """Clear screen and display banner."""
    os.system('cls' if os.name == 'nt' else 'clear')
    print("=" * 60)
    print("  DAE - Double At Email Decrypt Tool")
    print("  Python Cross-Platform Tool")
    print(f"  Version {SCRIPT_VERSION} (Task F Protocol)")
    print("=" * 60)
    print()

def print_menu():
    """Display main menu."""
    print("Choose an option:")
    print("  1. Decrypt DAE Email")
    print("  2. Decrypt Download Link")
    print("  3. View Instructions")
    print("  4. About")
    print("  5. Exit")
    print()

def select_file(title, filetypes=None):
    """Open file selection dialog."""
    if filetypes is None:
        filetypes = [("All Files", "*.*")]

    if HAS_TKINTER:
        root = tk.Tk()
        root.withdraw()  # Hide main window
        filepath = filedialog.askopenfilename(
            title=title,
            filetypes=filetypes
        )
        root.destroy()
        return filepath if filepath else None
    else:
        # Console fallback
        print(f"\n{title}")
        print("Enter the full path to the file (or press ENTER to cancel):")
        filepath = input("> ").strip()
        return filepath if filepath and os.path.exists(filepath) else None

def save_file(title, default_filename, filetypes=None):
    """Open save file dialog."""
    if filetypes is None:
        filetypes = [("All Files", "*.*")]

    if HAS_TKINTER:
        root = tk.Tk()
        root.withdraw()
        filepath = filedialog.asksaveasfilename(
            title=title,
            defaultextension=".eml",
            initialfile=default_filename,
            filetypes=filetypes
        )
        root.destroy()
        return filepath if filepath else None
    else:
        # Console fallback
        print(f"\n{title}")
        print(f"Default: {default_filename}")
        print("Enter the full path to save (or press ENTER for default):")
        filepath = input("> ").strip()
        if not filepath:
            filepath = default_filename
        return filepath

def confirm_yes_no(message):
    """Ask user yes/no question."""
    if HAS_TKINTER:
        root = tk.Tk()
        root.withdraw()
        result = messagebox.askyesno("Confirm", message)
        root.destroy()
        return result
    else:
        print(f"\n{message} (Y/N)")
        response = input("> ").strip().lower()
        return response in ['y', 'yes']

# ==============================================================================
# CRYPTOGRAPHY FUNCTIONS
# ==============================================================================

def load_private_key(pem_path):
    """Load RSA private key from PEM file."""
    try:
        with open(pem_path, 'rb') as f:
            pem_data = f.read()

        # Try different formats
        try:
            # Try PKCS#8 first
            private_key = serialization.load_pem_private_key(
                pem_data,
                password=None,
                backend=default_backend()
            )
        except ValueError:
            # Try PKCS#1 (traditional OpenSSL format)
            try:
                private_key = serialization.load_pem_private_key(
                    pem_data,
                    password=None,
                    backend=default_backend()
                )
            except:
                raise ValueError("Failed to load private key. Ensure it's in PEM format.")

        # Verify it's actually a private key
        if not hasattr(private_key, 'key_size'):
            raise ValueError("The selected file is not a valid private key.")

        return private_key
    except Exception as e:
        raise Exception(f"Error loading private key: {str(e)}")

def decrypt_hybrid_data(encrypted_data, private_key):
    """
    Decrypt data encrypted with hybrid AES+RSA encryption.

    Format: [IV:16 bytes][Encrypted AES Key:512 bytes][Encrypted Data]
    """
    try:
        # Convert bytes to base64 string if needed
        if isinstance(encrypted_data, bytes):
            base64_string = encrypted_data.decode('ascii')
        else:
            base64_string = encrypted_data

        # Decode base64
        combined_data = base64.b64decode(base64_string)

        # Validate minimum size (IV: 16 bytes + Encrypted AES Key: 512 bytes)
        if len(combined_data) < 528:
            raise ValueError("Encrypted data too short. Invalid format.")

        # Extract components
        iv = combined_data[0:16]
        encrypted_aes_key = combined_data[16:528]
        encrypted_data = combined_data[528:]

        # Decrypt AES key with RSA private key (OAEP padding)
        aes_key = private_key.decrypt(
            encrypted_aes_key,
            padding.OAEP(
                mgf=padding.MGF1(algorithm=hashes.SHA1()),
                algorithm=hashes.SHA1(),
                label=None
            )
        )

        # Create AES cipher
        cipher = Cipher(
            algorithms.AES(aes_key),
            modes.CBC(iv),
            backend=default_backend()
        )
        decryptor = cipher.decryptor()

        # Decrypt data with AES
        decrypted_data = decryptor.update(encrypted_data) + decryptor.finalize()

        # Remove PKCS7 padding
        padding_length = decrypted_data[-1]
        decrypted_data = decrypted_data[:-padding_length]

        return decrypted_data
    except Exception as e:
        raise Exception(f"Decryption failed: {str(e)}")

def decrypt_download_link(encrypted_link, private_key):
    """Decrypt the download link using RSA."""
    try:
        # Decode base64
        encrypted_bytes = base64.b64decode(encrypted_link)

        # Decrypt with RSA OAEP
        decrypted_bytes = private_key.decrypt(
            encrypted_bytes,
            padding.OAEP(
                mgf=padding.MGF1(algorithm=hashes.SHA1()),
                algorithm=hashes.SHA1(),
                label=None
            )
        )

        # Convert to string
        url = decrypted_bytes.decode('utf-8')
        return url
    except Exception as e:
        raise Exception(f"Link decryption failed: {str(e)}")

def decompress_gzip(compressed_data):
    """Decompress gzip data."""
    try:
        return gzip.decompress(compressed_data)
    except Exception as e:
        raise Exception(f"Decompression failed: {str(e)}")

# ==============================================================================
# MAIN OPERATIONS
# ==============================================================================

def decrypt_dae_email():
    """Decrypt a DAE email (eHead + optional eBody)."""
    print_banner()
    print("Decrypt DAE Email")
    print("=================")
    print()

    # Step 1: Select eHead file
    print("Step 1: Select eHead file (from email attachment)")
    print("  This should be named something like: ehead_*.bin")
    print()

    ehead_path = select_file(
        "Select eHead File",
        [("Binary Files", "*.bin"), ("All Files", "*.*")]
    )

    if not ehead_path:
        print("Operation cancelled.")
        input("\nPress ENTER to continue")
        return

    print(f"  Selected: {os.path.basename(ehead_path)}")
    print()

    # Step 2: Select eBody file (optional)
    print("Step 2: Select eBody file (if applicable)")
    print("  This should be named something like: ebody_*.bin")
    print("  If the email was small, there may not be an eBody file.")
    print()
    if not HAS_TKINTER:
        print("  Press ENTER if you don't have an eBody file, or enter path:")

    ebody_path = select_file(
        "Select eBody File (Optional)",
        [("Binary Files", "*.bin"), ("All Files", "*.*")]
    )

    if ebody_path:
        print(f"  Selected: {os.path.basename(ebody_path)}")
    else:
        print("  No eBody file selected (email may be small)")
    print()

    # Step 3: Select private key file
    print("Step 3: Select your private key file")
    print("  This should be a .pem file downloaded when you registered")
    print()

    key_path = select_file(
        "Select Private Key File",
        [("PEM Files", "*.pem"), ("All Files", "*.*")]
    )

    if not key_path:
        print("Operation cancelled.")
        input("\nPress ENTER to continue")
        return

    print(f"  Selected: {os.path.basename(key_path)}")
    print()

    # Load private key
    print("Loading private key...")
    try:
        private_key = load_private_key(key_path)
        print("Private key loaded successfully.")
        print()
    except Exception as e:
        print(f"ERROR: {str(e)}")
        print("       Please select your PRIVATE key (.pem file).")
        input("\nPress ENTER to continue")
        return

    # Read files
    print("Reading encrypted files...")
    try:
        with open(ehead_path, 'rb') as f:
            ehead_data = f.read()

        ebody_data = None
        if ebody_path:
            with open(ebody_path, 'rb') as f:
                ebody_data = f.read()
    except Exception as e:
        print(f"ERROR: Could not read file: {str(e)}")
        input("\nPress ENTER to continue")
        return

    # Recombine eHead + eBody
    print("Combining eHead and eBody...")
    eemail = ehead_data
    if ebody_data:
        eemail = ehead_data + ebody_data

    print(f"Combined size: {len(eemail)} bytes")
    print()

    # Decrypt
    print("Decrypting (this may take a moment for large files)...")
    try:
        compressed = decrypt_hybrid_data(eemail, private_key)
        print("Decryption successful.")
        print(f"Compressed size: {len(compressed)} bytes")
        print()

        # Decompress
        print("Decompressing...")
        eml_data = decompress_gzip(compressed)
        print("Decompression successful.")
        print(f"Final size: {len(eml_data)} bytes")
        print()

        # Generate filename
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        default_name = f"decrypted_email_{timestamp}.eml"

        # Save .eml file
        print("Step 4: Save decrypted .eml file")
        save_path = save_file(
            "Save Decrypted Email",
            default_name,
            [("Email Files", "*.eml"), ("All Files", "*.*")]
        )

        if not save_path:
            print("Operation cancelled.")
            input("\nPress ENTER to continue")
            return

        # Write file
        os.makedirs(os.path.dirname(save_path) if os.path.dirname(save_path) else '.', exist_ok=True)
        with open(save_path, 'wb') as f:
            f.write(eml_data)

        print(f"File saved: {save_path}")
        print()

        # Parse .eml to show summary
        print("Parsing email headers...")
        eml_content = eml_data.decode('utf-8', errors='replace')
        subject = ""
        from_addr = ""
        to_addr = ""
        has_attachment = False

        for line in eml_content.split('\n'):
            if line.startswith('Subject:'):
                subject = line[8:].strip()
            elif line.startswith('From:'):
                from_addr = line[5:].strip()
            elif line.startswith('To:'):
                to_addr = line[3:].strip()
            elif 'multipart' in line.lower():
                has_attachment = True

        print()
        print("=" * 60)
        print("EMAIL SUCCESSFULLY DECRYPTED!")
        print("=" * 60)
        print()
        if subject:
            print(f"Subject: {subject}")
        if from_addr:
            print(f"From: {from_addr}")
        if to_addr:
            print(f"To: {to_addr}")
        if has_attachment:
            print("Has attachment: Yes")
        print()
        print(f"File saved to: {save_path}")
        print()

        # Ask to open file
        if confirm_yes_no("Do you want to open the .eml file now?"):
            import subprocess
            import platform
            try:
                if platform.system() == 'Windows':
                    os.startfile(save_path)
                elif platform.system() == 'Darwin':  # macOS
                    subprocess.run(['open', save_path])
                else:  # Linux
                    subprocess.run(['xdg-open', save_path])
                print("Opening in default email client...")
            except Exception as e:
                print(f"Could not open file: {str(e)}")

    except Exception as e:
        print()
        print(f"ERROR: {str(e)}")
        print()
        print("Troubleshooting tips:")
        print("  1. Make sure you selected the correct private key")
        print("  2. Verify eHead and eBody files are not corrupted")
        print("  3. Ensure the files are from the same email")
        print()

    input("\nPress ENTER to continue")

def decrypt_dae_link():
    """Decrypt a download link."""
    print_banner()
    print("Decrypt Download Link")
    print("====================")
    print()

    # Select private key
    print("Step 1: Select your private key file")
    key_path = select_file(
        "Select Private Key File",
        [("PEM Files", "*.pem"), ("All Files", "*.*")]
    )

    if not key_path:
        print("Operation cancelled.")
        input("\nPress ENTER to continue")
        return

    print(f"Private key loaded: {os.path.basename(key_path)}")
    print()

    # Load private key
    try:
        private_key = load_private_key(key_path)
    except Exception as e:
        print(f"ERROR: {str(e)}")
        input("\nPress ENTER to continue")
        return

    # Get encrypted link
    print("Step 2: Paste the encrypted download link")
    print("  (from the DAE email you received)")
    print()
    print("Paste the link (base64 string):")

    if HAS_TKINTER:
        root = tk.Tk()
        root.withdraw()
        encrypted_link = simpledialog.askstring(
            "Input",
            "Paste the encrypted download link (base64 string):",
            parent=root
        )
        root.destroy()
    else:
        encrypted_link = input("> ").strip()

    if not encrypted_link:
        print("Operation cancelled.")
        input("\nPress ENTER to continue")
        return

    print()
    print("Decrypting link...")

    try:
        url = decrypt_download_link(encrypted_link.strip(), private_key)

        print("Link decrypted successfully!")
        print()
        print("Your download URL:")
        print(url)
        print()
        print("Copy this URL and paste it in your browser to download the eBody.")
        print()

        # Ask to open in browser
        if confirm_yes_no("Do you want to open this URL in your browser now?"):
            import webbrowser
            webbrowser.open(url)
            print("Opening in browser...")

    except Exception as e:
        print()
        print(f"ERROR: {str(e)}")
        print()
        print("Troubleshooting tips:")
        print("  1. Make sure you copied the entire encrypted link")
        print("  2. Verify you're using the correct private key")
        print("  3. The link must be decrypted with the RECIPIENT'S private key")
        print()

    input("\nPress ENTER to continue")

def show_instructions():
    """Display instructions."""
    print_banner()
    print("DAE Decryption Instructions")
    print("===========================")
    print()

    print("HOW TO DECRYPT A DAE EMAIL:")
    print()
    print("1. You received an email with:")
    print("   - An eHead file attached (ehead_*.bin)")
    print("   - An encrypted download link (for eBody)")
    print()
    print("2. Use option 2 in this tool to decrypt the download link")
    print("   - Select your private key (.pem file)")
    print("   - Paste the encrypted link")
    print("   - You'll get the download URL")
    print()
    print("3. Visit the URL in your browser to download the eBody")
    print()
    print("4. Use option 1 in this tool to decrypt the email")
    print("   - Select eHead file (from email attachment)")
    print("   - Select eBody file (downloaded from URL)")
    print("   - Select your private key (.pem file)")
    print("   - The tool will generate a .eml file")
    print()
    print("5. Open the .eml file in your email client")
    print("   - Works with Outlook, Thunderbird, Windows Mail, etc.")
    print()
    print("SECURITY NOTES:")
    print("  - Only YOU can decrypt emails sent to you")
    print("  - Your private key is never shared or uploaded")
    print("  - Keep your private key safe and never share it!")
    print()

    input("\nPress ENTER to continue")

def show_about():
    """Display about information."""
    print_banner()
    print("About DAE Decrypt Tool")
    print("======================")
    print()

    print("DAE (Double At Email) - Encrypted Email System")
    print(f"Version: {SCRIPT_VERSION}")
    print("Protocol: Task F (eHead/eBody split)")
    print()
    print("FEATURES:")
    print("  - Client-side decryption (private key never leaves your computer)")
    print("  - Support for large files (hybrid AES+RSA encryption)")
    print("  - Standard .eml file output (works with any email client)")
    print("  - Download link decryption")
    print("  - Cross-platform (Windows, macOS, Linux)")
    print()
    print(f"WEBSITE: {DAE_WEBSITE}")
    print()
    print("This tool is open source and can be audited.")
    print("All decryption happens locally on your computer.")
    print()

    input("\nPress ENTER to continue")

# ==============================================================================
# MAIN LOOP
# ==============================================================================

def main():
    """Main application loop."""
    if not HAS_TKINTER:
        print("NOTE: Running in console-only mode (tkinter not available)")
        print("      For a better experience, install tkinter support.")
        print()
        input("Press ENTER to continue...")

    while True:
        print_banner()
        print_menu()

        choice = input("Enter your choice: ").strip()

        if choice == "1":
            decrypt_dae_email()
        elif choice == "2":
            decrypt_dae_link()
        elif choice == "3":
            show_instructions()
        elif choice == "4":
            show_about()
        elif choice == "5":
            print()
            print("Thank you for using DAE!")
            print(f"For more information: {DAE_WEBSITE}")
            print()
            break
        else:
            print()
            print("Invalid choice. Please try again.")
            print()
            import time
            time.sleep(1)

if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        print("\n\nExiting...")
        sys.exit(0)
