NÀr vi pratar om steganografi förestÀller sig mÀnniskor terrorister, pedofiler, spioner, ja, i bÀsta fall kryptoanarkister och andra forskare. Och verkligen, vem annars kan behöva det? dölja nÄgot frÄn yttre ögon? Vilken nytta kan detta egentligen vara för den vanliga personen?
Det visar sig att det finns viss nytta. DÀrför kommer vi idag att komprimera data med hjÀlp av steganografimetoder. I slutet kan lÀsaren till och med anvÀnda sina ovÀrderliga JPEG-arkiv för att öka mÀngden ledigt utrymme pÄ filsystemet.

Vad?
Om lÀsaren kommer ihÄg, sÄ Àr steganografi sÄdana konstiga algoritmer som gör det möjligt att dölja nÀrvaron av en information inuti en annan. Med enklare ord: bild + fil == ungefÀr samma bild, men inte helt (istÀllet för bilder kan det vara vad som helst, men det Àr oftast tydligare pÄ dem). Samtidigt ska det inte finnas nÄgot enkelt sÀtt att avgöra om det finns nÄgot inuti eller inte.
Men om man inte kan skilja det ena frÄn det andra, finns det dÄ nÄgon skillnad överhuvudtaget? Ur en konsuments eller anvÀndares perspektiv spelar den matematiska noggrannheten (representerad av en specifik mÀngd bitar) ingen roll, bara det som uppfattas av dem.
Till exempel, lÄt oss titta pÄ tre bilder av en söt hund:
Akta dig, JPEG!

Trots den enorma storleksskillnaden Àr det fÄ som skulle vÀlja den tredje versionen. à andra sidan Àr skillnaden mellan de första tvÄ bilderna inte sÄ mÀrkbar, och mÀngden information i dem (enligt min Äsikt) kan likstÀllas.
SjÀlva den hÀr principen Àr redan gammal och har lÀnge utnyttjats av metoder för informationskomprimering med förlust. Men att bryta ner Àr inte att bygga, vi Àr intresserade av den mer avancerade sidan av frÄgan. Kan man integrera ytterligare information av storleken N i en fil sÄ att dess storlek ökar med M < N, och Àndringarna inte Àr mÀrkbara för anvÀndaren?
SjÀlvklart gÄr det. Men det Àr vÀrt att göra ett par förtydliganden direkt:
- För det första mÄste metoden vara universell och ge positiva resultat med de flesta indata. Det vill sÀga, i genomsnitt, för godtyckliga ingÄngar, ska den faktiska mÀngden lagrad information minska. "I genomsnitt" innebÀr att motsatta fall kan förekomma, men de bör inte dominera.
- För det andra bör den komprimerade behÄllarens storlek innan införandet av information vara större Àn den komprimerade motsvarigheten. Att bara införa en mÀngd bitar i BMP-bilder med LSB-metoden Àr inte steganografisk kompression; eftersom den originala bilden, nÀr den har körts genom nÄgon DEFLATE, troligtvis blir mÀrkbart mindre.
- För det tredje bör resultaten jÀmföras med redan komprimerade data som anvÀnder klassiska metoder. Detta gör att man kan ta bort den potentiella effekten av deras redundans och genomföra en mer effektiv kompression i allmÀnhet.
Var?
AnvÀndning av steganografi innebÀr att vi förutom den information som ska komprimeras ocksÄ behöver behÄllare dÀr den ska integreras. Den maximala mÀngden inbÀddad information beror till stor del pÄ specifika egenskaper, men ökar betydligt med antalet. DÀrför bör formatet för behÄllarna vara vanligt förekommande för att anvÀndaren ska ha ett tillrÀckligt antal för att fÄ nÄgon nytta av "komprimerings"-processen.
I det hÀr sammanhanget blir grafiska, ljud- och video-filer bra kandidater. Men pÄ grund av mÄngfalden av olika format, codecs och sÄ vidare, finns det i praktiken inte sÄ mÄnga alternativ att vÀlja mellan.
Med allt detta i Ätanke har jag valt JPEG. Det finns praktiskt taget överallt och anvÀnds brett bÄde för personligt bruk och affÀrsmÄl, och Àr nÀstan de facto-formatet för de flesta bilder.

