Реализация стеганографического метода Коха-Жао на Ruby

от автора

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

Алгоритм Коха-Жао для встраивания информации использует частотную область контейнера и заключается в относительной замене величин коэффициентов дискретного косинусного преобразования (ДКП). Изображение разбивается на блоки размерностью 8×8 пикселей и к каждому блоку применяется ДКП. Каждый блок пригоден для записи одного бита информации.

Итак алгоритм скрытия будет следующим:

— итерируем изображение двойным массивом с шагом в 8
— на каждой итерации создаем временный массив 8×8 пикселей, каждым элементом которого будет набор трех цветов пикселя.
— применяем ДКП к этому массиву, и получаем массив коэффициентов размером 8×8
— выбираем 2 коэффициента и высчитываем их разность по модулю
— если разность меньше или равна 25, то присваиваем первому коээфициенту положительное значение второго + константа, либо тоже самое но со знаком минус(это называется передача бита)
— если разность меньше или равна -25, то те же деяствия только для второго коэффициента.
— далее применяется обратное ДКП чтобы перевести наши коээфициенты обратно в пространственную область.
— после чего копируем новые значения цветов в изображение.

Реализация функции ДКП и ОДКП на языке Ruby выглядит следующим образом:

def dct(dct,arr)   s=0   (0..7).each do |i|     (0..7).each do |j|       temp = 0.0       (0..7).each do |x|         (0..7).each do |y|           temp = temp + $cos_t[i][x]*$cos_t[j][y]*arr[x][y][:blue]         end       end       dct[i][j] = $e[i][j]*temp     end   end   return dct end  def idct(dct,arr)   (0..7).each do |i|     (0..7).each do |j|       temp = 0       (0..7).each do |x|         (0..7).each do |y|           temp += dct[x][y]*$cos_t[x][i]*$cos_t[y][j]*$e[x][y]           arr[i][j][:blue] = (temp > 255) ? 255 : (temp < 0 ) ? 0 : temp.round;         end       end     end   end   return arr end 

$cos_t и $e — это глобальные переменные-массивы с уже заполненными значениями.

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

Полный код скрипта реализующего скрытие\чтение информации:

require 'RMagick' include Magick  $cos_t = [            [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],                       [0.9807853, 0.8314696, 0.5555702, 0.1950903,                        -0.1950903,-0.5555702,-0.8314696,-0.9807853],                        [0.9238795, 0.3826834,-0.3826834,-0.9238795,                         -0.9238795,-0.3826834, 0.3826834, 0.9238795],                         [0.8314696,-0.1950903,-0.9807853,-0.5555702,                          0.5555702, 0.9807853, 0.1950903,-0.8314696],                          [0.7071068,-0.7071068,-0.7071068, 0.7071068,                           0.7071068,-0.7071068,-0.7071068, 0.7071068],                           [0.5555702,-0.9807853, 0.1950903, 0.8314696,                            -0.8314696,-0.1950903, 0.9807853,-0.5555702],                            [0.3826834,-0.9238795, 0.9238795,-0.3826834,                             -0.3826834, 0.9238795,-0.9238795, 0.3826834],                             [0.1950903,-0.5555702, 0.8314696,-0.9807853,                              0.9807853,-0.8314696, 0.5555702,-0.1950903] ]  $e = [             [0.125, 0.176777777, 0.176777777, 0.176777777,                     0.176777777, 0.176777777, 0.176777777, 0.176777777],                     [0.176777777, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25],                     [0.176777777, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25],                     [0.176777777, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25],                     [0.176777777, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25],                     [0.176777777, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25],                     [0.176777777, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25],                     [0.176777777, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25]];  def insert_message(image,text)   i = image.copy   dct = Array.new(8).map!{Array.new(8)}   k = 0   l = 0   s=0   temp = Array.new(8).map!{Array.new(8)}   (0..(image.columns - 1)).step(8) do |i|     (0..(image.rows - 1)).step(8) do |j|       break if l >= text.length*8       (0..7).each do |x|         (0..7).each do |y|           temp[x][y] = {              :red=>image.pixel_color(j+x,i+y).red,             :green=>image.pixel_color(j+x,i+y).green,             :blue=>image.pixel_color(j+x,i+y).blue           }         end       end        dct = dct(dct,temp)       k = dct[3][4].abs - dct[4][3].abs       if get_bit(text,l)         if k<=25           dct[3][4] = (dct[3][4]>=0) ? dct[4][3].abs + 150 : -1*(dct[4][3].abs + 150)         end       else         if k>=-25           dct[4][3] = (dct[4][3]>=0) ? dct[3][4].abs + 150 : -1*(dct[3][4].abs + 150)         end       end       xt  = temp.clone       temp = idct(dct,temp)       (0..7).each do |x|         (0..7).each do |y|           pixel = Pixel.new(temp[x][y][:red],temp[x][y][:green],temp[x][y][:blue])           image.pixel_color(j+x,i+y,pixel)         end       end       l=l+1     end     break if l >= text.length   end   image.write('cr.bmp')   return image end  def read_message(image)   k = 0   s=0   out = []   l=0   a=''   p=0   b=0   dct = Array.new(8).map!{Array.new(8)}   temp = Array.new(8).map!{Array.new(8)}   (0..(image.columns - 1)).step(8) do |i|     (0..(image.rows - 1)).step(8) do |j|       (0..7).each do |x|         (0..7).each do |y|           temp[x][y] = {              :red=>image.pixel_color(j+x,i+y).red,             :green=>image.pixel_color(j+x,i+y).green,             :blue=>image.pixel_color(j+x,i+y).blue           }         end       end       l=l+1       dct = dct(dct,temp)       k = dct[3][4].abs-dct[4][3].abs        if k>=25         a=1       elsif k<=-25         a=0       else         a=-1         break       end       b |= a << p       if p==7         out.push(b.chr)         b=0       end       p=(p<7) ? p+1 : 0     end     if a==-1       break     end   end   return out.join end  def dct(dct,arr)   s=0   (0..7).each do |i|     (0..7).each do |j|       temp = 0.0       (0..7).each do |x|         (0..7).each do |y|           temp = temp + $cos_t[i][x]*$cos_t[j][y]*arr[x][y][:blue]         end       end       dct[i][j] = $e[i][j]*temp     end   end   return dct end  def idct(dct,arr)   (0..7).each do |i|     (0..7).each do |j|       temp = 0       (0..7).each do |x|         (0..7).each do |y|           temp += dct[x][y]*$cos_t[x][i]*$cos_t[y][j]*$e[x][y]           arr[i][j][:blue] = (temp > 255) ? 255 : (temp < 0 ) ? 0 : temp.round;         end       end     end   end   return arr end  def get_bit(str,pos)   return true if  str[pos/8].ord & (1 << pos % 8) > 0   return false if  str[pos/8].ord & (1 << pos % 8) <= 0 end  image = Magick::Image.read('src.bmp').first insert_message(image,"qweqwe")   image = Magick::Image.read('dst.bmp').first puts read_message image 

ссылка на оригинал статьи http://habrahabr.ru/post/216207/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *