Ukrywanie informacji w kotach

24

Jesteś tajnym agentem próbującym komunikować się ze swoją ojczyzną. Oczywiście informacje muszą być ukryte, aby nikt nie podsłuchiwał Twojej wiadomości. Co byłoby bardziej odpowiednie niż kot? Wszyscy uwielbiają śmieszne zdjęcia kotów [potrzebne źródło] , więc nie będą podejrzewać ukrytych tam tajnych informacji!


Zainspirowany algorytmem, którego gra Monako używa do zapisywania informacji o poziomie wspólnych poziomów , Twoim zadaniem jest napisanie programu, który zakodował informacje w najmniej znaczącym kolorze kolorów obrazu.

Format kodowania:

  • Pierwsze 24 bity określają długość pozostałego zakodowanego ciągu bajtów w bitach
  • Obraz jest odczytywany od lewej do prawej i od góry do dołu, oczywiście zaczynając od lewego górnego piksela
  • Kanały są odczytywane z czerwonego na zielony na niebieski
  • Odczytywany jest najmniej znaczący bit z każdego kanału
  • Bity są zapisywane w kolejności Big Endian

Zasady:

  • Twój program wymaga jednego ciągu bajtów do zakodowania i pojedynczej nazwy pliku obrazu dla obrazu podstawowego
  • Powstały obraz musi być wyprowadzony jako plik PNG o prawdziwym kolorze
  • Możesz używać We / Wy w dowolnej formie (ARGV, STDIN, STDOUT, zapis / odczyt z pliku), o ile podasz sposób korzystania z programu
  • Musisz wybrać losowy obraz śmiesznego kota i zakodować w nim swój program, aby pokazać, że Twój program działa
  • Możesz założyć, że podano tylko prawidłowe dane wejściowe, jeśli ilość bitów nie jest wystarczająca, obraz nie jest w prawdziwym formacie kolorów, obraz nie istnieje lub podobne problemy możesz zrobić, co chcesz
  • Możesz założyć, że dostarczony obraz nie zawiera żadnego kanału alfa
  • Długość jest liczona w bajtach UTF-8 bez BOM

Możesz użyć tego skryptu PHP do przetestowania rozwiązania, podając nazwę pliku PNG jako pierwszy argument wiersza poleceń:

<?php
if ($argc === 1) die('Provide the filename of the PNG to read from');
$imageSize = @getimagesize($argv[1]);

if ($imageSize === false) die('Not a PNG file');
list($width, $height) = $imageSize;

$image = imagecreatefrompng($argv[1]);
$read = 0;
$bits = '';
for ($y = 0; $y < $height; $y++) {
    for ($x = 0; $x < $width; $x++) {
        $colorAt = imagecolorat($image, $x, $y);
        $red = ($colorAt >> 16) & 0xFF;
        $green = ($colorAt >> 8) & 0xFF;
        $blue = ($colorAt >> 0) & 0xFF;

        $bits .= ($red & 1).($green & 1).($blue & 1);
        $read += 3;
        if ($read == 24) {
            $length = (int) bindec($bits);
            $bits = '';
        }
        else if ($read > 24 && ($read - 24) > $length) {
            $bits = substr($bits, 0, $length);
            break 2;
        }
    }
}
if (strlen($bits) !== $length) die('Not enough bits read to fulfill the length');
$parts = str_split($bits, 8);
foreach ($parts as $part) {
    echo chr(bindec($part));
}
TimWolla
źródło
Twoja specyfikacja mówi: „Twój program przyjmuje pojedynczy obraz jako bazę”. W Mathematica obraz jest tak naprawdę wyrażeniem jak wszystko inne, więc technicznie ta specyfikacja pozwoliłaby mi na wczytywanie pliku poza kodem, który wykonuje obliczenia (z parametrem wejściowym będącym rzeczywistym obrazem zamiast nazwy pliku obrazu) . Jeśli nie chcesz takich rzeczy, możesz określić, że program musi pobierać nazwę pliku obrazu jako dane wejściowe.
Martin Ender,
4
ME helpimtrappedinacatfactory OW
TheDoctor
Ponadto, czy bity nieużywane do kodowania muszą pozostać nietknięte? Czy możemy ustawić je na cokolwiek chcemy (ponieważ to tak naprawdę nie wpłynie na jakość obrazu i nie ma znaczenia przy dekodowaniu)?
Martin Ender,
1
Czy mogę użyć nie wbudowanej biblioteki, aby załadować i zapisać plik png, np. PIL w Pythonie?
Claudiu,
1
@TimWolla Od kota? Trzymaj go w pomieszczeniu i monitoruj kuwetę. Ze zdjęcia? Jeśli zrobisz zdjęcie rentgenowskie o wystarczająco wysokiej rozdzielczości, możesz zobaczyć stan poszczególnych tranzystorów w układzie flash. Jestem pewien, że to musi być najskuteczniejsza metoda przekazywania tajnych informacji, jaką kiedykolwiek wymyślono, chociaż kot może mieć inne pomysły.
Sonic Atom