NÌ¶Ă€Ì¶r̶ ̶?̶ Hur?
NÀsta följer omkring- och tekniska scheman och beskrivningar utan större förklaringar, sÄ de som Àr intresserade kan hoppa över dem och gÄ vidare till avsnittet "Högteknologi".
Gemensamma drag
För att kunna integrera data nÄgonstans mÄste man först bestÀmma var. Det kan finnas hur mÄnga olika bilder som helst i filsystemet, dÀr anvÀndaren kan vilja anvÀnda endast vissa. Den mÀngd önskade behÄllare kallar vi ett bibliotek.
Den bildas i tvÄ fall: före komprimering och före uppackning. I det första fallet kan man enkelt anvÀnda en uppsÀttning namn (eller bÀttre, ett reguljÀrt uttryck för dem) för filer, men i det andra krÀvs nÄgot mer tillförlitligt: anvÀndaren kan kopiera och flytta dem inom filsystemet, vilket hindrar korrekt identifiering. DÀrför behövs det att lagra deras hash-vÀrden (md5 rÀcker) efter att alla modifieringar har gjorts.
Inledande sökningen med reguljÀra uttryck Àr meningslös att göra över hela filsystemet, det rÀcker att ange en viss rotkatalog. Dit kommer en speciell arkivfil att sparas, dÀr dessa hash-vÀrden finns tillsammans med annan meta-information, som behövs för den efterföljande ÄterstÀllningen av den komprimerade informationen.
Allt detta gÀller lika mycket för vilken implementering av vilken algoritm för steganografisk datakomprimering som helst. SjÀlva processerna för komprimering och ÄterstÀllning av data kan kallas paketering och uppackning.
F5
Nu nÀr det Àr klart vad vi gör och varför, ÄterstÄr det att beskriva sjÀlva algoritmen för att nÄ mÄlet. LÄt oss minnas processen för att koda en JPEG-fil (tack till Nationalbibliotekets Wiki):

Medan vi tittar pÄ den, Àr det bÀttre att omedelbart göra nÄgra observationer:
- Storleken pÄ en JPEG-fil kan anses vara optimal, utan att ens försöka komprimera den med nÄgot program som WinRAR;
- Det Àr endast den lagrade informationen (den som Àr resultatet av diskret kosinustransformering, DCT) som kan modifieras för att sÀkerstÀlla nÄgon rimlig prestanda.
- För att inte förlora data i mÀrkbara industriella skala, krÀvs det att göra minimala modifieringar i varje enskild bild;
För sÄdana villkor passar en hel familj av algoritmer, som kan ses . Den mest avancerade av dem Àr algoritmen av Andreas Westfeld, som arbetar med DCT-koefficienter för ljuskomponenten (mÀnniskans öga Àr minst kÀnsligt för just dessa förÀndringar). Dess allmÀnna schema nÀr den arbetar med en befintlig JPEG-fil visas enligt följande schema:

Block F5 anvÀnder en avancerad inbÀddningsmetodik baserad pÄ matris kodning. Mer om det och sjÀlva algoritmen kan lÀsaren bekanta sig med via lÀnken ovan, men vi Àr först och frÀmst intresserade av det faktum att man kan göra fÀrre förÀndringar vid inbÀddning av samma mÀngd information ju större storleken pÄ den anvÀnda containern Àr, och för att genomföra sjÀlva algoritmen krÀvs endast enkla operationer av (de)kodning av Huffman och RLE.
SjÀlva Àndringarna görs pÄ heltalskoefficienterna och handlar om att minska deras absoluta vÀrden med en enhet, vilket gör att F5 kan anvÀndas för datakomprimering. Det beror pÄ att en koefficient med minskat absolutvÀrde troligen kommer att ta fÀrre bitar efter att ha genomfört Huffman-kodning pÄ grund av den statistiska fördelningen av vÀrden i JPEG.

I hÀndelse av att en nolla bildas (s.k. förkortning), kommer mÀngden lagrad information att minska med dess storlek, eftersom den tidigare sjÀlvstÀndiga koefficienten blir en del av den kodade RLE-sekvensen av nollor:

