![](https://habrastorage.org/webt/vb/zs/t9/vbzst9kbyntpdzvf31taxduv0tg.png)
Сокрытие сообщения в другом сообщении относится к области стеганографии. В этой статье мы будем прятать одну фотографию внутри другой. В результате при передаче такое фото будет выглядеть как обычный снимок, но по факту содержать два. Второй при этом можно будет извлечь при помощи внешнего инструмента.
Используя этот метод, можно прятать в своей художественной работе подпись или сохранять несколько снимков как один в целях экономии памяти на миниатюрных устройствах. Есть ещё один аналогичный подход, с помощью которого игровые ресурсы картриджей Pico-8 включаются в небольшой PNG самой игры*.
*Подробнее в статье «Steganography: decoding Pico-8 cartridges».
▍ Фотографии как матрицы
Чтобы иметь возможность управлять фотографиями и встраивать в них что-либо, сначала нужно разобраться с их возможным представлением и сохранением. Один из вариантов – это представить снимки в виде математических матриц, в которых каждая ячейка выражает пиксель, а её значение – цвет этого пикселя/ячейки.
![](https://habrastorage.org/webt/bx/ty/r3/bxtyr3d7iauygdjyp80vryoowak.png)
Например, при такой матрице:
![](https://habrastorage.org/webt/ut/-f/bf/ut-fbfb5uv3qluhd7q5yh0p9mgk.png)
Мы получим такое фото:
![](https://habrastorage.org/webt/tw/rk/8v/twrk8vy9ofbondtp96n30oqpmlq.png)
Если фотографию и матрицу сопоставить, то можно заметить, чем ближе значение к
255
, тем белее пиксель. При этом 0
означает чёрный, а всё между 0
и 255
оттенки серого.▍ Фотографии как битовые матрицы
Итак, снимки в виде матриц мы представили. Теперь давайте немного поботаним и выразим значение каждой ячейки не в десятичном, а в двоичном виде (обещаю, дальше это пригодится).
Та же фотография с помощью этой матрицы теперь будет выражаться так:
![](https://habrastorage.org/webt/w0/pe/hx/w0pehx1trzmeanxmdonkh-yikaq.png)
Далее нам нужно выяснить, что произойдёт с фотографией, если изменить младший бит. Для этого я их всё реверсирую и посмотрю, как в итоге будут выглядеть матрица и новое фото:
![](https://habrastorage.org/webt/wr/n-/rp/wrn-rpp2ci_bd_h-b0k4gzjz8mc.png)
![](https://habrastorage.org/webt/fy/e0/c4/fye0c4spne0118rtaefdtl0b58o.png)
Можете разглядеть какие-либо изменения? Предполагаю, что нет. Полученный вариант определённо выглядит так же, как оригинал (если только вы не обладатель сверхзрения), поскольку мы изменили лишь младшие биты, имеющие наименьшую значимость. С помощью этого элементарного приёма можно встраивать фотографии одну в другую, не вызывая подозрений в отношении оригинального снимка.
▍ Встраивание фото
Для встраивания фотографии нужно заменить каждый младший бит основного снимка на каждый бит встраиваемого, то есть размер фото, которое мы прячем, должен быть меньше основного.
![](https://habrastorage.org/webt/is/oj/u3/isoju3typi07ivm5ncilybsthss.png)
Но насколько меньше? В видимой фотографии размером n * m есть nm/8 младших бит, то есть внутри неё можно разместить фото размером √nm/8 * √nm/8. Например, при размере видимого снимка 1000 * 1000px мы получаем:
![](https://habrastorage.org/webt/i9/ip/pq/i9ippqwdy7snidm4dwdukbxpqdk.png)
Это означает, что можно скрыть в нём фотографию размером 353 * 353px.
▍ Цветные фото
В цветных снимках каждый пиксель представлен тремя матрицами: красной, зелёной и синей. Вместо этого можно рассматривать такие снимки как одну матрицу с кортежами из трёх значений в диапазоне от
0
до 255
.![](https://habrastorage.org/webt/qp/53/cq/qp53cqon4vspqz75ifijvom7cru.png)
В этом случае наш подход по встраиванию фотографии также сработает – нужно лишь заменить все младшие биты в каждой матрице каждой ячейки.
▍ PNG, JPEG и сжатие
Вы наверняка знаете, что некоторые форматы фото (например, JPEG) сильно сжимают исходное изображение, используя различные математические техники (например, вейвлет Хаара). Что же происходит со встраиваемым фото в таком случае? Оно с наибольшей вероятностью уничтожается, и при попытке извлечения мы увидим лишь шум. Но есть и другие форматы, например, PNG, которые сохраняют фотографию. Так что можно использовать рассмотренный трюк с ними.
▍ Реализация
Я реализовал этот метод давно, когда ещё учился на бакалавра, и соответствующий код лежит здесь. Это десктопное приложение, в котором для работы с битами фотографий используется Emgu CV.
![](https://habrastorage.org/webt/ou/g5/kh/oug5kh6sjydt9llengsiebnp40w.png)