Колись давно я написав свій
Сьогодні ми спробуємо копнути трохи глибше і розглянемо алгоритм LSB. Якщо вам цікаво, ласкаво прошу під кат. (Під катом трафік: біля мегабайта.)
Насамперед, необхідно зробити невеликий вступ. Всім відомо, що призначення криптографії – унеможливити читання секретної інформації. Зрозуміло, криптографія має свої сфери застосування, але є й інший підхід до захисту даних. Можна не шифрувати інформацію, а вдати, що в нас її немає. Саме для цього і вигадана стеганографія. Вікіпедія запевняє нас, що «стеганографія (від грец. στεγανοσ — прихований і грецьк. γραφω — пишу, буквально «таємнопис») — це наука про приховану передачу інформації шляхом збереження в таємниці самого факту передачі.
Звичайно ж, ніхто не забороняє поєднувати криптографічні та стеганографічні методи. Більше того, практично так і роблять, але наше завдання розібратися з основами. Якщо уважно вивчити статтю з Вікіпедії, можна дізнатися, що алгоритми стеганографії фігурує т.зв. контейнер та повідомлення. Контейнер – це будь-яка інформація, яка допомагає приховати наше секретне повідомлення.
У нашому випадку контейнером виступатиме картинка у форматі BMP. Спочатку розглянемо структуру цього файла. Файл умовно можна розбити на чотири частини: заголовок файлу, заголовок зображення, палітру і саме зображення. Для наших цілей треба знати лише те, що записано у заголовку.
Перші два байти заголовка - це сигнатура BM, далі в подвійному слові записаний розмір файлу в байтах, наступні 4 байти зарезервовані і повинні містити нулі і, нарешті, ще в одному подвійному слові записано зсув від початку файлу, до власне байтів зображення. У 24-бітовому bmp-файлі кожен піксел кодується трьома байтами BGR.
Тепер ми знаємо, як дістатися зображення, залишилося зрозуміти, як туди можна записати необхідну нам інформацію. Для цього нам і знадобиться метод LSB. Суть методу полягає в наступному: ми замінюємо молодші біти в байтах, які відповідають за кодування кольору. Припустимо, якщо черговий байт нашого секретного повідомлення - 11001011, а байти в зображенні - 11101100 01001110 01111100 0101100111 ..., то кодування буде виглядати так. Ми розіб'ємо байт секретного повідомлення на 4 двобітові частини: 11, 00, 10, 11 і замінимо отриманими фрагментами молодші біти зображення: …11101111 01001100 01111110 0101100111. Така заміна у випадку не помітна людському оку. Більше того, багато старих пристроїв виводу навіть не зможуть відобразити такі незначні зміни.
Зрозуміло, що можна міняти не лише 2 молодших біти, а й будь-яку їх кількість. Тут є така закономірність: що більше біт ми змінюємо, то більший обсяг інформації ми можемо сховати, і більші перешкоди у вихідному зображенні це викличе. Для прикладу ось вам два зображення:
При всьому бажанні я так і не зумів побачити різниці між ними, проте в другому зображенні за допомогою описаного методу захована поема Льюїса Керолла «Полювання на Снарка». Якщо ви дочитали до цього моменту, то вам, напевно, цікаво дізнатися і про реалізацію. Вона досить проста, але відразу попереджу, що зроблено все на 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