Odpowiedzi:

3

Perl i ImageMagick (Linux), 198 190

Edycja: Zbiegiem okoliczności wcześniej testowałem na komputerze z zainstalowaną wersją ImageMagick w wersji Q8 (8 bitów). „Standardowa” wersja Q16 wymaga wyraźnego podania -depth 8w wierszu polecenia. W systemie Linux identifywynik również wymaga usunięcia znaku nowej linii. Oba czynniki prowadzą do zwiększenia rozmiaru kodu, dlatego w odpowiedzi zamieszczam wersję Linuksa (prawdopodobnie także Maca) z zastosowanymi poprawkami, a także z usuniętymi elementami tylko dla systemu Windows (konwersja cr-lf, binarna vs tekst itp.). Wersja przenośna (nieco dłuższa) jest opublikowana pod koniec.

Z nowymi liniami dla czytelności:

$/=$1;
<>=~/\n/;
$_=`identify -format %wx%h $\``;
chop;
open O,"|convert -size $_ -depth 8 rgb: $`.png";
$_=`convert $\` rgb:`;
print O$_&y//\376/cr|unpack('B*',pack(NX,2048*length$').$')&y//\1/cr

Biegać:

perl cat.pl

Czyta ze STDIN, nazwa pliku obrazu w pierwszym wierszu, następuje komunikat „tajny”, zakończony ctrl-D. Nazwa pliku wyjściowego jest oryginalna z .pngdołączonym - niezbyt ładnym, jest zrobiona tylko dla zwięzłości.

Oto zdjęcie, w którym ukryte są bardzo tajne informacje:

wprowadź opis zdjęcia tutaj

I z pewnymi komentarzami:

# Undef input record separator, because we'll slurp input.

$/=$1;

# Read from STDIN, separate first line. 
# $` (prematch) contains image file name,
# $' (postmatch) - text to encode.

<>=~/\n/;

# Get IM's 'identify' output, width and height of the image. 
# Note: we don't have to separate them, \d+x\d+ string will 
# do just fine.

$_=`identify -format %wx%h $\``;
chop;

# Open output pipe - IM's 'convert' command that takes raw RGB data from 
# STDIN and writes output to PNG file. Interpolated into this command
# line is previous IM's 'identify' result. Convert wants '-size' command
# option in case of raw RGB input - for obvious reason.

open O,"|convert -size $_ -depth 8 rgb: $`.png";

# Get raw RGB data into $_.

$_=`convert $\` rgb:`;

# Last line does all the job. 

# y//\376/cr --- create string same length as $_, fill with 0xFE
# $_&y//\376/cr --- zero least significant bit for all image bytes (1).
# pack(NX,2048*length$') --- multiply by 8 (bytes to bits count) and 
#         shift left by 8 (because we'll pack long integer into 3 bytes) -
#         i.e. multiply by 2048.
# unpack('B*',pack(NX,2048*length$').$') ---- append 'secret text' to 
#       its encoded length and convert to 'binary' (consisting of 1 and 
#       0 characters) string.
# ... &y//\1/cr --- equivalent of tr/01/\0\1/. We don't have to worry 
#       that raw RGB length is larger than encoded text length, because
#       '&' truncates longer string argument (2).
# Then bitwise-'or' (1) and (2) strings.

print O$_&y//\376/cr|unpack('B*',pack(NX,2048*length$').$')&y//\1/cr

Dalej jest wersja przenośna, działa zarówno na systemie Windows (użyj ctrl-Zdo zakończenia wprowadzania danych), jak i na Linuksie, liczba bajtów wynosi 244.

$_=do{local$/;<>};
/\n/;
$_=`identify -format %wx%h $\``;
chomp;
open I,'-|:raw',"convert $` rgb:";
open O,'|-:raw',"convert -size $_ -depth 8 rgb: $`.png";
$_=do{local$/;<I>};
print O$_&y//\376/cr|unpack('B*',pack(NX,2048*length$').$')&y//\1/cr
użytkownik 2846289
źródło
10

Mathematica, 255 234 206 bajtów

