For længe siden skrev jeg mit . Det indlæg var dedikeret til et ret interessant problem, nemlig steganografi. Selvfølgelig kan løsningen, der blev foreslået i det gamle emne, ikke kaldes steganografi i ordets sande forstand. Det er blot et spil med filformater, men det er trods alt et ret interessant spil.
I dag vil vi forsøge at grave lidt dybere og se på LSB-algoritmen. Hvis du er interesseret, er du velkommen til at følge med. (Under indlægget er trafik: omkring en megabyte.)
Først og fremmest er det nødvendigt at lave en lille introduktion. Det er velkendt, at formålet med kryptografi er at gøre det umuligt at læse hemmelig information. Selvfølgelig har kryptografi sine anvendelsesområder, men der findes også en anden tilgang til databeskyttelse. Man kan vælge ikke at kryptere informationen, men at få det til at se ud som om, vi ikke har den. Det er netop til dette, at steganografi er opfundet. Wikipedia forsikrer os om, at "steganografi (fra græsk στεγανοσ — skjult og γραφω — jeg skriver, bogstaveligt talt 'hemmelig skrift') — det er videnskaben om skjult transmission af information ved at holde selve faktumet om transmissionen hemmeligt.
Selvfølgelig er der ingen, der forbyder at kombinere kryptografiske og steganografiske metoder. Desuden bliver dette ofte gjort i praksis, men vores opgave er at forstå det grundlæggende. Hvis man nøje studerer artiklen fra Wikipedia, kan man lære, at i steganografiske algoritmer fremgår den såkaldte beholder og besked. Beholderen er hvilken som helst information, der hjælper med at skjule vores hemmelige besked.
I vores tilfælde vil beholderen være et billede i BMP-format. Lad os først se på strukturen af denne fil. Filen kan groft opdeles i 4 dele: filheader, billedeheader, palet og selve billedet. Til vores formål skal vi kun kende det, der er skrevet i headeren.
De første to bytes i headeren er signaturen BM, derefter er filstørrelsen i bytes angivet i et dobbelt ord, de næste 4 bytes er reserveret og skal indeholde nuller, og endelig er det offset fra begyndelsen af filen til de faktiske billedbytes angivet i endnu et dobbelt ord. I en 24-bit bmp-fil kodes hver pixel med tre bytes BGR.
Nu ved vi, hvordan vi når frem til billedet; vi skal nu forstå, hvordan vi kan indtaste den nødvendige information. Til dette vil vi bruge LSB-metoden. Metodens essens er som følger: vi erstatter de mindste bits i bytes, der koder farven. Antag, at den næste byte af vores hemmelige meddelelse er 11001011, og bytes i billedet er…11101100 01001110 01111100 0101100111…, så vil kodningen se sådan ud. Vi opdeler byte af den hemmelige meddelelse i 4 to-bits dele: 11, 00, 10, 11, og erstatter de mindste bits i billedet med de opnåede fragmenter: …11101111 01001100 01111110 0101100111…. Sådan en erstatning er generelt usynlig for det menneskelige øje. Desuden vil mange gamle udstyr ikke engang kunne vise sådanne ubetydelige ændringer.
Det er klart, at man ikke kun kan ændre de 2 mindste bits, men enhver mængde af dem. Der er en følgelig regel: jo flere bits vi ændrer, desto større mængde information kan vi skjule, og jo større forstyrrelser vil dette forårsage i det oprindelige billede. Her er to billeder som eksempel:


På trods af mine bedste intentioner kunne jeg ikke se forskel imellem dem, og alligevel er der i det andet billede skjult Lewis Carrolls digt 'Jagten på Snark' ved hjælp af den beskrevne metode. Hvis du er nået til dette punkt, så er du sikkert interesseret i implementeringen. Den er ret simpel, men jeg advarer straks om, at det hele er gjort i Delphi. Der er to grunde til det: 1. Jeg mener, Delphi er et godt, anvendeligt sprog; 2. Dette program blev skabt under forberedelserne til et kursus om grundlæggende maskinsyn, og de studerende, jeg underviser, kender kun Delphi. For dem, der ikke er bekendt med syntaksen, skal jeg nævne en ting: shl x – bitvis venstreforskydning med x, shr x – bitvis højreforskydning med x.
Lad os antage, at vi skriver tekst ind i en container, der gemmes i en streng, og erstatter de to mindste bytes:
Kode til skrivning:
for i:=1 to length(str) do
begin
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;
kode til læsning:
for i:=1 to MsgSize do
begin
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;
Og for de helt dovne – .
Tak.
Kilde: habr.com
