LSB стеганография

    Когда-то давно я написал свой первый пост на хабре. И посвящён тот пост был весьма интересной проблеме, а именно стеганографии. Конечно, решение, предложенное в том старом топике, нельзя назвать стеганографией в истинном смысле этого слова. Это всего лишь игра с форматами файлов, но, тем не менее, довольно интересная игра.

    Сегодня мы попробуем копнуть чуть-чуть глубже и рассмотрим алгоритм LSB. Если вам интересно, милости прошу под кат. (Под катом трафик: около мегабайта.)

    Прежде всего, необходимо сделать небольшое вступление. Всем известно, что предназначение криптографии – сделать невозможным чтение секретной информации. Разумеется, криптография имеет свои области применения, но есть и другой подход к защите данных. Можно не шифровать информацию, а сделать вид, что у нас её нет. Именно для этого и придумана стеганография. Википедия уверяет нас что, «стеганография (от греч. στεγανοσ — скрытый и греч. γραφω — пишу, буквально «тайнопись») — это наука о скрытой передаче информации путём сохранения в тайне самого факта передачи.

    Конечно же, никто не запрещает совмещать криптографические и стеганографические методы. Более того, на практике так и делают, но наша задача разобраться с основами. Если внимательно изучить статью с Википедии, можно узнать, что в алгоритмах стеганографии фигурирует т.н. контейнер и сообщение. Контейнер — это любая информация, помогающая скрыть наше секретное сообщение.

    В нашем случае контейнером будет выступать картинка в формате BMP. Для начала рассмотрим структуру этого файла. Файл условно можно разбить на 4 части: заголовок файла, заголовок изображения, палитру и само изображение. Для наших целей надо знать только то, что записано в заголовке.

    Первые два байта заголовка – это сигнатура BM, далее в двойном слове записан размер файла в байтах, следующие 4 байта зарезервированы и должны содержать нули и, наконец, в ещё одном двойном слове записано смещение от начала файла, до собственно байтов изображения. В 24-битном bmp-файле каждый пиксел кодируются тремя байтами BGR.

    Теперь мы знаем, как добраться до изображения, осталось понять, как туда можно записать необходимую нам информацию. Для этого нам и пригодится метод LSB. Суть метода заключается в следующем: мы заменяем младшие биты в байтах, отвечающих за кодирование цвета. Допустим, если очередной байт нашего секретного сообщения – 11001011, а байты в изображении –…11101100 01001110 01111100 0101100111…, то кодирование будет выглядеть так. Мы разобьём байт секретного сообщения на 4 двухбитовые части: 11, 00, 10, 11, и заменим полученными фрагментами младшие биты изображения: …11101111 01001100 01111110 0101100111…. Такая замена в общем случае не заметна человеческому глазу. Более того, многие старые устройства вывода, даже не смогут отобразить такие незначительные перемены.

    Понятно, что можно менять не только 2 младших бита, но и любое их количество. Тут есть следующая закономерность: чем большее количество бит мы меняем, тем больший объём информации мы можем спрятать, и тем большие помехи в исходном изображении это вызовет. Для примера вот вам два изображения:

    image
    image

    При всём желании я так и не сумел увидеть разницы между ними, а тем не менее во втором изображении с помощью описанного метода спрятана поэма Льюиса Кэролла «Охота на Снарка». Если вы дочитали до этого момента, то вам наверняка интересно узнать и о реализации. Она довольна проста, но сразу предупрежу, что сделано всё на Delphi. Причин этому две: 1. Я считаю Delphi хорошим годным языком; 2. Эта программа родилась, в процессе подготовки курса по основам машинного зрения, а ребята, которым я этот курс читаю, пока ничего кроме Delphi не знают. Для тех, кто не знаком с синтаксисом надо пояснить одну вещь shl x – побитовый сдвиг влево на x, shr x – побитовый сдвиг вправо на x.

    Считаем, что мы записываем в контейнер текст, хранящийся в строке и заменяем младшие два байта:
    Код для записи:

    for i:=1 to length(str) do
        begin
          l1:=byte(str[i]) shr 6;
          l2:=byte(str[i]) shl 2; l2:=l2 shr 6;
          l3:=byte(str[i]) shl 4; l3:=l3 shr 6;
          l4:=byte(str[i]) shl 6; l4:=l4 shr 6;
     
          f.ReadBuffer(tmp,1);
          f.Position:=f.Position-1;
          tmp:=((tmp shr 2) shl 2)+l1;
          f.WriteBuffer(tmp,1);
     
          f.ReadBuffer(tmp,1);
          f.Position:=f.Position-1;
          tmp:=((tmp shr 2) shl 2)+l2;
          f.WriteBuffer(tmp,1);
     
          f.ReadBuffer(tmp,1);
          f.Position:=f.Position-1;
          tmp:=((tmp shr 2) shl 2)+l3;
          f.WriteBuffer(tmp,1);
     
          f.ReadBuffer(tmp,1);
          f.Position:=f.Position-1;
          tmp:=((tmp shr 2) shl 2)+l4;
          f.WriteBuffer(tmp,1);
     
        end;

    код для считывания:
    for i:=1 to MsgSize do
        begin
          f.ReadBuffer(tmp,1);
          l1:=tmp shl 6;
          f.ReadBuffer(tmp,1);
          l2:=tmp shl 6; l2:=l2 shr 2;
          f.ReadBuffer(tmp,1);
          l3:=tmp shl 6; l3:=l3 shr 4;
          f.ReadBuffer(tmp,1);
          l4:=tmp shl 6; l4:=l4 shr 6;
          str:=str+char(l1+l2+l3+l4);
        end;


    Ну и для совсем ленивых – ссылка на программу и её исходный код.

    Спасибо.
    Share post

    Comments 41

      +1
      Хорошая статья. Само то почитать вечером, сильно не напрягая мозги. Хотелось бы почитать о других алгоритмах и способах стенографии в таком же непринужденном стиле.

      P.S. Возможно, не лишним будет предупреждение о трафике, все-таки почти мегабайт в двух изображениях.
        0
        Спасибо, постараюсь.
          +1
          Метод тривиален, его обнаружение тоже тривиально. Мне знакомый, занимающийся этой темой, рассказывал, что со многими картинками прокатит такой способ: вытягиваем младшие биты со всего изображения и строим на их основе черно-белое изображение того разрешение. Получившаяся Картинка должна быть очень сильно похожа на оригинал, если нет — то там что-то есть, и этого знания, что что-то есть иногда вполне достаточно.
          Есть и другие, более продвинутые методы, над которыми он и работал.
            +1
            С чего это картинка из младших битов должна быть похожа на оригинал?

            Там только шумы будут же, не?
          0
          Стенография — это несколько другое, здесь описана стеганография. Просто чтобы вы не путил понятия.
            0
            *не путали
          0
          Изображение почти без изменений цвета. Я, например, невооружённым взглядом увидел, что верхняя граница «Охоты на Снарка» проходит где-то тут:

          Photoshop подтвердил
            0
            Всегда завидовал людям с хорошим зрением. А если по теме, то всегда можно менять, не два последних бита, а один: заметить границу станет тяжелее.
              0
              Конечно. Да, и не на монотонном фоне уже вообще ничего и не почувствуется
                +1
                Скорее людям с хорошими мониторами.
                  0
                  Скорее людям с плохими углом монитора ;)
                0
                Уж лучше RARJPEG применять, чем такой способ.
                  0
                  При использовании LSB не изменяется размер файла. Это его несомненный плюс.
                    0
                    Сейчас вместо проверки размера принято делать проверку контрольной суммы, так что плюс небольшой.
                      0
                      проверка контрольных сумм прокатила бы, если бы было исходное изображение
                        0
                        Ну вот и я о том же.
                          0
                          В таком случае, зачем оставлять оригинал?
                          • UFO just landed and posted this here
                  +3
                  Решение проблемы очевидно — нужно забивать неиспользованные LSB шумом. Тогда границы не будет.
                  0
                  Мм… Опередили меня со статьёй =) Как-раз вчера в топике про теги в мп3 выяснилось что хаброюзерам вообщем-то интересна эта тема.
                    +1
                    На этот алгоритм есть простая, но в то же время интересная (как мне кажется) атака.
                    Как правило, в качестве картинке-контейнера выступает фотография. В настоящей фотографии вероятности встретить, скажем, пиксели со значениями R равными 128 и 129 отличаются (аналогично для значений 130 и 131). Мы же записываем в младший бит фактически равномерно распределённый шум, поэтому выравниваем вероятности для соседних чётных и нечётных значений.

                    Анализируя разности между количествами таких вот соседних пикселей, можно сделать предположение о том, присутствует в изображении вложение или нет, и даже оценить его размер, если вложение «упаковано» в подряд-идущих пикселях. Метод реально работающий, нашёл его в книжке «Цифровая стеганография», когда сам интересовался этим вопросом.
                    • UFO just landed and posted this here
                        0
                        Теоретически можно так закодировать информацию, чтобы полученная гистограмма изображения была похожа на натуральную.
                        +2
                        Маленький нюанс по коду — ((x shr 2) shl 2)
                        все таки лучше реализовывать как
                        (x and $FC)
                          0
                          Вроде как старая тема. Еще похожий трюк с wav и gif прокатывает.
                            0
                            Сначала прочитал «LSD стенография»
                              0
                              snark
                              А вот и они — два изображения с режимом слоя Divide
                                0
                                Это всё хорошо, но есть два небольших замечания:
                                1. При записи информации, можно во всех остальных байтах тоже заменить последние биты, тогда граница сообщения будет не так видна.
                                2. Важно понимать, что для злоумышленника доступно только изображение с закодированным текстом. Т.е. исходного изображения нет, поэтому побайтовое сравнение изображений не сработает.
                                  0
                                  Сравнить с изображением, в котором эти последние биты — нулевые.
                                    0
                                    С флагом это сработает, а как быть с изображениями со сложным фоном?
                                      0
                                      Статистическим анализом можно извлечь кое-что.
                                    0
                                    Просто интересно было, насколько оно действительно меняет пиксели. Естественно это не метод поиска скрытых данных…
                                      0
                                      Итоговая версия программа может менять 1, 2 или 4 последних пикселя. Причём, если размер контейнера позволяет, то искажения минимальны. А зашумление остальных пикселов я добавил, спасибо.
                                  0
                                  Вам нужно было просто привести примеры с реальными картинками, а не флагом
                                    0
                                    Когда-то в рамках учебного курса тоже занимался таким методом, вот мои картинки для разбавления флага :)



                                      0
                                      Это полноценно восстанавливаемое изображение, или PNG-образец?
                                        0
                                        Это PNG-скриншот BMP-изображений исходного (слева) и содержащим сообщение (справа). Конечно, прямо из этой картинки сообщения уже не извлечь
                                          0
                                          Но сообщение там про историю становления математического факультета)
                                            0
                                            мм, почему из PNG не извлечь сообщение? Он ведь сжимает без потерь.
                                              0
                                              Это будет очень по стеганографичному — я ведь эту картинку вытащил из отчёта (.doc), увеличив масштаб немного и сделав скриншот. Теоретически конечно возможно… Ставлю плюс тому кто сможет)
                                      0
                                      Спасибо, теперь кто-нибудь закодирует библиотеку конгресса США в Санта-Барбара.

                                      Only users with full accounts can post comments. Log in, please.