Блог веб-студии RubyRuby

Здесь мы делимся нашим опытом.

Битовые изображения и метод LSB

Битовые изображения:

Битовые изображения были введены компанией Microsoft для стандартизации форматов файлов изображений для операционных систем семейства Windows. На сегодняшний день этот формат файлов поддерживается множеством файловых и операционных систем, но их использование становится все реже. Одна из причин этому – большой размер файлов, являющийся следствием слабого сжатия и многословности файлового формата. Однако, это дает преимущество при скрытии информации не вызывая подозрений. Для понимания того, как битовые изображения могут использоваться при сокрытии данных, необходимо разобраться в структуре файлового формата.

Структура формата битовых изображений:

Файл битового изображения можно разделить на два главных блока, заголовок и служебная информация. Заголовок, который состоит из 54 байт можно в свою очередь разбить на еще два подблока, битовый заголовок и битовая информация. Те изображения, которые меньше 16-бит, имеют дополнительный блок в заголовке, называемый цветовой палитрой.

Заголовок битового изображения

Заголовок битового изображения используется для идентификации файла как правильного битового изображения. Это определяется, прежде всего первыми двумя байтами, значения которых, должны быть 0x42 и 0x4D, что является ‘BM’ соответствуя ASCII-таблице. Следующие четыре байта содержат информацию о размере файла. Оставшиеся восемь зарезервированы для идентификации приложения и длины сдвига.

  • 0-1 Идентификатор битового изображения 0x42 и 0x4D (BM по ASCII-таблице)
  • 2-5 Размер битового изображения
  • 6-9 Зарезервировано
  • 10-13 Сдвиг до начала информации

Служебная информация состоит из следующих 30ти байт, начиная с 14го байта. Эта информация описана как:

  • 14-17 Размер заголовка
  • 18-21 Ширина изображения
  • 22-25 Высота изображения
  • 26-27 Количество цветовых плоскостей
  • 28:29 Глубина цвета
  • 30-33 Метод сжатия
  • 34-37 Размер данных изображения
  • 38-41 Количество пикселей на метр по горизонтали
  • 42-45 Количество пикселей на метр по вертикали
  • 46-49 Количество используемых цветов
  • 50-53 Количетсво наиболее важных используемых цветов

Данные изображения

Блок с данными изображения содержит непосредственно изображение хранящееся в пикселах. Этот файловый формат демонстрирует ряд уникальных свойств. Одно из которых поддается использованию в целях стеганографии. Во-первых, это то, что изображение хранится в обратном порядке(little-endian – от младшего байта к старшему). Первая строка блока данных соответствует последней строке изображения. Также и пикселы сохранены в обратном порядке – первым идет синий, за ним зеленый и наконец, красный. Свойство полезное для целей стеганографии заключается в том, что эти пиксели точно сохраняются в файле, что делает простым их идентифицирование и изменение.

Пример части bmp файла:

c0cdd2 c3ced3 c3ccd5 [“\xC0”, “\xCD”, “\xD2”, “\xC3”, “\xCE”, “\xD3”, “\xC3”, “\xCC”, “\xD5”]

c3ced3 c3ccd5 cbccd3 [“\xC3”, “\xCE”, “\xD3”, “\xC3”, “\xCC”, “\xD5”, “\xCB”, “\xCC”, “\xD3”]

c3ccd5 cbccd3 cbced2 [“\xC3”, “\xCC”, “\xD5”, “\xCB”, “\xCC”, “\xD3”, “\xCB”, “\xCE”, “\xD2”]

cbccd3 cbced2 cbd0d5 [“\xCB”, “\xCC”, “\xD3”, “\xCB”, “\xCE”, “\xD2”, “\xCB”, “\xD0”, “\xD5”]

Каждый пиксель несжатого 24-битного изображения представлен 24ю битами или тремя байтами. Каждый байт состоит из 8 битов, который соответствует одному из трех цветовых каналов, красного, синего или зеленого. Например абсолютно белый пиксель в бинарном виде представляется как 11111111 11111111 11111111, а абсолютно черный как 00000000 00000000 00000000. Использование восьми бит на каждый цветовой канал, имеет 28 вариантов, что является 256ю различными цветами для каждого канала. В свою очередь 256 вариантов цвета канала, получается 2563 = 16777216 возможных цветов для каждого пикселя.

Рядом стоящие номера цветов как 100,101,102,103 отличаются лишь интенсивностью от предыдущих. Человеческий глаз не способен различить два рядом стоящих цвета в единой битовой плоскости и определенно не способен различить два рядом стоящих цвета в диапазоне 0-16777216.

Ниже представлена уменьшенная версия немодифицированного 834x1200 несжатого 24х битного растрового изображения. Файл данного изображения состоит из 1000800 пикселей (834*1200 = 1000800), которые в свою очередь представляют 3002400 байт. Обычно битовые изображения таких размеров не применяют для практических целей. Данное изображение было выбрано для демонстрации в связи с тем, что имеет много шума, что является полезным фактором для скрытия информации, который будет рассмотрен ниже.

