/
ZaNyDa
/
Hashing_algorithm_code
Обзор
Документация
Войти
/
ZaNyDa
/
Hashing_algorithm_code
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
test.py
490 строк
24 KB
ZaNyDa
upload files
24 июн 2025, 19:53
24 июн 2025, 19:53
3865870
Код
Авторство
О чём код?
""" Главный модуль программы для вычисления хешей файлов с поддержкой ГОСТ алгоритмов """ # Импорт необходимых библиотек import hashlib # Стандартные алгоритмы хеширования import os # Работа с файловой системой import tkinter as tk # Графический интерфейс from tkinter import filedialog, messagebox, ttk # Элементы интерфейса from threading import Thread # Многопоточность import platform # Информация о платформе from binascii import hexlify # Преобразование в hex # ==================== РЕАЛИЗАЦИЯ ГОСТ 34.11-2012 (СТРИБОГ) ==================== class StreebogHash: """Класс для вычисления хешей по алгоритму ГОСТ 34.11-2012 (Стрибог)""" def __init__(self, size=256): """Инициализация хеш-функции""" self.size = size # Размер хеша: 256 или 512 бит self.buffer = bytearray() # Буфер для накопления данных # Инициализационные значения для хеша if size == 512: # Для 512-битного хеша начинаем с 0x00...01 self.h = bytearray([0x00]*64) self.h[0] = 0x01 else: # Для 256-битного хеша начинаем с 0x01...01 self.h = bytearray([0x01]*64) self.N = bytearray(64) # Параметр N (длина обработанных данных) self.Sigma = bytearray(64) # Параметр Σ (сумма всех блоков) # Таблица подстановок (первые 16 значений) self.tau = [ 0xFC, 0xEE, 0xDD, 0x11, 0xCF, 0x6E, 0x31, 0x16, 0xFB, 0xC4, 0xFA, 0xDA, 0x23, 0xC5, 0x04, 0x4D, # ... (полная таблица должна содержать 256 значений) ] def update(self, data): """Добавление данных для хеширования""" self.buffer += bytearray(data) # Добавляем новые данные в буфер # Обрабатываем полные блоки по 64 байта while len(self.buffer) >= 64: block = self.buffer[:64] # Берем первый полный блок self.buffer = self.buffer[64:] # Удаляем обработанный блок self._compress(block) # Сжимаем блок def hexdigest(self): """Получение итогового хеша в hex-формате""" # Добавляем padding (дополнение) если данных не хватает pad_len = 64 - len(self.buffer) padding = bytearray([0]*(pad_len-1) + [pad_len]) self.update(padding) # Финальное сжатие параметров N и Σ self._compress(self.N) self._compress(self.Sigma) # Возвращаем хеш нужной длины (обрезаем до 32 или 64 байт) return hexlify(self.h[:self.size//8]).decode() def _compress(self, message): """Основная функция сжатия (упрощенная реализация)""" # В реальной реализации здесь должны быть: # 1. Применение S-блоков (подстановка через таблицу tau) # 2. Линейное преобразование L # 3. Перестановка P # Временная реализация - просто XOR с сообщением for i in range(64): self.h[i] ^= message[i] # Обновляем параметры: self.N = self._add_mod_512(self.N, bytearray([0x02]*64)) # Увеличиваем счетчик self.Sigma = self._add_mod_512(self.Sigma, message) # Добавляем блок к сумме def _add_mod_512(self, a, b): """Сложение двух 512-битных чисел по модулю 2^512""" result = bytearray(64) carry = 0 # Перенос # Идем справа налево (от младших байтов к старшим) for i in reversed(range(64)): temp = a[i] + b[i] + carry # Суммируем байты и перенос result[i] = temp & 0xFF # Записываем младший байт carry = temp >> 8 # Обновляем перенос return result # ==================== РЕАЛИЗАЦИЯ ГОСТ Р 34.11-2018 (КУЗНЕЧИК) ==================== class KuznechikHash: """Класс для вычисления хешей по алгоритму ГОСТ Р 34.11-2018 (Кузнечик)""" def __init__(self): """Инициализация хеш-функции""" self.buffer = bytearray() # Буфер для накопления данных self.state = bytearray(32) # Внутреннее состояние (256 бит) # Таблица подстановок (первые 16 значений) self.pi = [ 0xFC, 0xEE, 0xDD, 0x11, 0xCF, 0x6E, 0x31, 0x16, 0xFB, 0xC4, 0xFA, 0xDA, 0x23, 0xC5, 0x04, 0x4D, # ... (полная таблица должна содержать 256 значений) ] def update(self, data): """Добавление данных для хеширования""" self.buffer += bytearray(data) # Добавляем новые данные в буфер # Обрабатываем полные блоки по 32 байта while len(self.buffer) >= 32: block = self.buffer[:32] # Берем первый полный блок self.buffer = self.buffer[32:] # Удаляем обработанный блок self._transform(block) # Преобразуем блок def hexdigest(self): """Получение итогового хеша в hex-формате""" # Добавляем padding (дополнение) если данных не хватает pad_len = 32 - len(self.buffer) padding = bytearray([0]*(pad_len-1) + [pad_len]) self.update(padding) # Возвращаем итоговое состояние return hexlify(self.state).decode() def _transform(self, block): """Основная функция преобразования (упрощенная реализация)""" # В реальной реализации здесь должны быть: # 1. Нелинейное преобразование (подстановка через таблицу pi) # 2. Линейное преобразование (умножение на матрицу) # Временная реализация - просто XOR с блоком for i in range(32): self.state[i] ^= block[i] # ==================== ГЛАВНОЕ ОКНО ПРОГРАММЫ ==================== class HashCalculatorApp: """Класс главного окна приложения""" def __init__(self, root): """Инициализация приложения""" self.root = root self.root.title("File Hash Calculator") # Заголовок окна self.root.geometry("800x700") # Размер окна # Проверка доступности внешних библиотек self.streebog_available = False self.kuznechik_available = False self.check_libraries() # Создание интерфейса self.setup_ui() # Показать статус библиотек self.show_library_status() def check_libraries(self): """Проверяем, установлены ли внешние библиотеки""" try: from streebog import Streebog # Пробуем импортировать self.streebog_available = True except ImportError: self.streebog_available = False try: from gostcrypto import gosthash # Пробуем импортировать self.kuznechik_available = True except ImportError: self.kuznechik_available = False def setup_ui(self): """Создаем графический интерфейс""" # Основной фрейм main_frame = ttk.Frame(self.root, padding=10) main_frame.pack(fill=tk.BOTH, expand=True) # Фрейм с кнопками управления button_frame = ttk.Frame(main_frame) button_frame.pack(fill=tk.X, pady=(0, 10)) # Кнопка "Добавить файлы" ttk.Button( button_frame, text="Добавить файлы", command=self.add_files ).pack(side=tk.LEFT, padx=5) # Кнопка "Очистить всё" ttk.Button( button_frame, text="Очистить всё", command=self.clear_all ).pack(side=tk.LEFT, padx=5) # Кнопка "Вычислить хеши" (изначально отключена) self.calc_btn = ttk.Button( button_frame, text="Вычислить хеши", command=self.start_calculation, state=tk.DISABLED ) self.calc_btn.pack(side=tk.RIGHT, padx=5) # Список файлов с прокруткой file_frame = ttk.LabelFrame(main_frame, text="Выбранные файлы") file_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 10)) scrollbar = ttk.Scrollbar(file_frame) scrollbar.pack(side=tk.RIGHT, fill=tk.Y) self.file_list = tk.Listbox( file_frame, yscrollcommand=scrollbar.set, selectmode=tk.EXTENDED, # Можно выбирать несколько файлов font=("Consolas", 10), # Моноширинный шрифт bg="#ffffff", # Белый фон relief=tk.FLAT # Плоский стиль ) self.file_list.pack(fill=tk.BOTH, expand=True, padx=5, pady=5) scrollbar.config(command=self.file_list.yview) # Связываем скроллбар и список # Фрейм с выбором алгоритмов algo_frame = ttk.LabelFrame(main_frame, text="Алгоритмы хеширования") algo_frame.pack(fill=tk.X, pady=(0, 10)) # Вкладки для группировки алгоритмов algo_tabs = ttk.Notebook(algo_frame) algo_tabs.pack(fill=tk.BOTH, padx=5, pady=5) # Вкладка со стандартными алгоритмами std_frame = ttk.Frame(algo_tabs) algo_tabs.add(std_frame, text="Стандартные") self.algo_vars = {} # Словарь для хранения состояний чекбоксов # Список стандартных алгоритмов std_algorithms = [ ("md5", "MD5"), ("sha1", "SHA-1"), ("sha256", "SHA-256"), ("sha512", "SHA-512"), ("sha3_256", "SHA3-256"), ("blake2b", "BLAKE2b"), ("blake2s", "BLAKE2s") ] # Создаем чекбоксы для стандартных алгоритмов for i, (algo, name) in enumerate(std_algorithms): var = tk.BooleanVar(value=True) # По умолчанию включены self.algo_vars[algo] = var # Сохраняем переменную cb = ttk.Checkbutton( std_frame, text=name, variable=var ) # Располагаем в сетке 2x4 cb.grid(row=i//4, column=i%4, sticky="w", padx=5, pady=2) # Вкладка с ГОСТ алгоритмами gost_frame = ttk.Frame(algo_tabs) algo_tabs.add(gost_frame, text="ГОСТ") # Список ГОСТ алгоритмов gost_algorithms = [ ("streebog256", "ГОСТ 34.11-2012 (256-bit)"), ("streebog512", "ГОСТ 34.11-2012 (512-bit)"), ("kuznechik256", "ГОСТ Р 34.11-2018 (256-bit)") ] # Создаем чекбоксы для ГОСТ алгоритмов for i, (algo, name) in enumerate(gost_algorithms): var = tk.BooleanVar() self.algo_vars[algo] = var # Сохраняем переменную cb = ttk.Checkbutton( gost_frame, text=name, variable=var, state=tk.NORMAL # Всегда доступны (используем встроенные реализации) ) var.set(True) # По умолчанию включены cb.grid(row=i, column=0, sticky="w", padx=5, pady=2) # Прогресс-бар для отображения хода вычислений self.progress = ttk.Progressbar( main_frame, orient=tk.HORIZONTAL, mode="determinate" # Детерминированный режим (с процентами) ) self.progress.pack(fill=tk.X, pady=(0, 10)) # Область для вывода результатов result_frame = ttk.LabelFrame(main_frame, text="Результаты") result_frame.pack(fill=tk.BOTH, expand=True) self.result_text = tk.Text( result_frame, font=("Consolas", 10), # Моноширинный шрифт bg="#ffffff", # Белый фон relief=tk.FLAT, # Плоский стиль padx=5, # Отступы pady=5 ) self.result_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5) self.result_text.config(state=tk.DISABLED) # Изначально только для чтения # Строка статуса внизу окна self.status_var = tk.StringVar(value="Готов к работе") status_bar = ttk.Label( self.root, textvariable=self.status_var, relief=tk.SUNKEN, # Утопленный стиль anchor=tk.W # Выравнивание по левому краю ) status_bar.pack(side=tk.BOTTOM, fill=tk.X) def show_library_status(self): """Показывает, какие библиотеки доступны""" self.append_result("=== Статус библиотек ===\n") self.append_result(f"ГОСТ 34.11-2012: {'Доступна внешняя библиотека' if self.streebog_available else 'Используется встроенная реализация'}\n") self.append_result(f"ГОСТ Р 34.11-2018: {'Доступна внешняя библиотека' if self.kuznechik_available else 'Используется встроенная реализация'}\n") self.append_result("="*40 + "\n\n") def append_result(self, text): """Добавляет текст в область результатов""" self.result_text.config(state=tk.NORMAL) # Включаем редактирование self.result_text.insert(tk.END, text) # Добавляем текст self.result_text.see(tk.END) # Прокручиваем вниз self.result_text.config(state=tk.DISABLED) # Отключаем редактирование self.root.update() # Обновляем интерфейс def add_files(self): """Добавляет файлы для обработки""" files = filedialog.askopenfilenames(title="Выберите файлы") if files: self.selected_files = list(files) self.file_list.delete(0, tk.END) # Очищаем список for file in self.selected_files: # Добавляем только имена файлов (без пути) self.file_list.insert(tk.END, os.path.basename(file)) self.calc_btn.config(state=tk.NORMAL) # Активируем кнопку self.status_var.set(f"Выбрано файлов: {len(self.selected_files)}") def clear_all(self): """Очищает все данные и результаты""" self.selected_files = [] self.file_list.delete(0, tk.END) self.result_text.config(state=tk.NORMAL) self.result_text.delete(1.0, tk.END) # Удаляем весь текст self.result_text.config(state=tk.DISABLED) self.progress["value"] = 0 # Сбрасываем прогресс self.calc_btn.config(state=tk.DISABLED) # Деактивируем кнопку self.status_var.set("Готов к работе") self.show_library_status() # Показываем статус библиотек def start_calculation(self): """Запускает вычисление хешей в отдельном потоке""" if not self.selected_files: messagebox.showwarning("Ошибка", "Выберите файлы!") return # Получаем выбранные алгоритмы selected_algos = [algo for algo, var in self.algo_vars.items() if var.get()] if not selected_algos: messagebox.showwarning("Ошибка", "Выберите хотя бы один алгоритм!") return # Запускаем в отдельном потоке, чтобы не блокировать интерфейс Thread( target=self.calculate_hashes, args=(self.selected_files, selected_algos), daemon=True # Поток завершится при закрытии программы ).start() def calculate_hashes(self, files, algorithms): """Вычисляет хеши для всех файлов выбранными алгоритмами""" total = len(files) * len(algorithms) # Общее количество операций processed = 0 # Счетчик выполненных операций # Блокируем кнопки и очищаем результаты self.update_ui(disable_buttons=True) self.append_result("="*40 + "\n") self.append_result(f"Начато вычисление для {len(files)} файл(ов)\n") self.append_result("="*40 + "\n\n") # Обрабатываем каждый файл for file_idx, file_path in enumerate(files, 1): filename = os.path.basename(file_path) filesize = os.path.getsize(file_path) # Выводим информацию о файле self.append_result(f"Файл {file_idx}/{len(files)}: {filename}\n") self.append_result(f"Размер: {self.format_size(filesize)}\n") self.append_result(f"Путь: {file_path}\n") self.status_var.set(f"Обработка {filename}...") try: # Создаем объекты хеширования для каждого алгоритма hashers = {} for algo in algorithms: try: hashers[algo] = self.get_hasher(algo) except Exception as e: self.append_result(f" {algo}: ❌ {str(e)}\n") # Читаем файл блоками по 64KB with open(file_path, "rb") as f: while chunk := f.read(8192 * 8): # Обновляем хеши для каждого алгоритма for hasher in hashers.values(): hasher.update(chunk) # Выводим результаты для каждого алгоритма for algo in algorithms: if algo in hashers: try: hash_value = hashers[algo].hexdigest() self.append_result(f" {algo}: {hash_value}\n") except Exception as e: self.append_result(f" {algo}: ❌ {str(e)}\n") # Обновляем прогресс processed += 1 self.progress["value"] = (processed / total) * 100 self.root.update() # Обновляем интерфейс except Exception as e: self.append_result(f" ❌ Ошибка обработки файла: {str(e)}\n") self.append_result("\n" + "-"*40 + "\n\n") # Завершение работы self.append_result("✅ Вычисление завершено!\n") self.status_var.set("Готов к работе") self.update_ui(disable_buttons=False) def get_hasher(self, algo): """Создает объект хеширования для указанного алгоритма""" if algo == "streebog256": if self.streebog_available: from streebog import Streebog # Используем внешнюю библиотеку return Streebog(256) return StreebogHash(256) # Или нашу реализацию elif algo == "streebog512": if self.streebog_available: from streebog import Streebog return Streebog(512) return StreebogHash(512) elif algo == "kuznechik256": if self.kuznechik_available: from gostcrypto import gosthash return gosthash.new('trayektoria256') return KuznechikHash() else: # Для стандартных алгоритмов используем hashlib return hashlib.new(algo) def format_size(self, size): """Форматирует размер файла в удобочитаемый вид""" for unit in ["Б", "КБ", "МБ", "ГБ", "ТБ"]: if size < 1024.0: return f"{size:.2f} {unit}" size /= 1024.0 return f"{size:.2f} ТБ" def update_ui(self, disable_buttons=True): """Обновляет состояние элементов интерфейса""" state = tk.DISABLED if disable_buttons else tk.NORMAL self.calc_btn.config(state=state) # Включаем/выключаем кнопку self.root.update() # Обновляем интерфейс # Точка входа в программу if __name__ == "__main__": # Настройка DPI для Windows (чтобы интерфейс нормально масштабировался) if platform.system() == "Windows": from ctypes import windll windll.shcore.SetProcessDpiAwareness(1) # Создаем главное окно root = tk.Tk() app = HashCalculatorApp(root) # Запускаем главный цикл обработки событий root.mainloop()