Загрузка данных
import os
import sys
import secrets
import hashlib
import subprocess
from Crypto.Cipher import AES
from Crypto.Util import Counter
ENCRYPTED_FILE = "encrypted.avi"
DECRYPTED_FILE = "decrypted.avi"
SETTINGS_FILE = "setting.txt"
def find_input_file():
"""Автоматически ищет файл object с любым расширением (.mp4, .png, .jpg и т.д.)"""
supported_extensions = ['.mp4', '.avi', '.mov', '.mkv', '.png', '.jpg', '.jpeg', '.webp']
for ext in supported_extensions:
filename = f"object{ext}"
if os.path.exists(filename):
return filename
return None
def generate_token(length=16):
return secrets.token_hex(length)
def get_key_and_iv(token: str):
key = hashlib.sha256(token.encode('utf-8')).digest()
iv = hashlib.md5(token.encode('utf-8')).digest()
return key, iv
def get_media_resolution(filepath: str):
"""Автоматическое получение разрешения (ширина x высота) для видео или картинки"""
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_media(in_path: str, out_path: str, token: str):
key, iv = get_key_and_iv(token)
width, height = get_media_resolution(in_path)
frame_size = width * height * 3 # RGB24 = 3 байта на пиксель
# 1. Процесс чтения файла (FFmpeg сам поймет, видео это или статичная картинка)
ff_read = subprocess.Popen([
'ffmpeg', '-y', '-loop', '1', '-i', in_path, # '-loop 1' позволяет даже картинку обрабатывать как видеопоток
'-f', 'image2pipe', '-pix_fmt', 'rgb24', '-vcodec', 'rawvideo', '-'
], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, bufsize=10**8)
# 2. Процесс записи обработанного потока в безпотерьный формат
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}]...")
# Для картинки ffmpeg с бесконечным лупом будет слать кадры вечно,
# поэтому для картинок ограничимся, например, 30 кадрами (1 секунда шума)
# Если это исходно видео, он обработает все кадры видео.
is_image = in_path.lower().endswith(('.png', '.jpg', '.jpeg', '.webp'))
max_frames = 30 if is_image else 999999999
while frame_index < max_frames:
raw_frame = ff_read.stdout.read(frame_size)
if not raw_frame:
break
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)
ff_write.stdin.write(processed_frame)
frame_index += 1
# Принудительно завершаем чтение картинки, так как у нее нет конца
ff_read.terminate()
ff_write.stdin.close()
ff_read.wait()
ff_write.wait()
print(f"[✓] Готово! Обработано кадров: {frame_index}")
def encrypt_mode():
input_file = find_input_file()
if not input_file:
print(f"[!] Не найден файл 'object' с поддерживаемым расширением (.mp4, .png, .jpg и т.д.) в текущей папке!")
return
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, 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
with open(SETTINGS_FILE, "r", encoding="utf-8") as f:
token = f.read().strip()
print(f"[+] Использован токен из {SETTINGS_FILE}: {token}")
process_media(ENCRYPTED_FILE, DECRYPTED_FILE, token)
if __name__ == "__main__":
print("Выберите режим:")
print("1 — Зашифровать (object.* -> 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("[!] Неверный выбор.")