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

Колись давно я написав свій перший пост на хабрі. І присвячений той пост був дуже цікавою проблемою, а саме стеганографією. Звичайно, рішення, запропоноване в тому старому топіку, не можна назвати стеганографією в цьому сенсі. Це лише гра з форматами файлів, але, проте, досить цікава гра.

Сьогодні ми спробуємо копнути трохи глибше і розглянемо алгоритм LSB. Якщо вам цікаво, ласкаво прошу під кат. (Під катом трафік: біля мегабайта.)

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

Звичайно ж, ніхто не забороняє поєднувати криптографічні та стеганографічні методи. Більше того, практично так і роблять, але наше завдання розібратися з основами. Якщо уважно вивчити статтю з Вікіпедії, можна дізнатися, що алгоритми стеганографії фігурує т.зв. контейнер та повідомлення. Контейнер – це будь-яка інформація, яка допомагає приховати наше секретне повідомлення.

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

Перші два байти заголовка - це сигнатура BM, далі в подвійному слові записаний розмір файлу в байтах, наступні 4 байти зарезервовані і повинні містити нулі і, нарешті, ще в одному подвійному слові записано зсув від початку файлу, до власне байтів зображення. У 24-бітовому bmp-файлі кожен піксел кодується трьома байтами BGR.

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

Зрозуміло, що можна міняти не лише 2 молодших біти, а й будь-яку їх кількість. Тут є така закономірність: що більше біт ми змінюємо, то більший обсяг інформації ми можемо сховати, і більші перешкоди у вихідному зображенні це викличе. Для прикладу ось вам два зображення:

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

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

Вважаємо, що ми записуємо в контейнер текст, що зберігається в рядку і замінюємо молодші два байти:
Код для запису:

for i:=1 to length(str) do
    починати
      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
    починати
      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;

Ну і для зовсім лінивих - посилання на програму та її вихідний код.

Спасибо.

Джерело: habr.com

Додати коментар або відгук