Загрузка данных


import os
import random
import string
import cv2
import numpy as np
from Crypto.Cipher import AES
from Crypto.Util import Counter

SETTINGS_FILE = "setting.txt"

def find_input_file():
    """Поиск файла object с любым поддерживаемым расширением"""
    supported_extensions = ['.png', '.jpg', '.jpeg', '.webp', '.mp4', '.avi', '.mov', '.mkv']
    for ext in supported_extensions:
        filename = f"object{ext}"
        if os.path.exists(filename):
            return filename, ext
    return None, None

def find_encrypted_file():
    """Поиск зашифрованного файла encrypted (картинка или avi-видео)"""
    supported_extensions = ['.png', '.jpg', '.jpeg', '.webp', '.avi', '.mp4']
    for ext in supported_extensions:
        filename = f"encrypted{ext}"
        if os.path.exists(filename):
            return filename, ext
    return None, None

def generate_token(length=32):
    chars = string.ascii_letters + string.digits
    return ''.join(random.choice(chars) for _ in range(length))

def token_to_key_and_iv(token: str):
    token_bytes = token.encode('utf-8')
    if len(token_bytes) >= 32:
        key = token_bytes[:32]
    else:
        key = token_bytes.ljust(32, b'\x00')
    iv = key[16:32]
    return key, iv

def encrypt_decrypt_bytes(data_bytes: bytes, key: bytes, iv: bytes, frame_index: int) -> bytes:
    ctr_int = int.from_bytes(iv, 'big') + frame_index
    ctr = Counter.new(128, initial_value=ctr_int)
    cipher = AES.new(key, AES.MODE_CTR, counter=ctr)
    return cipher.encrypt(data_bytes)

def process_media(in_path: str, out_path: str, token: str):
    key, iv = token_to_key_and_iv(token)
    ext = os.path.splitext(in_path)[1].lower()
    is_image = ext in ['.png', '.jpg', '.jpeg', '.webp']

    print(f"Чтение файла [{in_path}]...")

    if is_image:
        # ==========================================
        # 1. ОБРАБОТКА ИЗОБРАЖЕНИЙ (PNG / JPG)
        # ==========================================
        frame = cv2.imread(in_path)
        if frame is None:
            print(f"[!] Ошибка: Не удалось прочитать картинку {in_path}")
            return

        height, width, _ = frame.shape
        raw_bytes = frame.tobytes()

        processed_bytes = encrypt_decrypt_bytes(raw_bytes, key, iv, frame_index=0)
        processed_frame = np.frombuffer(processed_bytes, dtype=np.uint8).reshape((height, width, 3))

        cv2.imwrite(out_path, processed_frame)
        print(f"[✓] Успешно! Файл сохранен как: {out_path}")

    else:
        # ==========================================
        # 2. ОБРАБОТКА ВИДЕО (ЛЮБОЙ ФОРМАТ -> AVI Lossless)
        # ==========================================
        cap = cv2.VideoCapture(in_path)
        if not cap.isOpened():
            print(f"[!] Ошибка: Не удалось открыть видео {in_path}")
            return

        width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
        height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
        fps = cap.get(cv2.CAP_PROP_FPS)
        if fps == 0:
            fps = 30.0

        # Для видео гарантированно используем AVI + FFV1 (без потерь)
        # Это исключает любые фиолетовые ошибки OpenCV/FFmpeg
        fourcc = cv2.VideoWriter_fourcc(*'FFV1')
        out = cv2.VideoWriter(out_path, fourcc, fps, (width, height))

        if not out.isOpened():
            # Запасной кодек для Windows (Raw DIB)
            fourcc = cv2.VideoWriter_fourcc(*'DIB ')
            out = cv2.VideoWriter(out_path, fourcc, fps, (width, height))

        frame_index = 0
        print(f"Обработка кадров видео...")

        while cap.isOpened():
            ret, frame = cap.read()
            if not ret:
                break

            raw_bytes = frame.tobytes()
            processed_bytes = encrypt_decrypt_bytes(raw_bytes, key, iv, frame_index)
            processed_frame = np.frombuffer(processed_bytes, dtype=np.uint8).reshape((height, width, 3))

            out.write(processed_frame)
            frame_index += 1

        cap.release()
        out.release()
        print(f"[✓] Успешно! Видео сохранено как: {out_path} (кадров: {frame_index})")

def encrypt_mode():
    input_file, ext = find_input_file()
    if not input_file:
        print("[!] В папке со скриптом не найден исходный файл 'object' (.png, .mp4 и т.д.)!")
        return

    is_image = ext in ['.png', '.jpg', '.jpeg', '.webp']
    output_file = f"encrypted{ext}" if is_image else "encrypted.avi"
    
    print(f"[+] Найден файл для шифрования: {input_file}")

    token = generate_token()
    with open(SETTINGS_FILE, "w", encoding="utf-8") as f:
        f.write(token)
    print(f"[+] Новый токен записан в {SETTINGS_FILE}: {token}")

    process_media(input_file, output_file, token)

def decrypt_mode():
    encrypted_file, ext = find_encrypted_file()
    if not encrypted_file:
        print("[!] Зашифрованный файл 'encrypted.*' не найден!")
        return

    if not os.path.exists(SETTINGS_FILE):
        print(f"[!] Файл с токеном {SETTINGS_FILE} не найден!")
        return

    is_image = ext in ['.png', '.jpg', '.jpeg', '.webp']
    output_file = f"decrypted{ext}" if is_image else "decrypted.avi"

    with open(SETTINGS_FILE, "r", encoding="utf-8") as f:
        token = f.read().strip()
    print(f"[+] Считан токен из {SETTINGS_FILE}: {token}")

    process_media(encrypted_file, output_file, token)

if __name__ == "__main__":
    print("====================================")
    print("    ШИФРАТОР МЕДИАФАЙЛОВ ПО ТОКЕНУ  ")
    print("====================================")
    print("Выберите режим:")
    print("1 — Зашифровать (object.* -> encrypted.* + генерация setting.txt)")
    print("2 — Расшифровать (encrypted.* -> decrypted.* по токену из setting.txt)")
    
    choice = input("Введите цифру (1 или 2): ").strip()
    
    if choice == "1":
        encrypt_mode()
    elif choice == "2":
        decrypt_mode()
    else:
        print("[!] Неверный выбор.")