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


import os
import sys
import secrets
import hashlib
import subprocess
from Crypto.Cipher import AES
from Crypto.Util import Counter

# Файлы по умолчанию
INPUT_FILE = "object.mp4"      # Исходный файл (может быть .mp4, .png, .jpg, .avi и т.д.)
ENCRYPTED_FILE = "encrypted.avi"  # Файл с шифрованным видео/шумом
DECRYPTED_FILE = "decrypted.avi"  # Восстановленный файл
SETTINGS_FILE = "setting.txt" # Файл для хранения токена

def generate_token(length=16):
    """Генерация безопасного рандомного токена"""
    return secrets.token_hex(length)

def get_key_and_iv(token: str):
    """Получение 256-битного ключа и 128-битного IV из текстового токена"""
    key = hashlib.sha256(token.encode('utf-8')).digest()
    iv = hashlib.md5(token.encode('utf-8')).digest()
    return key, iv

def get_video_resolution(filepath: str):
    """Автоматическое получение разрешения видео (ширина x высота) через ffprobe"""
    cmd = [
        'ffprobe', '-v', 'error',
        '-select_streams', 'v:0',
        '-show_entries', 'stream=width,height',
        '-of', 'csv=s=x:p=0',
        filepath
    ]
    try:
        output = subprocess.check_output(cmd).decode('utf-8').strip()
        width, height = map(int, output.split('x'))
        return width, height
    except Exception as e:
        print(f"[!] Ошибка определения разрешения файла {filepath}: {e}")
        sys.exit(1)

def process_video(in_path: str, out_path: str, token: str):
    """Шифрование / Дешифрование потока через FFmpeg + AES-CTR"""
    key, iv = get_key_and_iv(token)
    width, height = get_video_resolution(in_path)
    frame_size = width * height * 3  # RGB24 = 3 байта на пиксель

    # 1. Процесс чтения исходного видео в формате сырых пикселей (rawvideo RGB24)
    ff_read = subprocess.Popen([
        'ffmpeg', '-y', '-i', in_path,
        '-f', 'image2pipe', '-pix_fmt', 'rgb24', '-vcodec', 'rawvideo', '-'
    ], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, bufsize=10**8)

    # 2. Процесс записи обработанного потока пикселей в безпотерьный формат (FFV1)
    ff_write = subprocess.Popen([
        'ffmpeg', '-y',
        '-f', 'rawvideo', '-pix_fmt', 'rgb24', '-s', f'{width}x{height}', '-r', '30',
        '-i', '-',
        '-c:v', 'ffv1', out_path
    ], stdin=subprocess.PIPE, stderr=subprocess.DEVNULL)

    frame_index = 0
    print(f"Обработка [{in_path} -> {out_path}]...")

    while True:
        raw_frame = ff_read.stdout.read(frame_size)
        if not raw_frame:
            break

        # Настраиваем счетчик AES-CTR для текущего кадра
        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)

        # Шифруем / расшифровываем байты кадра
        processed_frame = cipher.encrypt(raw_frame)

        # Записываем результат в выходной процесс FFmpeg
        ff_write.stdin.write(processed_frame)
        frame_index += 1

    ff_read.stdout.close()
    ff_write.stdin.close()
    ff_read.wait()
    ff_write.wait()
    print(f"[✓] Готово! Обработано кадров: {frame_index}")

def encrypt_mode():
    if not os.path.exists(INPUT_FILE):
        print(f"[!] Файл {INPUT_FILE} не найден!")
        return

    # 1. Генерируем токен и сохраняем в setting.txt
    token = generate_token()
    with open(SETTINGS_FILE, "w", encoding="utf-8") as f:
        f.write(token)
    print(f"[+] Новый токен сгенерирован и записан в {SETTINGS_FILE}: {token}")

    # 2. Запускаем шифрование
    process_video(INPUT_FILE, ENCRYPTED_FILE, token)

def decrypt_mode():
    if not os.path.exists(ENCRYPTED_FILE):
        print(f"[!] Зашифрованный файл {ENCRYPTED_FILE} не найден!")
        return

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

    # 1. Считываем токен
    with open(SETTINGS_FILE, "r", encoding="utf-8") as f:
        token = f.read().strip()
    print(f"[+] Использован токен из {SETTINGS_FILE}: {token}")

    # 2. Запускаем дешифрование
    process_video(ENCRYPTED_FILE, DECRYPTED_FILE, token)

if __name__ == "__main__":
    print("Выберите режим:")
    print("1 — Зашифровать (object.mp4 -> encrypted.avi + создать setting.txt)")
    print("2 — Расшифровать (encrypted.avi -> decrypted.avi по токену из setting.txt)")
    
    choice = input("Введите цифру (1 или 2): ").strip()
    
    if choice == "1":
        encrypt_mode()
    elif choice == "2":
        decrypt_mode()
    else:
        print("[!] Неверный выбор.")