
Инструмент стеганографии для изображений JPG
jdvrif (JPG Data Vehicle) — это быстрый и простой в использовании инструмент стеганографии командной строки для сокрытия и извлечения файлов любого типа через JPG-изображение. Только для Linux.
Ваш файл данных сжимается с помощью libdeflate/zlib, затем шифруется с помощью XChaCha20-Poly1305 (secretstream из libsodium) ключом, производным от Argon2id из случайно сгенерированного восстановительного PIN-кода, и наконец встраивается в изображение-контейнер. PIN-код отображается один раз, в конце работы команды conceal, и нигде не сохраняется: без него скрытый файл невозможно восстановить.
Используя режим сокрытия по умолчанию, вы можете скрыть файл любого типа, при этом итоговое изображение ограничено размером в 2GiB. Остальные режимы сокрытия для платформ и совместимые сайты социальных сетей (перечисленные ниже) имеют свои собственные гораздо меньшие ограничения по размеру и другие требования.
Существует веб-версия jdvrif, которую можно использовать сразу же как удобную альтернативу загрузке и компиляции исходного кода CLI. Загрузка файлов через веб-интерфейс ограничена 20MiB.
Для тех, кто интересуется этим языком, также доступен экспериментальный порт на Rust jdvrif-rs. Он совместим по формату: любая из сборок может восстановить изображения, созданные другой.
jdvrif частично основан на реализованной технике исследователя в области безопасности David Buchanan.

Демонстрационное изображение: "A place of concealment" / PIN: 7912872750612437051
В отличие от распространённого метода стеганографии LSB (Least Significant Bit), при котором данные скрываются в пикселях изображения-контейнера, jdvrif в основном прячет данные внутри сегментов приложения JPG-изображения (ICC, EXIF, XMP и т. д.).
| Режим сокрытия | Куда помещаются данные | Где можно поделиться итоговым изображением |
|---|---|---|
| (без опции) | сегменты профиля APP2/ICC | X-Twitter, Tumblr, Mastodon, Pixelfed, PostImage, ImgBB, ImgPile, Flickr |
| -b | сегменты EXIF / Photoshop / XMP с обрамлением | только Bluesky |
| -r | DCT-коэффициенты JPEG (QIM) | только Reddit |
| -x | DCT-коэффициенты JPEG (J-UNIWARD/STC) | только X-Twitter |
Два платформенных исключения из метода хранения в сегментах по умолчанию — это Reddit и X-Twitter. У обеих есть собственный режим сокрытия, и ни один из этих режимов вообще не использует сегменты метаданных: -r и -x переносят полезную нагрузку в DCT-коэффициентах JPG-изображения.
Reddit перекодирует загруженные изображения и отбрасывает сегменты метаданных, на которые опирается режим по умолчанию, поэтому -r — единственный режим, который там работает. X-Twitter сохраняет один небольшой сегмент ICC, поэтому режим по умолчанию на этой платформе всё ещё работает, но только для крошечной полезной нагрузки.
Для режима сокрытия Reddit (-r) мы используем метод стеганографии QIM (Quantization Index Modulation в области DCT-коэффициентов JPEG), поскольку это единственный метод хранения, который в настоящее время работает для Reddit. Изображение-контейнер перекодируется в baseline Q75 4:2:0, а полезная нагрузка переносится в его блоках DCT яркости.
Чтобы максимизировать ёмкость хранилища для платформы Reddit, используйте изображение-контейнер с большими размерами, 2048x2048, 4096x4096, 8192x8192 (макс.) и т. д.
Качество изображения-контейнера для этого метода не важно, и его следует оставлять базовым для наибольших размеров, чтобы помочь минимизировать размер файла изображения-контейнера.
Хотя платформа X-Twitter может использовать метод по умолчанию, предоставляемый jdvrif, при котором данные скрываются в сегментах APP2/ICC, X-Twitter ограничивает это одним сегментом ICC с максимальным размером всего ~10KiB.
Чтобы вместить больше этих ~10 КиБ, используйте режим сокрытия платформы X-Twitter (-x). Он полностью отказывается от сегментов метаданных — в ICC-профиль ничего не записывается — и вместо этого использует адаптивный метод стеганографии J-UNIWARD с кодированием Syndrome-Trellis (STC). Контейнер транскодируется в прогрессивный 4:2:0 с качеством, производным от исходного (с ограничением Q97).
Чтобы максимизировать ёмкость хранилища для платформы X-Twitter, используйте контейнерное изображение высокого качества/детализации с большими размерами, 1024x1024, 2048x2048, 4096x4096 (макс.) и т. д.
Носители -r и -x шифруют ваши данные и привязывают их местоположение к вашему PIN-коду восстановления с помощью Argon2id, но встраивание всё равно изменяет статистику DCT изображения, поэтому целенаправленный стегоанализ может выявить, что изображение содержит скрытые данные.
Изображения -r и -x, созданные с помощью jdvrif v9.0, остаются восстановимыми, но v9.0 не может восстановить изображения -r или -x, созданные с помощью v9.1.
Оба режима DCT переносят гораздо меньше данных, чем режим по умолчанию, поэтому используйте capsize для измерения контейнерного изображения перед выбором полезной нагрузки (см. Проверка ёмкости).
Для сборки требуются CMake 3.20 или новее, flock из util-linux, а также Ninja (предпочтительно) или Make. Компилятор должен быть GCC 14 или новее либо Clang 18 или новее в паре со стандартной библиотекой C++23, реализующей такие возможности, как std::format и std::print. Требуемые нативные библиотеки: libsodium, libjpeg-turbo (оба API — turbojpeg и libjpeg), zlib и libdeflate. OpenMP необязателен: при его наличии он распараллеливает проход вычисления стоимости J-UNIWARD для -x.
$ sudo apt update
$ sudo apt install g++ cmake ninja-build util-linux libsodium-dev libturbojpeg0-dev libjpeg-dev zlib1g-dev libdeflate-dev
$ g++ --version # confirm the reported version is 14 or newer
$ chmod +x compile_jdvrif.sh
$ ./compile_jdvrif.sh
$ sudo cp jdvrif /usr/bin
Если в вашем дистрибутиве GCC 14 поставляется как версионированный пакет, установите g++-14 и выполните сборку командой CXX=g++-14 ./compile_jdvrif.sh.
Обёртка хранит объектные файлы с отслеживанием зависимостей в src/build/, поэтому при последующих запусках пересобирается только изменённое, а опубликованный бинарный файл jdvrif заменяется только после полной успешной сборки. Задайте JDVRIF_JOBS=<count>, чтобы изменить ограничение параллелизма (по умолчанию: число CPU, но не более 8), JDVRIF_BUILD_DIR=<path> для использования отдельного кэша сборки или BUILD_MODE=sanitize для сборки с ASan/UBSan.
$ jdvrif
Usage: jdvrif conceal [-b|-r|-x] <cover_image> <secret_file>
jdvrif recover <cover_image>
jdvrif capsize [-r|-x] <cover_image>
jdvrif --info
Запустите jdvrif --info, чтобы получить полное встроенное руководство по режимам, параметрам платформ и ограничениям размера.
$ jdvrif conceal your_cover_image.jpg your_secret_file.doc
Platform compatibility for output image:-