Это уменьшенное изображение, которое дальше будет разбито еще на три, каждое из которых будет представлять один из трех цветовых каналов, красного,синего и зеленого. Это достигается обнулением остальных двух цветовых каналов для конкретного цвета. Например, если пиксель представлен в бинарном виде, как 01001110 01100110 01010110, то для представления его в красной цветовой плоскости, он должен выглядеть как 01001110 00000000 00000000. Для зеленой плоскости пиксель будет иметь вид 00000000 01100110 00000000.

Это единственное, что необходимо изменить для представления изображения для каждой цветовой плоскости.

Для пикселя который представлен массивом элементы которого, являются байтами цветовых плоскостей, код для представления в красном цвете на языке Ruby будет следующим:

1
2
3
4
5
\#line[0] =  line[0] # не меняем красный канал

line[1] = (0b00000000).to_i >> 3 # зеленый обнуляем

line[2] = (0b00000000).to_i  # синий обнуляем

Изображение в красной цветовой плоскости

Изображение в зеленой цветовой плоскости

Изображение в синей цветовой плоскости

Необходимо сказать, что хотя спецификация формата файла bmp гласит что вся информация представляющаяся как целые числа должна иметь порядок байт от младшего к старшему(little-endian), на практике оказалось,что большинство приложений сохраняют изображения данного формата в порядке от старшего к младшему(big-endian). В связи с этим первый элемент массива line является красным каналом. Несмотря на это, знание структуры хранения информации, является очень важным для понимания принципов скрытия информации в изображении. Одним из популярных методов скрытия, является техника где используется только одна цветовая плоскость, это позволяет наименьшим образом разрушать исходное изображение.

Шум

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

При исследовании изображения с выборкой младших значащих бит становится очевидным отсутствие сходства с исходным изображением. На изображении можно увидеть лишь отображение случайного шума, а также небольшие цветные области изображения внизу, соответствующие областям исходной картинки, где значения младших значащих бит равны 0 имеют идентичные пиксели для восприятия.

Изображение отражающее старшие значащие биты

Изображение отражающее младшие значащие биты

Выделение выборки младших и старших значащих бит заключается в представлении пикселя как каждого цветового канала в виде 00000000 и 11111111 соответственно. Например, если пиксель представлен в бинарном виде, как 01001101 01101110 10101111, то младший значащий пиксель должен быть 11111111 00000000 11111111, а старший значащий пиксель, как 00000000 00000000 11111111.

Ниже представлены два метода демонстрирующие данную функциональность в Ruby:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def getLSB byte
  if((byte.to_i % 2) == 1)
    return 0b11111111
  else  
    return 0b00000000
  end
end

def getMSB byte
  if( byte.to_i > 127)
    return 0b11111111
  else  
    return 0b00000000
  end
end

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

Скрытие информации

Количество информации, которое может быть скрыто в изображение, прямо пропорционально его размеру и специфики метода скрытия. Рассмотрим изображение размером 200x267 пикселей. Используя формат 24-битного несжатого изображения получаем размер в 160200 байт или 160 килобайт. Это посчитано путем умножения соотношения сторон (200x267=53400 пикселей) и умножив на 3, так как имеем 3 цветовые плоскости. Это соответствует 1281600 бит, которые мы можем модифицировать. На самом же деле наши возможности куда меньше.

Большинство стеганографических техник скрытия информации использует 1 бит на байт для сохранения информации, реже меньше. Кроме того, помним, что скрытие 1го бита информации не очень целесообразно. Зачастую мы хотим скрывать текст, который имеет размер в несколько десятков байт, каждый их которых представлен 8ю битами. Более менее реальный лимит на количество скрываемых данных будет (160200/8 = 20025). Этого достаточно для сохранения декларации о независимости дважды в случае простого текста. Но если мы хотим использовать шифрование, то это достаточно мало.

Рассмотрим простейшую технику сткрытия, которая основывается на замене младших бит на языке Ruby

допустим у нас имеется массив bytes, который хранит секретное сообщение в бинарном виде, для обычной строки это может выглядеть как

1
"secret".unpack("C*")

Сам алгоритм на Ruby сводится к следующему

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
loop {
  begin
    line = src_file.readline #src_file - дескриптор файла картинки
  rescue
    break
  end
  break unless line
  line = line.split(' ').map{|x| x.to_i}
  0.upto(line.length / 3 - 1) do |x|
    if offset < bytes.length
      byte = bytes[offset]
      pixel = x * 3
      # xxx0 0000 Красная плоскость занимает 3 бита 
            line[pixel] = line[pixel] & 0xF8 | ((byte >> 5) & 0x7)
            # 000x x000 Зеленая следующие 2
            line[pixel + 1] = line[pixel + 1] & 0xFC | ((byte >> 3) & 0x3)
            # 0000 0xxx Синяя оставшиеся 3
            line[pixel + 2] = line[pixel + 2] & 0xF8 | (byte & 0x7)
      offset += 1
    end
  end
}

Данный метод совершенно не устойчив к любым атакам, и легко обнаружается простым гистограммным анализом. Более современные алгоритмы будут описаны в следующих статьях.

Заказать сайт на Ruby on Rails

Комментарии