Modifieringar
Dataskydd och komprimering Àr ortogonala uppgifter, dÀrför kan man bortse frÄn den hemliga lösenordspermutationerna frÄn den ursprungliga algoritmen. Dessutom behöver vi veta exakt hur man extraherar data, sÄ all nödvÀndig information för detta (vilka containrar som anvÀnts, i vilken ordning, osv.) mÄste registreras i en separat fil och vara öppen för fri lÀsning av komprimeraren.
Den ursprungliga algoritmen Àr avsedd för överföring av hemliga meddelanden, sÄ den arbetar Ät gÄngen endast med en container, och förutsÀtter att anvÀndaren sjÀlv kommer att dela upp den i delar vid behov, om det överhuvudtaget skulle uppstÄ. Dessutom, vid oberoende inbÀddning i varje container, kommer man pÄ förhand att behöva veta hur mÄnga bitar data som ska placeras i varje. DÀrför bör koefficienterna för varje element i biblioteket sammanfogas till en abstrakt stor och arbetas med enligt den ursprungliga algoritmen.
Eftersom den ursprungliga F5 tillÄter anvÀndning av upp till 12% av behÄllarens storlek, kommer en sÄdan modifiering ocksÄ att öka den maximala kapaciteten: "upp till 12%" av storleken pÄ hela biblioteket Àr större Àn eller lika med summan av "upp till 12%" av varje av dess element.
Den kodifierade allmÀnna schemat ser ut som följer:

SjÀlva algoritmen
Nu Àr det dags att beskriva sjÀlva algoritmen frÄn början till slut, sÄ att lÀsaren inte hÄlls i mörkret:
- AnvÀndaren definierar de binÀrt komprimerade data M och biblioteket L med hjÀlp av ett reguljÀrt uttryck och roten av sökvÀgen;
- I den ordning som elementen i biblioteket förekommer pÄ filsystemet bildar de MC:
- FrÄn filens data avkodas en serie koefficienter C;
- MC <- MC | C;
- Parametern k bestÀms utifrÄn det skrÀmmande olikheten:
|M| * 8 / (count_full(MC) + count_ones(MC) * k_rate(k)) < k / ((1 << k) - 1); - NĂ€sta tas
n = (1 << k) - 1de lÀgsta bitarna av de icke-noll elementen frÄn MC och skrivs in ia:- Den magiska hash-funktionen
f, som avbildar ett n-bitsordatill ett k-bitsords; - Om
s == 0, sÄ Àndra ingenting och algoritmen gÄr vidare till nÀsta koefficienter; - Minska det absoluta vÀrdet av koefficienten som ansvarar för
s-e bit i ordeta; - Om minskningen resulterade i att koefficienten blev 0, upprepa steget frÄn början;
- Den magiska hash-funktionen
- Alla koefficienter kodas med RLE och Huffman, skrivs in i de ursprungliga filerna;
- I arkivfilen skrivs parametern k;
- FrÄn varje fil L, i den ordning de förekommer frÄn början, berÀknas MD5-hash och skrivs in i arkivfilen.
Högteknologi
Den naiva formen av algoritmen och implementeringen pÄ andra hög-nivÄ (sÀrskilt, med skrÀpsamling) sprÄk skulle ge förfÀrlig prestanda, sÄ alla dessa svÄrigheter genomförde jag i rent C och genomförde en rad optimeringar bÄde för körningshastighet och för minne (du kan inte förestÀlla dig hur mycket dessa bilder vÀger utan komprimering Àven till DCT). Men sÄ, initialt lÀmnade körningshastigheten mycket att önska, sÄ jag kommer inte att beskriva hela processen och de anvÀnda metoderna.
Plattformsoberoende har uppnÄtts genom att anvÀnda en kombination av biblioteken libjpeg, pcre och tinydir, vilket jag tackar dem för. Som standard kompileras allt med en vanlig make, sÄ Windows-anvÀndare mÄste installera nÄgot Cygwin, eller ordna med Visual Studio och biblioteken sjÀlva.
Implementeringen Àr tillgÀnglig som ett kommandoradsverktyg och ett bibliotek. De som vill veta mer om anvÀndningen av det senare kan lÀsa i readme-filen i repot pÄ GitHub, vars lÀnk jag kommer att bifoga i slutet av inlÀgget. LÄt oss nu gÄ vidare till beskrivningen och demonstration av arbetet.
Hur man anvÀnder?
Med försiktighet. AnvÀnda bilder kan flyttas, döpas om och kopieras som man önskar. Men man ska vara mycket försiktig och inte Àndra deras innehÄll. Att Àndra en enda bit kommer att leda till att hash-vÀrdet bryts och informationen blir omöjlig att ÄterstÀlla.
LÄt oss sÀga att vi efter kompileringen fÄtt den körbara filen f5ar. Vi kan analysera storleken pÄ biblioteket för att berÀkna möjligheterna till dess anvÀndning med hjÀlp av flaggan -a: ./f5ar -a [sökmappe] [Perl-kompatibel reguljÀr uttryck]. Packning görs med kommandot ./f5ar -p [sökmappe] [Perl-kompatibel reguljÀr uttryck] [packad fil] [arkivnamn], och uppackning med hjÀlp av ./f5ar -u [arkivfil] [namn pÄ ÄterstÀlld fil].
Demonstration av arbetet
För att visa metodens effektivitet har jag laddat upp en samling av 225 helt gratis hundbilder frÄn tjÀnsten . Varje bild har en nÄgot högre kvalitet Àn vanliga anvÀndarbilder, men ÀndÄ. Varje bild har transkoderats med hjÀlp av libjpeg för att eliminera pÄverkan av bibliotekets kodningsspecifika attribut pÄ den totala storleken. För att illustrera det sÀmsta exemplet pÄ komprimerbara data har en slumpmÀssig 36-megabytes (lite mer Àn 5% av den totala storleken) jÀmnt fördelad fil genererats med dd.
Testprocessen Àr ganska enkel:
$ ls
binary_data dogs f5ar
$ du -sh dogs/
633M dogs/
$ du -h binary_data
36M binary_data
$ ./f5ar -p dogs/ .*jpg binary_data dogs.f5ar
LĂ€ser komprimerad fil... ok
Initierar arkivet... ok
Analyserar bibliotekskapacitet... klart pÄ 16.8s
UpptÀckte nÄgot garanterad kapacitet pÄ 48439359 byte
UpptÀckte möjlig kapacitet pÄ upp till 102618787 byte
Komprimerar... klart pÄ 32.6s
Sparar arkivet... ok
$ ./f5ar -u dogs/dogs.f5ar unpacked
Initierar arkivet... ok
LĂ€ser arkivfilen... ok
Fyller arkivet med filer... klart pÄ 1.2s
Dekomprimerar... klart pÄ 17.5s
Skriver utvunna data... ok
$ sha1sum binary_data unpacked
ba7ade4bc77881ab463121e77bbd4d41ee181ae9 binary_data
ba7ade4bc77881ab463121e77bbd4d41ee181ae9 unpacked
$ du -sh dogs/
563M dogs/Eller en skÀrmdump för entusiaster

