Привет, Хабр! При работе со стеганографией первый и самый важный вопрос, который возникает перед пользователем: «А мой файл вообще поместится в эту картинку?». Попытка спрятать 10-мегабайтный архив в иконку размером 64x64 пикселя обречена на провал. Именно поэтому оценка стеганографической емкости контейнера — это краеугольный камень любой операции по сокрытию данных.

Емкость — это не просто размер файла. Это сложное понятие, которое кардинально меняется в зависимости от формата контейнера (PNG, JPEG, DOCX) и метода сокрытия (LSB, DCT и др.).

Сегодня на примере кода из нашего проекта ChameleonLab мы подробно разберем, как вычисляется емкость для разных типов файлов, и напишем соответствующие функции на Python.

Основы основ — LSB-емкость в растровых изображениях (PNG, BMP)

Это самый простой и интуитивно понятный случай. Метод LSB (Least Significant Bit) позволяет заменять наименее значимые биты в каждом байте цвета пикселя.

Математика

Расчет здесь — простая арифметика:

  1. Считаем общее число байт: Изображение состоит из пикселей, каждый пиксель — из каналов (обычно 3: Red, Green, Blue). Общее число байт, доступных для модификации, это ширина × высота × 3.

  2. Умножаем на n_bits: n_bits — это количество "младших" бит, которые мы решаем использовать в каждом байте (от 1 до 8). Общая емкость в битах = (ширина × высота × 3) × n_bits.

  3. Переводим в байты: Делим общее число бит на 8.

  4. Вычитаем накладные расходы: Всегда нужно оставить немного места (10-20 байт) для служебной информации: сигнатуры, длины сообщения, флага шифрования и т.д.

Код

Эта логика реализована в функции calculate_capacity в нашем файле steganography_core.py:

# steganography_core.py
import numpy as np

def calculate_capacity(carrier_bytes: np.ndarray, n_bits: int) -> int:
    """
    Вычисляет максимальную стеганографическую емкость контейнера в байтах для LSB.
    """
    if n_bits < 1 or n_bits > 8:
        raise ValueError("n_bits должен быть в диапазоне 1..8")

    # carrier_bytes.size — это и есть (ширина * высота * каналы) для NumPy массива
    total_bits = int(carrier_bytes.size) * int(n_bits)
    
    # Делим на 8, чтобы получить байты, и вычитаем небольшой запас на заголовок
    return (total_bits // 8) - 10

Например, для картинки 1920x1080 (Full HD) с 3 каналами (RGB) и n_bits = 2:

  • 1920 1080 3 = 6 220 800 байт данных.

  • 6 220 800 * 2 = 12 441 600 доступных бит.

  • 12 441 600 / 8 = 1 555 200 байт.

  • 1 555 200 - 10 ≈ 1.55 мегабайт полезной нагрузки.

Программа "ChameleonLab". Количество бит: 1
Программа "ChameleonLab". Количество бит: 1
Программа "ChameleonLab". Количество бит: 8
Программа "ChameleonLab". Количество бит: 8

Продвинутый уровень — емкость в JPEG (DCT-метод)

С JPEG все гораздо сложнее. Это формат сжатия с потерями, и прямой LSB-анализ пикселей здесь не работает — при сохранении файла все ваши изменения будут уничтожены.

Встраивание происходит в коэффициенты ДКП (DCT) — это числовые представления частотных компонент изображения. Мы можем прятать по 1 биту в LSB каждого такого коэффициента.

Логика и ограничения

  1. Только AC-коэффициенты: В каждом блоке 8x8 есть один DC-коэффициент (основная яркость) и 63 AC-коэффициента (детали). DC-коэффициент очень важен для изображения, и его изменение сильно заметно, поэтому мы его не трогаем.

  2. Проблема нулей: Если значение коэффициента равно 1 или -1, изменение его LSB превратит его в 0 или -2. Нулевые AC-коэффициенты часто отбрасываются при сжатии, что может повредить всю цепочку скрытых данных.

  3. Итог: Надежная емкость JPEG — это количество AC-коэффициентов, абсолютное значение которых больше 1.

Код

Для работы с JPEG мы используем библиотеку jpegio. Наша функция calculate_capacity_dct из файла steganography_dct.py реализует описанную логику:

# steganography_dct.py
try:
    import jpegio
except ImportError:
    jpegio = None

def calculate_capacity_dct(carrier_path: str) -> int:
    """
    Рассчитывает емкость, считая все ненулевые AC-коэффициенты, 
    изменение которых не приведет к 0.
    """
    if jpegio is None:
        raise ImportError("Библиотека 'jpegio' не найдена.")
        
    try:
        jpeg = jpegio.read(carrier_path)
    except Exception:
        return 0
    
    available_coeffs = 0
    # Считаем коэффициенты только в канале яркости (Y) - он первый
    y_coeffs = jpeg.coef_arrays[0]
    
    # Проходим по каждому блоку 8x8
    for block_idx in range(y_coeffs.shape[0] * y_coeffs.shape[1] // 64):
        block = y_coeffs.reshape(-1, 64)[block_idx]
        # Проходим по AC-коэффициентам (индексы с 1 по 63)
        for i in range(1, 64):
            # Считаем только те, что не превратятся в 0 при изменении LSB
            if abs(block[i]) > 1:
                available_coeffs += 1
    
    # Каждый такой коэффициент может хранить 1 бит. Делим на 8 и вычитаем запас.
    return available_coeffs // 8 - 20

Особый случай — емкость в офисных документах (DOCX, ODF)

Документы .docx, .xlsx, .odf и т.п. — это, по сути, ZIP-архивы. Метод стеганографии здесь заключается не в изменении существующего контента, а в добавлении нового файла внутрь этой архивной структуры.

Это означает, что у таких документов нет фиксированной стеганографической емкости. Предел ограничен лишь файловой системой и здравым смыслом — ведь файл .docx размером 500 МБ вызовет гораздо больше подозрений, чем обычный. В нашем приложении для таких форматов расчет емкости не выводится, а сообщается, что можно встроить файл практически любого размера.

Практическое применение — зачем все это нужно?

В интерфейсе «ChameleonLab» расчет емкости происходит автоматически при выборе файла-контейнера. Программа немедленно сообщает пользователю, сколько места доступно, и сравнивает это с размером выбранного секрета. Это позволяет избежать ошибок и сразу понять, какой метод и какие настройки (n_bits) лучше использовать для конкретной задачи.

Заключение

Мы увидели, что стеганографическая емкость — это не одна простая формула, а целый набор подходов, зависящих от формата файла-контейнера.

  • Для PNG/BMP это простая арифметика на основе пикселей и n_bits.

  • Для JPEG это сложный подсчет "безопасных" DCT-коэффициентов.

  • Для DOCX/ODF понятие емкости практически отсутствует.

Понимание этих различий — ключ к эффективному и безопасному сокрытию данных.

Последнюю версию программы «Steganographia» от ChameleonLab для Windows и macOS можно скачать на нашем официальном сайте. https://chalab.ru

А чтобы быть в курсе обновлений, обсуждать новые функции и общаться с единомышленниками, присоединяйтесь к нашему Telegram-каналу: https://t.me/ChameleonLab

Комментарии (0)