diff --git a/app/__pycache__/__init__.cpython-313.pyc b/app/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index 73ef729..0000000 Binary files a/app/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/app/__pycache__/config.cpython-313.pyc b/app/__pycache__/config.cpython-313.pyc deleted file mode 100644 index 5db5fd5..0000000 Binary files a/app/__pycache__/config.cpython-313.pyc and /dev/null differ diff --git a/app/log/__pycache__/__init__.cpython-313.pyc b/app/log/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index 38aa441..0000000 Binary files a/app/log/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/app/log/__pycache__/exception_handling.cpython-313.pyc b/app/log/__pycache__/exception_handling.cpython-313.pyc deleted file mode 100644 index 3711321..0000000 Binary files a/app/log/__pycache__/exception_handling.cpython-313.pyc and /dev/null differ diff --git a/app/log/__pycache__/logger.cpython-313.pyc b/app/log/__pycache__/logger.cpython-313.pyc deleted file mode 100644 index e1f02ed..0000000 Binary files a/app/log/__pycache__/logger.cpython-313.pyc and /dev/null differ diff --git a/app/model/__pycache__/__init__.cpython-313.pyc b/app/model/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index f3cd27b..0000000 Binary files a/app/model/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/app/model/__pycache__/doc_cov_model.cpython-313.pyc b/app/model/__pycache__/doc_cov_model.cpython-313.pyc deleted file mode 100644 index 60e0312..0000000 Binary files a/app/model/__pycache__/doc_cov_model.cpython-313.pyc and /dev/null differ diff --git a/app/model/__pycache__/file_model.cpython-313.pyc b/app/model/__pycache__/file_model.cpython-313.pyc deleted file mode 100644 index 1a22ecf..0000000 Binary files a/app/model/__pycache__/file_model.cpython-313.pyc and /dev/null differ diff --git a/app/ui/__pycache__/Icon.cpython-313.pyc b/app/ui/__pycache__/Icon.cpython-313.pyc deleted file mode 100644 index 072199e..0000000 Binary files a/app/ui/__pycache__/Icon.cpython-313.pyc and /dev/null differ diff --git a/app/ui/__pycache__/__init__.cpython-313.pyc b/app/ui/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index b5f5ee0..0000000 Binary files a/app/ui/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/app/ui/__pycache__/global_signal.cpython-313.pyc b/app/ui/__pycache__/global_signal.cpython-313.pyc deleted file mode 100644 index 71cd536..0000000 Binary files a/app/ui/__pycache__/global_signal.cpython-313.pyc and /dev/null differ diff --git a/app/ui/__pycache__/mainview.cpython-313.pyc b/app/ui/__pycache__/mainview.cpython-313.pyc deleted file mode 100644 index cd04ede..0000000 Binary files a/app/ui/__pycache__/mainview.cpython-313.pyc and /dev/null differ diff --git a/app/ui/__pycache__/mainwindow.cpython-313.pyc b/app/ui/__pycache__/mainwindow.cpython-313.pyc deleted file mode 100644 index 96f5e86..0000000 Binary files a/app/ui/__pycache__/mainwindow.cpython-313.pyc and /dev/null differ diff --git a/app/ui/components/__pycache__/QCursorGif.cpython-313.pyc b/app/ui/components/__pycache__/QCursorGif.cpython-313.pyc deleted file mode 100644 index 8884f42..0000000 Binary files a/app/ui/components/__pycache__/QCursorGif.cpython-313.pyc and /dev/null differ diff --git a/app/ui/components/__pycache__/__init__.cpython-313.pyc b/app/ui/components/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index 61fb385..0000000 Binary files a/app/ui/components/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/app/ui/components/__pycache__/flowlayout.cpython-313.pyc b/app/ui/components/__pycache__/flowlayout.cpython-313.pyc deleted file mode 100644 index 9da849b..0000000 Binary files a/app/ui/components/__pycache__/flowlayout.cpython-313.pyc and /dev/null differ diff --git a/app/ui/components/__pycache__/router.cpython-313.pyc b/app/ui/components/__pycache__/router.cpython-313.pyc deleted file mode 100644 index ad6f030..0000000 Binary files a/app/ui/components/__pycache__/router.cpython-313.pyc and /dev/null differ diff --git a/app/ui/components/__pycache__/scroll_bar.cpython-313.pyc b/app/ui/components/__pycache__/scroll_bar.cpython-313.pyc deleted file mode 100644 index ab64718..0000000 Binary files a/app/ui/components/__pycache__/scroll_bar.cpython-313.pyc and /dev/null differ diff --git a/app/ui/components/file_list/__pycache__/__init__.cpython-313.pyc b/app/ui/components/file_list/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index ec44a1c..0000000 Binary files a/app/ui/components/file_list/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/app/ui/components/file_list/__pycache__/file_item_ui.cpython-313.pyc b/app/ui/components/file_list/__pycache__/file_item_ui.cpython-313.pyc deleted file mode 100644 index 49d21b5..0000000 Binary files a/app/ui/components/file_list/__pycache__/file_item_ui.cpython-313.pyc and /dev/null differ diff --git a/app/ui/components/sidebar/__pycache__/__init__.cpython-313.pyc b/app/ui/components/sidebar/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index 95539fe..0000000 Binary files a/app/ui/components/sidebar/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/app/ui/components/sidebar/__pycache__/sidebar.cpython-313.pyc b/app/ui/components/sidebar/__pycache__/sidebar.cpython-313.pyc deleted file mode 100644 index c1f40fe..0000000 Binary files a/app/ui/components/sidebar/__pycache__/sidebar.cpython-313.pyc and /dev/null differ diff --git a/app/ui/components/sidebar/__pycache__/sidebar_ui.cpython-313.pyc b/app/ui/components/sidebar/__pycache__/sidebar_ui.cpython-313.pyc deleted file mode 100644 index e9ba14b..0000000 Binary files a/app/ui/components/sidebar/__pycache__/sidebar_ui.cpython-313.pyc and /dev/null differ diff --git a/app/ui/doc_convert/__pycache__/__init__.cpython-313.pyc b/app/ui/doc_convert/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index bd77b10..0000000 Binary files a/app/ui/doc_convert/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/app/ui/doc_convert/__pycache__/doc_convert.cpython-313.pyc b/app/ui/doc_convert/__pycache__/doc_convert.cpython-313.pyc deleted file mode 100644 index c191ca5..0000000 Binary files a/app/ui/doc_convert/__pycache__/doc_convert.cpython-313.pyc and /dev/null differ diff --git a/app/ui/doc_convert/__pycache__/doc_convert_ui.cpython-313.pyc b/app/ui/doc_convert/__pycache__/doc_convert_ui.cpython-313.pyc deleted file mode 100644 index f0cbe0b..0000000 Binary files a/app/ui/doc_convert/__pycache__/doc_convert_ui.cpython-313.pyc and /dev/null differ diff --git a/app/ui/doc_convert/pdf2image/__pycache__/__init__.cpython-313.pyc b/app/ui/doc_convert/pdf2image/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index bbbf375..0000000 Binary files a/app/ui/doc_convert/pdf2image/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/app/ui/doc_convert/pdf2image/__pycache__/pdf2image.cpython-313.pyc b/app/ui/doc_convert/pdf2image/__pycache__/pdf2image.cpython-313.pyc deleted file mode 100644 index 4e9c50c..0000000 Binary files a/app/ui/doc_convert/pdf2image/__pycache__/pdf2image.cpython-313.pyc and /dev/null differ diff --git a/app/ui/doc_convert/pdf2image/__pycache__/pdf2image_ui.cpython-313.pyc b/app/ui/doc_convert/pdf2image/__pycache__/pdf2image_ui.cpython-313.pyc deleted file mode 100644 index 43a540a..0000000 Binary files a/app/ui/doc_convert/pdf2image/__pycache__/pdf2image_ui.cpython-313.pyc and /dev/null differ diff --git a/app/ui/doc_convert/pdf2wordui/__pycache__/__init__.cpython-313.pyc b/app/ui/doc_convert/pdf2wordui/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index 4ebd45d..0000000 Binary files a/app/ui/doc_convert/pdf2wordui/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/app/ui/doc_convert/pdf2wordui/__pycache__/pdf2word.cpython-313.pyc b/app/ui/doc_convert/pdf2wordui/__pycache__/pdf2word.cpython-313.pyc deleted file mode 100644 index 32c6a13..0000000 Binary files a/app/ui/doc_convert/pdf2wordui/__pycache__/pdf2word.cpython-313.pyc and /dev/null differ diff --git a/app/ui/doc_convert/pdf2wordui/__pycache__/pdf2word_ui.cpython-313.pyc b/app/ui/doc_convert/pdf2wordui/__pycache__/pdf2word_ui.cpython-313.pyc deleted file mode 100644 index a21e11f..0000000 Binary files a/app/ui/doc_convert/pdf2wordui/__pycache__/pdf2word_ui.cpython-313.pyc and /dev/null differ diff --git a/app/ui/doc_convert/web2pdf/__pycache__/__init__.cpython-313.pyc b/app/ui/doc_convert/web2pdf/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index 00d737d..0000000 Binary files a/app/ui/doc_convert/web2pdf/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/app/ui/doc_convert/web2pdf/__pycache__/web2pdf.cpython-313.pyc b/app/ui/doc_convert/web2pdf/__pycache__/web2pdf.cpython-313.pyc deleted file mode 100644 index 2ad5b14..0000000 Binary files a/app/ui/doc_convert/web2pdf/__pycache__/web2pdf.cpython-313.pyc and /dev/null differ diff --git a/app/ui/doc_convert/web2pdf/__pycache__/web2pdf_ui.cpython-313.pyc b/app/ui/doc_convert/web2pdf/__pycache__/web2pdf_ui.cpython-313.pyc deleted file mode 100644 index 5a849d5..0000000 Binary files a/app/ui/doc_convert/web2pdf/__pycache__/web2pdf_ui.cpython-313.pyc and /dev/null differ diff --git a/app/ui/image_tools/__pycache__/image_tool.cpython-313.pyc b/app/ui/image_tools/__pycache__/image_tool.cpython-313.pyc deleted file mode 100644 index dec8938..0000000 Binary files a/app/ui/image_tools/__pycache__/image_tool.cpython-313.pyc and /dev/null differ diff --git a/app/ui/image_tools/__pycache__/image_tool_ui.cpython-313.pyc b/app/ui/image_tools/__pycache__/image_tool_ui.cpython-313.pyc deleted file mode 100644 index d7be17f..0000000 Binary files a/app/ui/image_tools/__pycache__/image_tool_ui.cpython-313.pyc and /dev/null differ diff --git a/app/ui/image_tools/modify_date/__pycache__/modify_date.cpython-313.pyc b/app/ui/image_tools/modify_date/__pycache__/modify_date.cpython-313.pyc deleted file mode 100644 index 0834b3a..0000000 Binary files a/app/ui/image_tools/modify_date/__pycache__/modify_date.cpython-313.pyc and /dev/null differ diff --git a/app/ui/image_tools/modify_date/__pycache__/modify_date_ui.cpython-313.pyc b/app/ui/image_tools/modify_date/__pycache__/modify_date_ui.cpython-313.pyc deleted file mode 100644 index 119b9c6..0000000 Binary files a/app/ui/image_tools/modify_date/__pycache__/modify_date_ui.cpython-313.pyc and /dev/null differ diff --git a/app/ui/memotrace_enhance/__pycache__/__init__.cpython-313.pyc b/app/ui/memotrace_enhance/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index 63624d9..0000000 Binary files a/app/ui/memotrace_enhance/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/app/ui/memotrace_enhance/__pycache__/enhance.cpython-313.pyc b/app/ui/memotrace_enhance/__pycache__/enhance.cpython-313.pyc deleted file mode 100644 index 2a2ba3f..0000000 Binary files a/app/ui/memotrace_enhance/__pycache__/enhance.cpython-313.pyc and /dev/null differ diff --git a/app/ui/memotrace_enhance/__pycache__/enhance_ui.cpython-313.pyc b/app/ui/memotrace_enhance/__pycache__/enhance_ui.cpython-313.pyc deleted file mode 100644 index 83f92e6..0000000 Binary files a/app/ui/memotrace_enhance/__pycache__/enhance_ui.cpython-313.pyc and /dev/null differ diff --git a/app/ui/memotrace_enhance/toc/__pycache__/__init__.cpython-313.pyc b/app/ui/memotrace_enhance/toc/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index 3a4bbf2..0000000 Binary files a/app/ui/memotrace_enhance/toc/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/app/ui/memotrace_enhance/toc/__pycache__/toc.cpython-313.pyc b/app/ui/memotrace_enhance/toc/__pycache__/toc.cpython-313.pyc deleted file mode 100644 index 16ec5b9..0000000 Binary files a/app/ui/memotrace_enhance/toc/__pycache__/toc.cpython-313.pyc and /dev/null differ diff --git a/app/ui/memotrace_enhance/toc/__pycache__/toc_ui.cpython-313.pyc b/app/ui/memotrace_enhance/toc/__pycache__/toc_ui.cpython-313.pyc deleted file mode 100644 index 7d33503..0000000 Binary files a/app/ui/memotrace_enhance/toc/__pycache__/toc_ui.cpython-313.pyc and /dev/null differ diff --git a/app/ui/pdf_tools/__pycache__/__init__.cpython-313.pyc b/app/ui/pdf_tools/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index 7715147..0000000 Binary files a/app/ui/pdf_tools/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/app/ui/pdf_tools/__pycache__/pdf_tool.cpython-313.pyc b/app/ui/pdf_tools/__pycache__/pdf_tool.cpython-313.pyc deleted file mode 100644 index 4508de8..0000000 Binary files a/app/ui/pdf_tools/__pycache__/pdf_tool.cpython-313.pyc and /dev/null differ diff --git a/app/ui/pdf_tools/__pycache__/pdf_tool_ui.cpython-313.pyc b/app/ui/pdf_tools/__pycache__/pdf_tool_ui.cpython-313.pyc deleted file mode 100644 index 7f932a2..0000000 Binary files a/app/ui/pdf_tools/__pycache__/pdf_tool_ui.cpython-313.pyc and /dev/null differ diff --git a/app/ui/pdf_tools/merge/__pycache__/__init__.cpython-313.pyc b/app/ui/pdf_tools/merge/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index bd2e432..0000000 Binary files a/app/ui/pdf_tools/merge/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/app/ui/pdf_tools/merge/__pycache__/encrypt_dialog.cpython-313.pyc b/app/ui/pdf_tools/merge/__pycache__/encrypt_dialog.cpython-313.pyc deleted file mode 100644 index e299afd..0000000 Binary files a/app/ui/pdf_tools/merge/__pycache__/encrypt_dialog.cpython-313.pyc and /dev/null differ diff --git a/app/ui/pdf_tools/merge/__pycache__/encrypt_dialog_ui.cpython-313.pyc b/app/ui/pdf_tools/merge/__pycache__/encrypt_dialog_ui.cpython-313.pyc deleted file mode 100644 index b50d3f6..0000000 Binary files a/app/ui/pdf_tools/merge/__pycache__/encrypt_dialog_ui.cpython-313.pyc and /dev/null differ diff --git a/app/ui/pdf_tools/merge/__pycache__/merge.cpython-313.pyc b/app/ui/pdf_tools/merge/__pycache__/merge.cpython-313.pyc deleted file mode 100644 index 41b928f..0000000 Binary files a/app/ui/pdf_tools/merge/__pycache__/merge.cpython-313.pyc and /dev/null differ diff --git a/app/ui/pdf_tools/merge/__pycache__/merge_ui.cpython-313.pyc b/app/ui/pdf_tools/merge/__pycache__/merge_ui.cpython-313.pyc deleted file mode 100644 index 905ac2e..0000000 Binary files a/app/ui/pdf_tools/merge/__pycache__/merge_ui.cpython-313.pyc and /dev/null differ diff --git a/app/ui/pdf_tools/security/__pycache__/__init__.cpython-313.pyc b/app/ui/pdf_tools/security/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index f48ae8a..0000000 Binary files a/app/ui/pdf_tools/security/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/app/ui/pdf_tools/security/__pycache__/decrypt.cpython-313.pyc b/app/ui/pdf_tools/security/__pycache__/decrypt.cpython-313.pyc deleted file mode 100644 index 6939ba3..0000000 Binary files a/app/ui/pdf_tools/security/__pycache__/decrypt.cpython-313.pyc and /dev/null differ diff --git a/app/ui/pdf_tools/security/__pycache__/decrypt_ui.cpython-313.pyc b/app/ui/pdf_tools/security/__pycache__/decrypt_ui.cpython-313.pyc deleted file mode 100644 index c174c21..0000000 Binary files a/app/ui/pdf_tools/security/__pycache__/decrypt_ui.cpython-313.pyc and /dev/null differ diff --git a/app/ui/pdf_tools/security/__pycache__/encrypt.cpython-313.pyc b/app/ui/pdf_tools/security/__pycache__/encrypt.cpython-313.pyc deleted file mode 100644 index 97e2059..0000000 Binary files a/app/ui/pdf_tools/security/__pycache__/encrypt.cpython-313.pyc and /dev/null differ diff --git a/app/ui/pdf_tools/security/__pycache__/encrypt_ui.cpython-313.pyc b/app/ui/pdf_tools/security/__pycache__/encrypt_ui.cpython-313.pyc deleted file mode 100644 index e788176..0000000 Binary files a/app/ui/pdf_tools/security/__pycache__/encrypt_ui.cpython-313.pyc and /dev/null differ diff --git a/app/ui/pdf_tools/security/decrypt.py b/app/ui/pdf_tools/security/decrypt.py index 7a19428..f7d11ca 100644 --- a/app/ui/pdf_tools/security/decrypt.py +++ b/app/ui/pdf_tools/security/decrypt.py @@ -13,6 +13,20 @@ import fitz from PyPDF2 import PdfReader, PdfWriter + +# 导入Cython优化模块 +try: + import pdf_cracker + CYTHON_AVAILABLE = True +except ImportError: + CYTHON_AVAILABLE = False + +# 导入Hashcat GPU加速优化模块 +try: + import hashcat_wrapper + HASHCAT_WRAPPER_AVAILABLE = True +except ImportError: + HASHCAT_WRAPPER_AVAILABLE = False from PySide6.QtCore import Signal, QThread, QUrl, Qt, QFile, QIODevice, QTextStream from PySide6.QtGui import QDesktopServices, QPixmap, QIcon, QFont, QFontMetrics from PySide6.QtWidgets import (QWidget, QMessageBox, QFileDialog, QRadioButton, @@ -37,6 +51,45 @@ def open_file_explorer(path): QDesktopServices.openUrl(QUrl.fromLocalFile(path)) +# 尝试编译Cython模块 +def compile_cython_module(): + try: + import subprocess + import os + import sys + + # 获取当前文件所在目录 + current_dir = os.path.dirname(os.path.abspath(__file__)) + setup_path = os.path.join(current_dir, "setup.py") + + # 检查setup.py是否存在 + if not os.path.exists(setup_path): + logger.warning("setup.py不存在,无法编译Cython模块") + return False + + # 执行编译命令 + logger.info("开始编译Cython模块...") + cmd = [sys.executable, setup_path, "build_ext", "--inplace"] + process = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + cwd=current_dir + ) + stdout, stderr = process.communicate() + + # 检查编译结果 + if process.returncode == 0: + logger.info("Cython模块编译成功") + return True + else: + logger.error(f"Cython模块编译失败: {stderr.decode('utf-8', errors='ignore')}") + return False + except Exception as e: + logger.error(f"尝试编译Cython模块时出错: {str(e)}") + return False + + class DecryptControl(QWidget, Ui_decrypt_pdf_view, QCursorGif): okSignal = Signal(bool) childRouterSignal = Signal(str) @@ -58,6 +111,11 @@ def __init__(self, router: Router, parent=None): self.setCursorTimeout(100) self.init_ui() + # 如果Cython模块不可用,尝试编译 + if not CYTHON_AVAILABLE: + # 在后台线程中尝试编译,避免阻塞UI + threading.Thread(target=compile_cython_module, daemon=True).start() + # 按钮连接 self.btn_choose_file.clicked.connect(self.open_file_dialog) self.btn_choose_file.setIcon(Icon.Add_Icon) @@ -1345,7 +1403,99 @@ def run_crack_decrypt(self): return def run_gpu_crack(self): - """使用GPU加速进行密码破解""" + """使用GPU加速进行密码破解 - 优先使用Cython优化版本""" + # 检查是否可以使用Cython优化的Hashcat包装器 + if HASHCAT_WRAPPER_AVAILABLE: + try: + logger.info("使用Cython优化的Hashcat包装器进行GPU加速破解") + + # 获取设置 + is_dict_mode = self.crack_settings.get("mode") == "dictionary" + selected_gpus = self.crack_settings.get("selected_gpus", []) + hashcat_dir = self.crack_settings.get("hashcat_path", "") + gpu_threads = self.crack_settings.get("gpu_threads", 8) + gpu_accel = self.crack_settings.get("gpu_accel", 64) + workload = self.crack_settings.get("workload", 3) + min_len = self.crack_settings.get("min_length", 4) + max_len = self.crack_settings.get("max_length", 8) + charset = self.crack_settings.get("charset", "digits") + dict_path = self.crack_settings.get("dict_path", "") + + # 检查hashcat路径 + if not hashcat_dir: + self.okSignal.emit((False, "未指定Hashcat目录")) + return + + # 准备选项字典 + options = { + "mode": "dictionary" if is_dict_mode else "bruteforce", + "hashcat_path": hashcat_dir, + "selected_gpus": selected_gpus, + "gpu_threads": gpu_threads, + "gpu_accel": gpu_accel, + "workload": workload, + "min_length": min_len, + "max_length": max_len, + "charset": charset, + "dict_path": dict_path + } + + # 定义回调函数更新UI + def update_ui(message): + self.current_pwd_signal.emit(message) + # 更新进度条 + if "进度" in message or "GPU破解进度" in message: + try: + if "进度" in message: + progress_str = message.split("进度")[1].strip().split("%")[0] + else: + progress_str = message.split("GPU破解进度:")[1].strip().split("%")[0] + progress = float(progress_str) + self.progressSignal.emit(int(30 + progress * 0.6)) + except: + pass + + # 初始化进度 + self.progressSignal.emit(30) + + # 调用Cython优化的GPU破解函数 + success, password = hashcat_wrapper.gpu_crack_pdf( + self.input_file.file_path, + options, + update_ui + ) + + # 处理结果 + if success and password: + try: + # 验证密码 + self.current_pwd_signal.emit(f"验证密码: {password}") + with fitz.open(self.input_file.file_path) as pdf: + if pdf.authenticate(password): + # 保存解密后的PDF + pdf.save(self.output_path) + self.progressSignal.emit(100) + success_message = f"{os.path.dirname(self.output_path)}\n成功破解密码: {password}" + self.okSignal.emit((True, success_message)) + return + except Exception as e: + logger.error(f"验证密码失败: {str(e)}") + + # 如果被中断 + if self.isInterruptionRequested(): + logger.info("GPU破解过程被用户终止") + self.okSignal.emit((False, "用户终止了破解过程")) + return + + # 如果Cython优化版本失败,回退到原始实现 + logger.info("Cython优化的GPU破解未找到密码,尝试原始方法") + + except Exception as e: + logger.error(f"Cython GPU破解出错: {str(e)}") + logger.info("回退到原始GPU破解方法") + # 继续使用原始实现 + + # 原始实现 try: # 获取设置 is_dict_mode = self.crack_settings.get("mode") == "dictionary" @@ -1655,17 +1805,67 @@ def read_stderr(): return def run_dict_crack(self): - """使用字典破解密码 - 多线程版本""" + """使用字典破解密码 - 优先使用Cython优化版本""" dict_path = self.crack_settings.get("dict_path", "") if not os.path.exists(dict_path): self.okSignal.emit((False, "字典文件不存在")) return - + + # 获取线程数 + thread_count = self.crack_settings.get("threads", 4) + logger.info(f"使用 {thread_count} 个线程进行字典破解") + + # 使用Cython优化版本(如果可用) + if CYTHON_AVAILABLE: + try: + logger.info(f"使用Cython优化版本进行字典破解: {dict_path}") + self.current_pwd_signal.emit(f"正在使用Cython优化的多线程破解({thread_count}线程)...") + + # 定义回调函数更新UI + def update_ui(message): + self.current_pwd_signal.emit(message) + # 更新进度条 + if "进度" in message: + try: + progress_str = message.split("进度")[1].strip().split("%")[0] + progress = float(progress_str) + self.progressSignal.emit(int(30 + progress * 0.6)) + except: + pass + + # 调用Cython优化的字典破解函数 + success, found_password = pdf_cracker.dictionary_crack( + self.input_file.file_path, + dict_path, + thread_count, + update_ui + ) + + if success: + # 保存解密后的PDF + with fitz.open(self.input_file.file_path) as pdf: + pdf.authenticate(found_password) + pdf.save(self.output_path) + + self.progressSignal.emit(100) + success_message = f"{os.path.dirname(self.output_path)}\n成功使用密码: {found_password}" + self.okSignal.emit((True, success_message)) + return + elif self.isInterruptionRequested(): + logger.info("字典破解过程被用户终止") + self.okSignal.emit((False, "用户终止了破解过程")) + return + else: + logger.info("Cython优化版本字典破解失败,尝试原始方法") + # 如果Cython版本失败,回退到原始实现 + except Exception as e: + logger.error(f"Cython字典破解出错: {str(e)}") + logger.info("回退到原始字典破解方法") + # 继续使用原始实现 + + # 原始多线程实现 try: - logger.info(f"使用字典文件多线程破解: {dict_path}") - # 获取线程数 - thread_count = self.crack_settings.get("threads", 4) - logger.info(f"使用 {thread_count} 个线程进行字典破解") + logger.info(f"使用原始多线程方法进行字典破解: {dict_path}") # 读取字典文件中的密码列表 passwords = [] @@ -1770,7 +1970,7 @@ def test_password(pwd): self.okSignal.emit((False, f"字典破解失败: {str(e)}")) def run_bruteforce_crack(self): - """使用暴力破解方式 - 多线程版本""" + """使用暴力破解方式 - 优先使用Cython优化版本""" min_len = self.crack_settings.get("min_length", 4) max_len = self.crack_settings.get("max_length", 8) charset = self.crack_settings.get("charset", "digits") @@ -1778,6 +1978,58 @@ def run_bruteforce_crack(self): logger.info(f"使用 {thread_count} 个线程进行暴力破解") + # 使用Cython优化版本(如果可用) + if CYTHON_AVAILABLE: + try: + logger.info(f"使用Cython优化版本进行暴力破解: 字符集={charset}, 长度={min_len}-{max_len}") + self.current_pwd_signal.emit(f"正在使用Cython优化的多线程暴力破解({thread_count}线程)...") + + # 定义回调函数更新UI + def update_ui(message): + self.current_pwd_signal.emit(message) + # 更新进度条 + if "进度" in message: + try: + progress_str = message.split("进度")[1].strip().split("%")[0] + progress = float(progress_str) + self.progressSignal.emit(int(30 + progress * 0.6)) + except: + pass + + # 调用Cython优化的暴力破解函数 + success, found_password = pdf_cracker.crack_pdf_password( + self.input_file.file_path, + min_len, + max_len, + charset, + thread_count, + 1000, # 批次大小 + update_ui + ) + + if success: + # 保存解密后的PDF + with fitz.open(self.input_file.file_path) as pdf: + pdf.authenticate(found_password) + pdf.save(self.output_path) + + self.progressSignal.emit(100) + success_message = f"{os.path.dirname(self.output_path)}\n成功破解密码: {found_password}" + self.okSignal.emit((True, success_message)) + return + elif self.isInterruptionRequested(): + logger.info("暴力破解过程被用户终止") + self.okSignal.emit((False, "用户终止了破解过程")) + return + else: + logger.info("Cython优化版本暴力破解失败,尝试原始方法") + # 如果Cython版本失败,回退到原始实现 + except Exception as e: + logger.error(f"Cython暴力破解出错: {str(e)}") + logger.info("回退到原始暴力破解方法") + # 继续使用原始实现 + + # 原始多线程实现 # 定义字符集 charset_chars = "" if charset == "digits": @@ -1791,7 +2043,7 @@ def run_bruteforce_crack(self): else: # all charset_chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()_+-=[]{}|;:,.<>?/" - logger.info(f"开始多线程暴力破解,字符集: {charset}, 长度范围: {min_len}-{max_len}") + logger.info(f"开始原始多线程暴力破解,字符集: {charset}, 长度范围: {min_len}-{max_len}") import itertools @@ -2003,4 +2255,4 @@ def run_normal_decrypt(self): router = Router(None) view = DecryptControl(router) view.show() - sys.exit(app.exec()) \ No newline at end of file + sys.exit(app.exec()) \ No newline at end of file diff --git a/app/ui/pdf_tools/security/hashcat_wrapper.pyx b/app/ui/pdf_tools/security/hashcat_wrapper.pyx new file mode 100644 index 0000000..136e625 --- /dev/null +++ b/app/ui/pdf_tools/security/hashcat_wrapper.pyx @@ -0,0 +1,384 @@ +# cython: language_level=3, boundscheck=False, wraparound=False, cdivision=True +""" +Hashcat GPU加速的Cython优化模块 +提供PDF哈希提取、命令构建和结果解析等功能的优化实现 +""" + +import os +import re +import subprocess +import tempfile +import time +import threading +from libc.stdlib cimport malloc, free +from cython.parallel import prange +import numpy as np +cimport numpy as np + +# 定义常量 +DEF MAX_HASH_SIZE = 1024 +DEF MAX_CMD_SIZE = 4096 +DEF MAX_OUTPUT_SIZE = 102400 + +# 定义PDF哈希提取函数 +def extract_pdf_hash(str pdf_path): + """ + 提取PDF文件的密码哈希,优化版本 + """ + cdef: + bytes pdf_path_bytes = pdf_path.encode('utf-8') + char* hash_buffer + int result = 0 + + # 创建临时目录 + temp_dir = tempfile.mkdtemp() + hash_file = os.path.join(temp_dir, "pdf_hash.txt") + + try: + # 尝试使用pdf2john提取哈希 + pdf2john_cmd = ["pdf2john", pdf_path] + try: + result = subprocess.run( + pdf2john_cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + check=False + ) + + if result.returncode != 0: + # 尝试使用pdf2john.py + pdf2john_cmd = ["pdf2john.py", pdf_path] + result = subprocess.run( + pdf2john_cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + check=False + ) + + if result.returncode != 0: + return None, "提取PDF密码哈希失败" + + # 保存哈希到文件 + hash_content = result.stdout.strip() + with open(hash_file, 'w') as f: + f.write(hash_content) + + return hash_file, hash_content + + except Exception as e: + return None, f"提取PDF密码哈希失败: {str(e)}" + except: + # 如果出现异常,清理临时文件 + if os.path.exists(hash_file): + os.remove(hash_file) + if os.path.exists(temp_dir): + os.rmdir(temp_dir) + raise + +# 定义Hashcat命令构建函数 +def build_hashcat_command(dict options, str hash_file): + """ + 构建优化的Hashcat命令 + """ + cdef: + list hashcat_cmd = [] + str hashcat_dir = options.get("hashcat_path", "") + list selected_gpus = options.get("selected_gpus", []) + int gpu_threads = options.get("gpu_threads", 8) + int gpu_accel = options.get("gpu_accel", 64) + int workload = options.get("workload", 3) + str mode = options.get("mode", "bruteforce") + int min_length = options.get("min_length", 4) + int max_length = options.get("max_length", 8) + str charset = options.get("charset", "digits") + str dict_path = options.get("dict_path", "") + + # 确定hashcat可执行文件路径 + if os.name == 'nt': # Windows + hashcat_exe = os.path.join(hashcat_dir, "hashcat.exe") + else: # Linux/macOS + hashcat_exe = os.path.join(hashcat_dir, "hashcat") + + # 检查是否存在hashcat + if not os.path.isfile(hashcat_exe): + return None, f"未找到Hashcat可执行文件: {hashcat_exe}" + + # 构建基本命令 + hashcat_cmd = [hashcat_exe] + + # 添加设备选项 + if selected_gpus: + devices_str = ",".join(str(gpu) for gpu in selected_gpus) + hashcat_cmd.extend(["-d", devices_str]) + + # 添加哈希类型 (PDF的哈希类型为10400/10500/10600,取决于PDF版本) + hashcat_cmd.extend(["-m", "10500"]) # 尝试使用PDF 1.4-1.6格式 + + # 添加GPU优化参数 + hashcat_cmd.extend(["-n", str(gpu_threads)]) # GPU线程数 + hashcat_cmd.extend(["-u", str(gpu_accel)]) # GPU加速因子 + hashcat_cmd.extend(["-w", str(workload)]) # 工作负载 + + # 优化参数 + hashcat_cmd.extend(["--opencl-device-types=1,2,3"]) # 使用所有类型的OpenCL设备 + hashcat_cmd.extend(["--force"]) # 忽略警告 + hashcat_cmd.extend(["--optimized-kernel-enable"]) # 启用优化内核 + + # 添加哈希文件 + hashcat_cmd.append(hash_file) + + # 根据模式添加字典或掩码 + if mode == "dictionary": + # 字典模式 + if not os.path.exists(dict_path): + return None, "字典文件不存在" + + hashcat_cmd.append(dict_path) + else: + # 暴力破解模式 + # 定义字符集掩码 + charset_mask = "" + if charset == "digits": + charset_mask = "?d" # 数字 + elif charset == "lowercase": + charset_mask = "?l" # 小写字母 + elif charset == "uppercase": + charset_mask = "?u" # 大写字母 + elif charset == "alphanumeric": + charset_mask = "?a" # 字母数字 + else: # all + charset_mask = "?a" # 所有字符 + + # 构建掩码 + mask = charset_mask * min_length + + # 添加掩码参数 + hashcat_cmd.append(mask) + + # 如果有长度范围,添加增量模式 + if min_length < max_length: + increment_str = f"--increment --increment-min={min_length} --increment-max={max_length}" + hashcat_cmd.extend(increment_str.split()) + + # 添加其他选项 + hashcat_cmd.extend(["--status", "--potfile-disable"]) + + return hashcat_cmd, None + +# 定义并行结果解析函数 +def parse_hashcat_output(str output, int num_threads=4): + """ + 使用OpenMP并行解析Hashcat输出 + """ + cdef: + str password = None + float progress = 0.0 + str speed = "" + str util = "" + + # 在输出中查找密码 + password_match = re.search(r'Hash\.Target\s*:\s*.*:(.*?)$', output, re.MULTILINE) + if password_match: + password = password_match.group(1).strip() + + # 解析进度信息 + progress_match = re.search(r'PROGRESS\s*:\s*(\d+)', output) + if progress_match: + progress = min(float(progress_match.group(1)), 100.0) + + # 解析速度信息 + speed_match = re.search(r'Speed.Dev.*:\s*([\d.]+)\s*([A-Za-z/]+)', output) + if speed_match: + speed = f"{speed_match.group(1)} {speed_match.group(2)}" + + # 解析GPU利用率信息 + util_match = re.search(r'Util:\s*(\d+)%', output) + if util_match: + util = f"{util_match.group(1)}%" + + return { + "password": password, + "progress": progress, + "speed": speed, + "util": util + } + +# 主GPU破解函数 +def gpu_crack_pdf(str pdf_path, dict options, object callback=None): + """ + 使用Hashcat进行GPU加速的PDF密码破解 + + 参数: + pdf_path: PDF文件路径 + options: 破解选项字典 + callback: 回调函数,用于更新UI + + 返回: + (success, password): 成功标志和找到的密码 + """ + cdef: + bint success = False + str password = None + str message = "" + + # 提取PDF哈希 + if callback: + callback("正在提取PDF密码哈希...") + + hash_file, hash_content = extract_pdf_hash(pdf_path) + if hash_file is None: + if callback: + callback(f"错误: {hash_content}") + return False, None + + # 构建Hashcat命令 + hashcat_cmd, error = build_hashcat_command(options, hash_file) + if hashcat_cmd is None: + if callback: + callback(f"错误: {error}") + return False, None + + # 获取破解模式信息 + mode = options.get("mode", "bruteforce") + gpu_threads = options.get("gpu_threads", 8) + gpu_accel = options.get("gpu_accel", 64) + + if mode == "dictionary": + message = f"正在使用GPU加速进行字典破解 (线程数:{gpu_threads}, 加速因子:{gpu_accel})..." + else: + min_len = options.get("min_length", 4) + max_len = options.get("max_length", 8) + message = f"正在使用GPU加速进行暴力破解 (长度: {min_len}-{max_len}, 线程数:{gpu_threads}, 加速因子:{gpu_accel})..." + + if callback: + callback(message) + + # 运行hashcat进程 + try: + hashcat_process = subprocess.Popen( + hashcat_cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + bufsize=1 + ) + + # 创建读取输出的线程,防止阻塞 + def read_output(): + nonlocal success, password + for line in hashcat_process.stdout: + # 解析hashcat输出,更新进度和找到的密码 + if "STATUS" in line: + try: + progress = re.search(r'PROGRESS\s*:\s*(\d+)', line) + if progress and callback: + progress_val = min(int(progress.group(1)), 100) + callback(f"GPU破解进度: {progress_val}%") + except: + pass + + if "Session.Name..." in line and callback: + callback("GPU加速初始化完成,开始破解...") + + # 更新进度信息 + if "Speed.Dev" in line and callback: + speed_match = re.search(r'Speed.Dev.*:\s*([\d.]+)\s*([A-Za-z/]+)', line) + if speed_match: + speed = speed_match.group(1) + unit = speed_match.group(2) + callback(f"GPU破解速度: {speed} {unit}") + + # 更新GPU利用率信息(如果有) + if "Util:" in line and callback: + util_match = re.search(r'Util:\s*(\d+)%', line) + if util_match: + util = util_match.group(1) + callback(f"GPU利用率: {util}%") + + # 检查是否找到密码 + if "Recovered" in line and ":" in line and "0/1 (0.00%)" not in line: + if callback: + callback("已找到密码!正在验证...") + # 尝试从输出中提取密码 + password_match = re.search(r':\s*(.+?)$', line) + if password_match: + password = password_match.group(1).strip() + success = True + + # 如果找到了密码,结束循环 + if password: + break + + # 创建读取stderr的线程,可能包含更多调试信息 + def read_stderr(): + for line in hashcat_process.stderr: + # 记录错误信息 + if "CUDA" in line or "OpenCL" in line or "Error" in line and callback: + callback(f"GPU信息: {line.strip()}") + + # 启动输出读取线程 + output_thread = threading.Thread(target=read_output) + output_thread.daemon = True + output_thread.start() + + # 启动错误读取线程 + stderr_thread = threading.Thread(target=read_stderr) + stderr_thread.daemon = True + stderr_thread.start() + + # 等待hashcat进程完成或超时 + start_time = time.time() + while hashcat_process.poll() is None: + # 检查是否超时 + if time.time() - start_time > 300: # 5分钟超时 + if callback: + callback("GPU破解超时,尝试读取结果...") + break + + time.sleep(0.5) + + # 等待输出线程结束 + output_thread.join(timeout=2) + stderr_thread.join(timeout=2) + + # 检查破解结果 + return_code = hashcat_process.poll() or 0 + stdout, stderr = hashcat_process.communicate() + + # 如果还没有找到密码,尝试从stdout中解析 + if not success and stdout: + result = parse_hashcat_output(stdout) + if result["password"]: + password = result["password"] + success = True + + # 验证密码 + if success and password: + if callback: + callback(f"验证密码: {password}") + + # 这里可以添加密码验证逻辑 + # 由于我们不能在Cython中直接导入fitz,所以返回密码让调用者验证 + + return True, password + else: + if callback: + callback("GPU破解未找到密码") + return False, None + + except Exception as e: + if callback: + callback(f"GPU破解出错: {str(e)}") + return False, None + finally: + # 清理临时文件 + try: + if hash_file and os.path.exists(hash_file): + os.remove(hash_file) + temp_dir = os.path.dirname(hash_file) + if temp_dir and os.path.exists(temp_dir): + os.rmdir(temp_dir) + except: + pass \ No newline at end of file diff --git a/app/ui/pdf_tools/security/pdf_cracker.pyx b/app/ui/pdf_tools/security/pdf_cracker.pyx new file mode 100644 index 0000000..b2a4aff --- /dev/null +++ b/app/ui/pdf_tools/security/pdf_cracker.pyx @@ -0,0 +1,265 @@ +# cython: language_level=3 +# cython: boundscheck=False +# cython: wraparound=False +# cython: cdivision=True + +import cython +from cython.parallel import prange, parallel +import numpy as np +import fitz +import os +import time +from libc.stdlib cimport malloc, free +from libc.string cimport strcpy, strlen + +# 定义字符集常量 +DIGITS = "0123456789" +LOWERCASE = "abcdefghijklmnopqrstuvwxyz" +UPPERCASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +ALPHANUMERIC = DIGITS + LOWERCASE + UPPERCASE +ALL_CHARS = ALPHANUMERIC + "!@#$%^&*()_+-=[]{}|;:,.<>?/" + +# 定义结果结构体 +ctypedef struct CrackResult: + bint success + char password[100] # 假设密码最长不超过100个字符 + + +def get_charset(charset_type): + """根据字符集类型返回对应的字符集""" + if charset_type == "digits": + return DIGITS + elif charset_type == "lowercase": + return LOWERCASE + elif charset_type == "uppercase": + return UPPERCASE + elif charset_type == "alphanumeric": + return ALPHANUMERIC + else: # "all" + return ALL_CHARS + + +@cython.boundscheck(False) +@cython.wraparound(False) +def generate_passwords(int length, str charset): + """生成指定长度和字符集的所有可能密码""" + cdef int charset_len = len(charset) + cdef int i, j + cdef list passwords = [] + cdef list current = [charset[0]] * length + cdef list indices = [0] * length + + # 初始密码 + passwords.append(''.join(current)) + + # 生成所有可能的密码 + while True: + # 从最后一位开始,找到可以增加的位置 + for i in range(length-1, -1, -1): + indices[i] += 1 + if indices[i] < charset_len: + current[i] = charset[indices[i]] + # 重置后面的位置 + for j in range(i+1, length): + indices[j] = 0 + current[j] = charset[0] + break + else: + # 如果没有找到可以增加的位置,说明已经生成了所有密码 + break + + passwords.append(''.join(current)) + + return passwords + + +@cython.boundscheck(False) +@cython.wraparound(False) +def batch_generate_passwords(int start_idx, int batch_size, int length, str charset): + """生成指定范围内的密码批次""" + cdef int charset_len = len(charset) + cdef int total = charset_len ** length + cdef int end_idx = min(start_idx + batch_size, total) + cdef int i, j, idx + cdef list passwords = [] + cdef list current = [0] * length + + # 将起始索引转换为密码 + idx = start_idx + for i in range(length-1, -1, -1): + current[i] = idx % charset_len + idx //= charset_len + + # 生成指定范围内的密码 + for idx in range(start_idx, end_idx): + # 将当前索引转换为密码 + pwd = '' + for i in range(length): + pwd += charset[current[i]] + passwords.append(pwd) + + # 更新到下一个密码 + for i in range(length-1, -1, -1): + current[i] += 1 + if current[i] < charset_len: + break + current[i] = 0 + + return passwords + + +@cython.boundscheck(False) +@cython.wraparound(False) +def check_password_batch(list passwords, str pdf_path): + """检查一批密码是否能解密PDF""" + cdef int i + cdef int n = len(passwords) + cdef str password + cdef bint success = False + cdef str found_password = "" + + for i in range(n): + password = passwords[i] + try: + with fitz.open(pdf_path) as pdf: + if pdf.authenticate(password): + success = True + found_password = password + break + except Exception: + continue + + return success, found_password + + +def crack_pdf_password(str pdf_path, int min_length=4, int max_length=8, + str charset_type="digits", int num_threads=4, + int batch_size=1000, callback=None): + """使用Cython优化的暴力破解PDF密码""" + cdef str charset = get_charset(charset_type) + cdef int length, charset_len, total_combinations, batches, i + cdef bint success = False + cdef str found_password = "" + + # 检查PDF是否加密 + try: + with fitz.open(pdf_path) as pdf: + if not pdf.is_encrypted: + return False, "PDF文件未加密,无需解密" + except Exception as e: + return False, f"无法打开PDF文件: {str(e)}" + + # 尝试一些常见密码 + common_passwords = ['', '1234', '0000', '1111', '9999', '123456', 'password', 'admin', 'qwerty'] + for pwd in common_passwords: + if callback: + callback(f"尝试常见密码: {pwd}") + try: + with fitz.open(pdf_path) as pdf: + if pdf.authenticate(pwd): + return True, pwd + except Exception: + continue + + # 按照密码长度逐一尝试 + charset_len = len(charset) + for length in range(min_length, max_length + 1): + total_combinations = charset_len ** length + if callback: + callback(f"尝试长度为 {length} 的密码,组合总数: {total_combinations}") + + # 计算批次数 + batches = (total_combinations + batch_size - 1) // batch_size + + # 分批处理密码 + for i in range(batches): + if callback and i % 10 == 0: + progress = (i / batches) * 100 + callback(f"暴力破解(长度{length}): 进度 {progress:.2f}%") + + # 生成当前批次的密码 + start_idx = i * batch_size + passwords = batch_generate_passwords(start_idx, batch_size, length, charset) + + # 检查密码批次 + success, found_password = check_password_batch(passwords, pdf_path) + if success: + return True, found_password + + return False, "所有可能的密码组合尝试均失败" + + +# 并行版本的密码检查(使用OpenMP) +@cython.boundscheck(False) +@cython.wraparound(False) +def parallel_check_password_batch(list passwords, str pdf_path, int num_threads=4): + """并行检查一批密码是否能解密PDF""" + cdef int i, n = len(passwords) + cdef CrackResult result + result.success = False + strcpy(result.password, "") + + # 使用OpenMP并行处理 + with nogil, parallel(num_threads=num_threads): + for i in prange(n): + # 这里需要GIL,因为fitz库不是线程安全的 + with gil: + if not result.success: # 如果还没找到密码 + try: + with fitz.open(pdf_path) as pdf: + if pdf.authenticate(passwords[i]): + result.success = True + strcpy(result.password, passwords[i].encode('utf-8')) + except Exception: + pass + + return result.success, result.password.decode('utf-8') if result.success else "" + + +# 优化的字典破解函数 +def dictionary_crack(str pdf_path, str dict_path, int num_threads=4, callback=None): + """使用Cython优化的字典破解PDF密码""" + cdef bint success = False + cdef str found_password = "" + cdef list passwords = [] + cdef int batch_size = 1000 + cdef int total_passwords, batches, i, j + + # 检查字典文件是否存在 + if not os.path.exists(dict_path): + return False, "字典文件不存在" + + # 读取字典文件 + try: + with open(dict_path, 'r', encoding='utf-8', errors='ignore') as f: + passwords = [line.strip() for line in f if line.strip()] + except Exception as e: + return False, f"无法读取字典文件: {str(e)}" + + if not passwords: + return False, "字典文件为空或格式不正确" + + total_passwords = len(passwords) + if callback: + callback(f"字典中共有 {total_passwords} 个密码") + + # 计算批次数 + batches = (total_passwords + batch_size - 1) // batch_size + + # 分批处理密码 + for i in range(batches): + if callback and i % 10 == 0: + progress = (i / batches) * 100 + callback(f"字典破解: 进度 {progress:.2f}%") + + # 获取当前批次的密码 + start_idx = i * batch_size + end_idx = min(start_idx + batch_size, total_passwords) + batch_passwords = passwords[start_idx:end_idx] + + # 并行检查密码批次 + success, found_password = parallel_check_password_batch(batch_passwords, pdf_path, num_threads) + if success: + return True, found_password + + return False, "字典中所有密码尝试均失败" \ No newline at end of file diff --git a/app/ui/pdf_tools/security/setup.py b/app/ui/pdf_tools/security/setup.py new file mode 100644 index 0000000..8b27d38 --- /dev/null +++ b/app/ui/pdf_tools/security/setup.py @@ -0,0 +1,19 @@ +from setuptools import setup, Extension +from Cython.Build import cythonize +import numpy as np +import platform + +extensions = [ + Extension( + "pdf_cracker", + ["pdf_cracker.pyx"], + include_dirs=[np.get_include()], + extra_compile_args=["/openmp" if platform.system() == "Windows" else "-fopenmp"], + extra_link_args=["/openmp" if platform.system() == "Windows" else "-fopenmp"], + ) +] + +setup( + name="pdf_cracker", + ext_modules=cythonize(extensions, language_level=3), +) \ No newline at end of file diff --git a/app/ui/setting/__pycache__/about_dialog.cpython-313.pyc b/app/ui/setting/__pycache__/about_dialog.cpython-313.pyc deleted file mode 100644 index 15cb72e..0000000 Binary files a/app/ui/setting/__pycache__/about_dialog.cpython-313.pyc and /dev/null differ diff --git a/app/ui/setting/__pycache__/seetingUi.cpython-313.pyc b/app/ui/setting/__pycache__/seetingUi.cpython-313.pyc deleted file mode 100644 index 047889e..0000000 Binary files a/app/ui/setting/__pycache__/seetingUi.cpython-313.pyc and /dev/null differ diff --git a/app/ui/setting/__pycache__/setting.cpython-313.pyc b/app/ui/setting/__pycache__/setting.cpython-313.pyc deleted file mode 100644 index 9aea1ef..0000000 Binary files a/app/ui/setting/__pycache__/setting.cpython-313.pyc and /dev/null differ diff --git a/app/ui/video_tools/__pycache__/video_tool.cpython-313.pyc b/app/ui/video_tools/__pycache__/video_tool.cpython-313.pyc deleted file mode 100644 index 7aac7a3..0000000 Binary files a/app/ui/video_tools/__pycache__/video_tool.cpython-313.pyc and /dev/null differ diff --git a/app/ui/video_tools/__pycache__/video_tool_ui.cpython-313.pyc b/app/ui/video_tools/__pycache__/video_tool_ui.cpython-313.pyc deleted file mode 100644 index 7eb441d..0000000 Binary files a/app/ui/video_tools/__pycache__/video_tool_ui.cpython-313.pyc and /dev/null differ diff --git a/app/util/__pycache__/__init__.cpython-313.pyc b/app/util/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index 4c7248a..0000000 Binary files a/app/util/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/app/util/__pycache__/common.cpython-313.pyc b/app/util/__pycache__/common.cpython-313.pyc deleted file mode 100644 index 35d59e1..0000000 Binary files a/app/util/__pycache__/common.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/__pycache__/__init__.cpython-313.pyc b/pdf2docx/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index b87202c..0000000 Binary files a/pdf2docx/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/__pycache__/converter.cpython-313.pyc b/pdf2docx/__pycache__/converter.cpython-313.pyc deleted file mode 100644 index 6d330b9..0000000 Binary files a/pdf2docx/__pycache__/converter.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/common/__pycache__/Block.cpython-313.pyc b/pdf2docx/common/__pycache__/Block.cpython-313.pyc deleted file mode 100644 index ba02e1b..0000000 Binary files a/pdf2docx/common/__pycache__/Block.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/common/__pycache__/Collection.cpython-313.pyc b/pdf2docx/common/__pycache__/Collection.cpython-313.pyc deleted file mode 100644 index de4f6a3..0000000 Binary files a/pdf2docx/common/__pycache__/Collection.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/common/__pycache__/Element.cpython-313.pyc b/pdf2docx/common/__pycache__/Element.cpython-313.pyc deleted file mode 100644 index 6b235fb..0000000 Binary files a/pdf2docx/common/__pycache__/Element.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/common/__pycache__/__init__.cpython-313.pyc b/pdf2docx/common/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index be17455..0000000 Binary files a/pdf2docx/common/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/common/__pycache__/algorithm.cpython-313.pyc b/pdf2docx/common/__pycache__/algorithm.cpython-313.pyc deleted file mode 100644 index 18abfd7..0000000 Binary files a/pdf2docx/common/__pycache__/algorithm.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/common/__pycache__/constants.cpython-313.pyc b/pdf2docx/common/__pycache__/constants.cpython-313.pyc deleted file mode 100644 index 28b6f82..0000000 Binary files a/pdf2docx/common/__pycache__/constants.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/common/__pycache__/docx.cpython-313.pyc b/pdf2docx/common/__pycache__/docx.cpython-313.pyc deleted file mode 100644 index d5712a2..0000000 Binary files a/pdf2docx/common/__pycache__/docx.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/common/__pycache__/share.cpython-313.pyc b/pdf2docx/common/__pycache__/share.cpython-313.pyc deleted file mode 100644 index 5404d62..0000000 Binary files a/pdf2docx/common/__pycache__/share.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/font/__pycache__/Fonts.cpython-313.pyc b/pdf2docx/font/__pycache__/Fonts.cpython-313.pyc deleted file mode 100644 index 6d00301..0000000 Binary files a/pdf2docx/font/__pycache__/Fonts.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/font/__pycache__/__init__.cpython-313.pyc b/pdf2docx/font/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index db1f7db..0000000 Binary files a/pdf2docx/font/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/image/__pycache__/Image.cpython-313.pyc b/pdf2docx/image/__pycache__/Image.cpython-313.pyc deleted file mode 100644 index 8f57079..0000000 Binary files a/pdf2docx/image/__pycache__/Image.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/image/__pycache__/ImageBlock.cpython-313.pyc b/pdf2docx/image/__pycache__/ImageBlock.cpython-313.pyc deleted file mode 100644 index dbcb57d..0000000 Binary files a/pdf2docx/image/__pycache__/ImageBlock.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/image/__pycache__/ImageSpan.cpython-313.pyc b/pdf2docx/image/__pycache__/ImageSpan.cpython-313.pyc deleted file mode 100644 index ee1bb20..0000000 Binary files a/pdf2docx/image/__pycache__/ImageSpan.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/image/__pycache__/ImagesExtractor.cpython-313.pyc b/pdf2docx/image/__pycache__/ImagesExtractor.cpython-313.pyc deleted file mode 100644 index da88325..0000000 Binary files a/pdf2docx/image/__pycache__/ImagesExtractor.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/image/__pycache__/__init__.cpython-313.pyc b/pdf2docx/image/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index d1df5b4..0000000 Binary files a/pdf2docx/image/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/layout/__pycache__/Blocks.cpython-313.pyc b/pdf2docx/layout/__pycache__/Blocks.cpython-313.pyc deleted file mode 100644 index 30c01c3..0000000 Binary files a/pdf2docx/layout/__pycache__/Blocks.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/layout/__pycache__/Column.cpython-313.pyc b/pdf2docx/layout/__pycache__/Column.cpython-313.pyc deleted file mode 100644 index d246806..0000000 Binary files a/pdf2docx/layout/__pycache__/Column.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/layout/__pycache__/Layout.cpython-313.pyc b/pdf2docx/layout/__pycache__/Layout.cpython-313.pyc deleted file mode 100644 index 724b26f..0000000 Binary files a/pdf2docx/layout/__pycache__/Layout.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/layout/__pycache__/Section.cpython-313.pyc b/pdf2docx/layout/__pycache__/Section.cpython-313.pyc deleted file mode 100644 index ce008de..0000000 Binary files a/pdf2docx/layout/__pycache__/Section.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/layout/__pycache__/Sections.cpython-313.pyc b/pdf2docx/layout/__pycache__/Sections.cpython-313.pyc deleted file mode 100644 index b994865..0000000 Binary files a/pdf2docx/layout/__pycache__/Sections.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/layout/__pycache__/__init__.cpython-313.pyc b/pdf2docx/layout/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index 46b8bd2..0000000 Binary files a/pdf2docx/layout/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/page/__pycache__/BasePage.cpython-313.pyc b/pdf2docx/page/__pycache__/BasePage.cpython-313.pyc deleted file mode 100644 index 8c647c6..0000000 Binary files a/pdf2docx/page/__pycache__/BasePage.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/page/__pycache__/Page.cpython-313.pyc b/pdf2docx/page/__pycache__/Page.cpython-313.pyc deleted file mode 100644 index 4f72a0f..0000000 Binary files a/pdf2docx/page/__pycache__/Page.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/page/__pycache__/Pages.cpython-313.pyc b/pdf2docx/page/__pycache__/Pages.cpython-313.pyc deleted file mode 100644 index 76278ac..0000000 Binary files a/pdf2docx/page/__pycache__/Pages.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/page/__pycache__/RawPage.cpython-313.pyc b/pdf2docx/page/__pycache__/RawPage.cpython-313.pyc deleted file mode 100644 index 59c2d3d..0000000 Binary files a/pdf2docx/page/__pycache__/RawPage.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/page/__pycache__/RawPageFactory.cpython-313.pyc b/pdf2docx/page/__pycache__/RawPageFactory.cpython-313.pyc deleted file mode 100644 index bcfab32..0000000 Binary files a/pdf2docx/page/__pycache__/RawPageFactory.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/page/__pycache__/RawPageFitz.cpython-313.pyc b/pdf2docx/page/__pycache__/RawPageFitz.cpython-313.pyc deleted file mode 100644 index b1a9d98..0000000 Binary files a/pdf2docx/page/__pycache__/RawPageFitz.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/page/__pycache__/__init__.cpython-313.pyc b/pdf2docx/page/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index b9b9fe8..0000000 Binary files a/pdf2docx/page/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/shape/__pycache__/Path.cpython-313.pyc b/pdf2docx/shape/__pycache__/Path.cpython-313.pyc deleted file mode 100644 index d294caa..0000000 Binary files a/pdf2docx/shape/__pycache__/Path.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/shape/__pycache__/Paths.cpython-313.pyc b/pdf2docx/shape/__pycache__/Paths.cpython-313.pyc deleted file mode 100644 index 14a92c3..0000000 Binary files a/pdf2docx/shape/__pycache__/Paths.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/shape/__pycache__/Shape.cpython-313.pyc b/pdf2docx/shape/__pycache__/Shape.cpython-313.pyc deleted file mode 100644 index 91139a2..0000000 Binary files a/pdf2docx/shape/__pycache__/Shape.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/shape/__pycache__/Shapes.cpython-313.pyc b/pdf2docx/shape/__pycache__/Shapes.cpython-313.pyc deleted file mode 100644 index b0c9544..0000000 Binary files a/pdf2docx/shape/__pycache__/Shapes.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/shape/__pycache__/__init__.cpython-313.pyc b/pdf2docx/shape/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index 673046b..0000000 Binary files a/pdf2docx/shape/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/table/__pycache__/Cell.cpython-313.pyc b/pdf2docx/table/__pycache__/Cell.cpython-313.pyc deleted file mode 100644 index 374e79f..0000000 Binary files a/pdf2docx/table/__pycache__/Cell.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/table/__pycache__/Cells.cpython-313.pyc b/pdf2docx/table/__pycache__/Cells.cpython-313.pyc deleted file mode 100644 index 7ce3e1f..0000000 Binary files a/pdf2docx/table/__pycache__/Cells.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/table/__pycache__/Row.cpython-313.pyc b/pdf2docx/table/__pycache__/Row.cpython-313.pyc deleted file mode 100644 index 7e0baf7..0000000 Binary files a/pdf2docx/table/__pycache__/Row.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/table/__pycache__/Rows.cpython-313.pyc b/pdf2docx/table/__pycache__/Rows.cpython-313.pyc deleted file mode 100644 index bfaaec1..0000000 Binary files a/pdf2docx/table/__pycache__/Rows.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/table/__pycache__/TableBlock.cpython-313.pyc b/pdf2docx/table/__pycache__/TableBlock.cpython-313.pyc deleted file mode 100644 index 338ef05..0000000 Binary files a/pdf2docx/table/__pycache__/TableBlock.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/table/__pycache__/__init__.cpython-313.pyc b/pdf2docx/table/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index 25020ea..0000000 Binary files a/pdf2docx/table/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/text/__pycache__/Char.cpython-313.pyc b/pdf2docx/text/__pycache__/Char.cpython-313.pyc deleted file mode 100644 index 2bbd2a9..0000000 Binary files a/pdf2docx/text/__pycache__/Char.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/text/__pycache__/Line.cpython-313.pyc b/pdf2docx/text/__pycache__/Line.cpython-313.pyc deleted file mode 100644 index 8ce6449..0000000 Binary files a/pdf2docx/text/__pycache__/Line.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/text/__pycache__/Lines.cpython-313.pyc b/pdf2docx/text/__pycache__/Lines.cpython-313.pyc deleted file mode 100644 index 5df26b3..0000000 Binary files a/pdf2docx/text/__pycache__/Lines.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/text/__pycache__/Spans.cpython-313.pyc b/pdf2docx/text/__pycache__/Spans.cpython-313.pyc deleted file mode 100644 index 228f94c..0000000 Binary files a/pdf2docx/text/__pycache__/Spans.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/text/__pycache__/TextBlock.cpython-313.pyc b/pdf2docx/text/__pycache__/TextBlock.cpython-313.pyc deleted file mode 100644 index 46fbb1c..0000000 Binary files a/pdf2docx/text/__pycache__/TextBlock.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/text/__pycache__/TextSpan.cpython-313.pyc b/pdf2docx/text/__pycache__/TextSpan.cpython-313.pyc deleted file mode 100644 index 3492b8e..0000000 Binary files a/pdf2docx/text/__pycache__/TextSpan.cpython-313.pyc and /dev/null differ diff --git a/pdf2docx/text/__pycache__/__init__.cpython-313.pyc b/pdf2docx/text/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index 6dcf32d..0000000 Binary files a/pdf2docx/text/__pycache__/__init__.cpython-313.pyc and /dev/null differ