Som det framgÄr har vi utgÄtt frÄn ursprungliga 633 + 36 == 669 megabyte data pÄ hÄrddisken och kommit fram till en mer tilltalande storlek av 563, vilket ger oss en kompressionsfaktor pÄ ~1,188. Denna radikala skillnad förklaras av de extremt smÄ förluster som liknar dem som uppnÄs vid JPEG-filer optimering med klassiska metoder (som tinyjpg). Naturligtvis, nÀr steganografisk komprimering anvÀnds, "förloras" inte informationen bara, utan anvÀnds för att koda andra data. Dessutom Àr antalet "optimerade" koefficienter genom att anvÀnda F5 mycket mindre Àn vid traditionell optimering.
Oavsett vilka modifieringar som görs, Àr de helt osynliga för ögat. Under spoilern nedan kan lÀsaren bedöma skillnaden bÄde visuellt och genom att subtrahera vÀrdena för den modifierade komponenten frÄn originalet (ju mer dÀmpad fÀrgen Àr, desto mindre Àr skillnaden):
LÀnkar till bilder som inte fick plats pÄ habrastorage
Original â
Modifierad â
Skillnad â
Avslutande
Jag hoppas att jag har lyckats övertyga lÀsaren om att sÄdana metoder Àr möjliga och vÀrda att utforska. Det kan dock verka mycket enklare att köpa en hÄrddisk eller en extra kanal (för nÀtöverföring) Àn att försöka spara pÄ detta sÀtt. à ena sidan Àr det faktiskt sÄ, extensiv utveckling Àr ofta enklare och mer pÄlitlig. Men Ä andra sidan bör vi inte glömma den intensiva utvecklingen. Det finns trots allt inga garantier för att man nÀsta dag kan gÄ till affÀren och köpa en ny hÄrddisk pÄ tusen terabyte, men att anvÀnda de som redan finns hemma kan man alltid göra.
->
KĂ€lla: habr.com
