Калісьці даўно я напісаў свой
Сёння мы паспрабуем капнуць крыху глыбей і разгледзім алгарытм LSB. Калі вам цікава, калі ласка пад кат. (Пад катам трафік: каля мегабайта.)
Перш за ўсё, неабходна зрабіць невялікі ўступ. Усім вядома, што прызначэнне крыптаграфіі - зрабіць немагчымым чытанне сакрэтнай інфармацыі. Зразумела, крыптаграфія мае свае вобласці ўжывання, але ёсць і іншы падыход да абароны дадзеных. Можна не шыфраваць інфармацыю, а зрабіць выгляд, што ў нас яе няма. Менавіта для гэтага і прыдумана стэганаграфія. Вікіпедыя запэўнівае нас што, «стеганаграфія (ад грэч. στεγανοσ — утоены і грэч. γραφω — пішу, літаральна «тайнапіс») — гэта навука аб утоенай перадачы інфармацыі шляхам захавання ў таямніцы самога факту перадачы.
Вядома ж, ніхто не забараняе сумяшчаць крыптаграфічныя і стэганаграфічныя метады. Больш за тое, на практыцы так і робяць, але нашая задача разабрацца з асновамі. Калі ўважліва вывучыць артыкул з Вікіпедыі, можна даведацца, што ў алгарытмах стэганаграфіі фігуруе т.зв. кантэйнер і паведамленне. Кантэйнер - гэта любая інфармацыя, якая дапамагае схаваць наша сакрэтнае паведамленне.
У нашым выпадку кантэйнерам будзе выступаць карцінка ў фармаце BMP. Для пачатку разгледзім структуру гэтага файла. Файл умоўна можна разбіць на 4 часткі: загаловак файла, загаловак выявы, палітру і сама выява. Для нашых мэт трэба ведаць толькі тое, што запісана ў загалоўку.
Першыя два байта загалоўка - гэта сігнатура 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