För länge sedan skrev jag mitt . Det inlägget handlade om ett ganska intressant problem, nämligen steganografi. Självklart kan man inte kalla lösningen som presenterades i det gamla inlägget för steganografi i ordets sanna mening. Det är bara ett spel med filformat, men ändå en ganska intressant lek.
I dag ska vi försöka gräva lite djupare och titta på LSB-algoritmen. Om du är intresserad, varsågod att följa med. (Under cat: ungefär en megabyte trafik.)
Först måste vi göra en kort introduktion. Det är allmänt känt att syftet med kryptografi är att göra det omöjligt att läsa hemlig information. Naturligtvis har kryptografi sina tillämpningsområden, men det finns också en annan metod för att skydda data. Man behöver inte kryptera informationen, utan kan istället låtsas att vi inte har den. Det är just därför steganografi har uppfunnits. Wikipedia försäkrar oss att 'steganografi (från grekiska στεγανοσ — dolda och γραφω — skriva, bokstavligen "hemligt skrivande") är vetenskapen om att dölja överföring av information genom att hålla hemligt själva faktum av överföringen.'
Självklart är ingen emot att kombinera kryptografiska och steganografiska metoder. Faktum är att man i praktiken gör just detta, men vår uppgift är att förstå grunderna. Om man noggrant studerar artikeln på Wikipedia kan man lära sig att i steganografi-algoritmer förekommer begreppen container och meddelande. Containern är vilken information som helst som hjälper till att dölja vårt hemliga meddelande.
I vårt fall kommer containern att vara en bild i BMP-format. Först måste vi titta på strukturen av denna fil. Filer kan grovt delas in i fyra delar: filhuvud, bildhuvud, palett och själva bilden. För våra syften behöver vi bara veta vad som står i filhuvudet.
De två första bytes av filhuvudet är signaturen BM, därefter skrivs filstorleken i bytes i ett ord, följande 4 bytes är reserverade och ska innehålla nollor och slutligen står i ännu ett ord offset från filens början till själva bildbytes. I en 24-bitars bmp-fil kodas varje pixel med tre bytes BGR.
Nu vet vi hur man når bilden, det återstår att förstå hur vi kan skriva nödvändig information dit. För detta kommer metoden LSB till nytta. Metodens kärna går ut på att vi ersätter de lägsta bitarna i byte som ansvarar för färgkodning. Antag att det aktuella bytet i vårt hemliga meddelande är 11001011, och bytena i bilden är… 11101100 01001110 01111100 0101100111…, då kommer kodningen att se ut så här. Vi delar upp bytet i vårt hemliga meddelande i 4 tvåbitars delar: 11, 00, 10, 11, och ersätter de lägsta bitarna i bilden med dessa fragment: … 11101111 01001100 01111110 0101100111…. Sådan ersättning är för det mesta osynlig för det mänskliga ögat. Dessutom kan många gamla utdataenheter knappt visa sådana obetydliga förändringar.
Det är klart att vi kan ändra inte bara 2 lägsta bitar utan också vilket antal som helst. Här finns följande samband: ju fler bitar vi ändrar, desto mer information kan vi dölja, och desto större störningar kommer det att orsaka i den ursprungliga bilden. Här är två exempel på bilder:


Trots alla ansträngningar kunde jag inte se någon skillnad mellan dem, ändå har en dikt av Lewis Carroll, "Jakt på Snark", dolts i den andra bilden med hjälp av den beskrivna metoden. Om du har kommit så här långt, så är du säkert intresserad av implementeringen. Den är ganska enkel, men jag varnar att allt är gjort i Delphi. Anledningen till detta är två: 1. Jag anser att Delphi är ett bra och användbart språk; 2. Det här programmet kom till under förberedelserna för en kurs om grundläggande maskinsyn, och killarna som jag håller den kursen för kan fortfarande inget annat än Delphi. För dem som inte är bekanta med syntaxen bör jag förtydliga en sak: shl x – bitvis skiftning till vänster med x, shr x – bitvis skiftning till höger med x.
Vi antar att vi skriver text i en container, som lagras i en sträng och ersätter de lägsta två bitarna:
Kod för att skriva:
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;
kod för att läsa:
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;
Och för de som är riktigt lata - .
Tack.
Källa: habr.com