Widziałem tak wiele 255sekund podczas testowania tego, jestem niesłusznie szczęśliwy z powodu rozmiaru kodu. :) A potem moja ambicja, aby zagrać w golfa jeszcze bardziej, zwróciła moją uwagę ...

f=(j=ImageData[Import@#2,t="Byte"];k=(d=IntegerDigits)[j,2,8]~Flatten~2;n=1;(k[[n++,-1]]=#)&/@d[Length@#,2,24]~Join~#&[Join@@d[ToCharacterCode@#,2,8]];ArrayReshape[#~FromDigits~2&/@k,Dimensions@j]~Image~t)&

Z technicznego punktu widzenia jest to funkcja, a nie „program”, ale z drugiej strony jest to sposób, w jaki piszesz „programy” w Mathematica, jeśli ta koncepcja jest tam nawet ważna. Nazwij to jak

f["my secret", "fully/qualified/cat.png"]

Zwróci rzeczywiste wyrażenie obrazu (ponieważ jest to najbardziej naturalny sposób na zwrócenie obrazu w Mathematica), więc jeśli chcesz plik, musisz go wyeksportować:

Export["output-cat.png", f["my secret", "input-cat.png"]]

Oto wymagany przykład:

wprowadź opis zdjęcia tutaj

Chciałbym pokazać tutaj zdekodowaną wiadomość, ale nie pasuje ... więc uruchom ją przez dekoder OP. ;)

Przy okazji, mogę sprawić, że będzie działać z sekretami UTF-8 za zaledwie 7 bajtów (zmiana ToCharacterCode@#na #~ToCharacterCode~"utf8").

Nieskluczony kod:

f[secret_, filename_] := (
  bits = Join @@ IntegerDigits[ToCharacterCode[secret], 2, 8];
  bits = Join[d[Length @ bits, 2, 24], bits];
  data = ImageData[Import@#2, "Byte"];
  dims = Dimensions@data;
  data = Flatten[IntegerDigits[data, 2, 8], 2];
  m = n = 1;
  While[m <= Length @ bits,
    data[[n++, -1]] = bits[[m++]]
  ];
  Image[ArrayReshape[FromDigits[#, 2] & /@ data, dims], "Byte"]
)
Martin Ender
źródło
„Chciałbym pokazać tutaj zdekodowaną wiadomość, ale nie pasuje ... więc uruchom ją przez dekoder OP;;)” - zrobiłem to i daje mi „????????? ??? +++++++ ?? ++++++++++++++++++++ ================= ~ === ~ ============ ~ :::: ~~~~~ = [... dla 9773 znaków] "
TessellatingHeckler
1
@TessellatingHeckler, to prawda. wypróbuj czcionkę o stałej szerokości i pamiętaj, że są tam nowe wiersze w stylu UNIX (np. wypróbuj terminal lub program PowerShell o szerokości co najmniej 180 znaków lub jeśli uruchamiasz go jako skrypt internetowy w przeglądarce, następnie zobacz źródło);)
Martin Ender
2
Widzę! Very meta. Pomaga mi również w wersji KiTTY PuTTY 😸
TessellatingHeckler
5

PHP, 530 bajtów

<?php function p($i,$j){return str_pad(decbin($i),$j,0,0);}extract(getopt("i:o:t:"));$t=file_get_contents($t);$_=imagecreatefrompng($i);list($w,$h)=getimagesize($i);$b="";for($i=0;$i<strlen($t);)$b.=p(ord($t[$i++]),8);$l=strlen($b);$b=p($l,24).$b;$l+=24;for($i=$x=$y=0;$y<$h;$y++){for(;$x<$w;){$C=imagecolorat($_,$x,$y);$R=($C>>16)&0xff;$G=($C>>8)&0xff;$B=$C&0xff;$i<$l&&$R=$b[$i++]|$R&~1;$i<$l&&$G=$b[$i++]|$G&~1;$i<$l&&$B=$b[$i++]|$B&~1;imagesetpixel($_,$x++,$y,imagecolorallocate($_,$R,$G,$B));if($i>$l){imagepng($_,$o);die;}}}

Biegnij jak php 25443.php -i<input image> -o<output image> -t<file to hide>.

A oto przykładowy obraz.

http://i.imgur.com/hevnrbm.png

Nieskluczony kod jest ukryty w przykładowym obrazie. Testowane z dekoderem OP. Przepraszam za nie śmieszne zdjęcie kota.

Przekąska
źródło
1
Dodaj nieoznaczony kod do swojej odpowiedzi.
AL
1
Możesz skrócić 0xffdo 255.
TimWolla,
Można zapisać 4 bajty, jeśli zakładamy krótkie tagi: <?function.
nyuszika7h