Nascondere le informazioni in Gatti


24

Sei un agente segreto che cerca di comunicare con la tua patria. Ovviamente le informazioni devono essere nascoste in modo che nessuno intercetta il messaggio. Cosa sarebbe più adatto di un gatto? Tutti adorano immagini divertenti di gatti [citazione necessaria] , quindi non sospetteranno che informazioni segrete si nascondano lì dentro!


Ispirato dall'algoritmo utilizzato dal gioco Monaco per salvare le informazioni sui livelli dei livelli condivisi , è compito tuo scrivere un programma che codifichi le informazioni nei bit meno significativi dei colori di un'immagine.

Formato di codifica:

  • I primi 24 bit determinano la lunghezza della stringa di byte codificata rimanente in bit
  • L'immagine viene letta da sinistra a destra e dall'alto verso il basso, ovviamente a partire dal pixel in alto a sinistra
  • I canali vengono letti dal rosso al verde al blu
  • Viene letto il bit meno significativo di ciascun canale
  • I bit vengono salvati nell'ordine di Big Endian

Regole:

  • Il programma richiede una singola stringa di byte da codificare e un singolo nome file di immagine per l'immagine di base
  • L'immagine risultante deve essere emessa come un file PNG a colori reali
  • È possibile utilizzare l'I / O in qualsiasi forma (ARGV, STDIN, STDOUT, scrivere / leggere da un file), purché si dichiari come utilizzare il programma
  • Devi scegliere un'immagine casuale di un gatto divertente e codificare il tuo programma in esso per mostrare che il tuo programma funziona
  • Puoi supporre che ti venga fornito un input valido, se la quantità di bit non è sufficiente, l'immagine non è nel formato di colore vero, l'immagine non esiste o problemi simili potresti fare quello che vuoi
  • Si può presumere che l'immagine fornita non contenga alcun canale alfa
  • La lunghezza viene contata in byte UTF-8 senza distinta base

Puoi usare questo script PHP per testare la tua soluzione, fornire il nome del file PNG come primo argomento della riga di comando:

<?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));
}

Le tue specifiche dicono "il tuo programma prende una singola immagine come base". In Mathematica un'immagine è in realtà solo un'espressione come qualsiasi altra cosa, quindi tecnicamente questa specifica mi consentirebbe di eseguire il caricamento del file al di fuori del codice che esegue il calcolo (con il parametro di input che è un'immagine reale anziché il nome del file dell'immagine) . Se non vuoi cose del genere, potresti voler specificare che il programma deve prendere il nome del file di un'immagine come input.
Martin Ender,

4
ME helpimtrappedinacatfactory OW
TheDoctor

Inoltre, i bit non utilizzati per la codifica devono rimanere intatti? Oppure possiamo impostarli su ciò che vogliamo (poiché ciò non influirà davvero sulla qualità dell'immagine e non importa per la decodifica)?
Martin Ender,

1
Posso usare una libreria non integrata per caricare e salvare il file png, ad esempio PIL in Python?
Claudiu,

1
@TimWolla Dal gatto? Tienilo al chiuso e monitora la lettiera. Dalla foto? Se scatti una foto a raggi X con una risoluzione sufficientemente elevata, potresti essere in grado di vedere lo stato dei singoli transistor nel chip flash. Sono certo che questo deve essere il metodo più efficiente per trasmettere informazioni segrete mai inventate, sebbene il gatto possa avere altre idee.
Sonic Atom

Risposte:


3

Perl & ImageMagick (Linux), 198 190

Modificare: per coincidenza, in precedenza ho provato su un computer con la versione Q8 (profondità 8 bit) di ImageMagick installata. La versione Q16 'standard' richiede esplicito -depth 8sulla riga di comando. Su Linux, il identifyrisultato richiede anche la rimozione di newline. Entrambi i fattori portano all'aumento della dimensione del codice, quindi inserisco la versione di Linux (probabilmente anche Mac) come risposta, con correzioni applicate e anche con alcune cose solo per Windows rimosse (conversione cr-lf, binario vs testo ecc.). La versione portatile (leggermente più lunga) viene pubblicata verso la fine.

Con le nuove righe per la leggibilità:

$/=$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

Correre:

perl cat.pl

Legge da STDIN, il nome del file immagine sulla prima riga, segue il messaggio "segreto", terminato con ctrl-D . Il nome del file di output è originale con l' .pngaggiunta - non molto bello, è fatto solo per brevità.

Ecco un'immagine con alcune informazioni molto segrete nascoste all'interno:

inserisci qui la descrizione dell'immagine

E con alcuni commenti:

# 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

La prossima è la versione portatile, funziona sia su Windows (usare ctrl-Zper terminare l'input) sia su Linux, il conteggio dei byte è 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

10

Mathematica, 255 234 206 byte

Ho visto così tanti 255s mentre lo testavo, sono irragionevolmente felice della dimensione del codice. :) E poi la mia ambizione di giocarci ancora meglio ha avuto il meglio di me ...

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)&

È tecnicamente una funzione e non un "programma", ma di nuovo questo è praticamente il modo in cui scrivi "programmi" in Mathematica, se quel concetto è valido anche lì. Chiamalo come

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

Restituirà un'espressione di immagine reale (perché è il modo più naturale per restituire un'immagine in Mathematica), quindi se vuoi un file, devi esportarlo:

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

Ecco l'esempio richiesto:

inserisci qui la descrizione dell'immagine

Mi piacerebbe mostrarti il ​​messaggio decodificato qui, ma non si adatta ... quindi eseguilo attraverso il decoder dell'OP. ;)

A proposito, potrei farlo funzionare con i segreti UTF-8 per soli 7 byte (cambia ToCharacterCode@#in #~ToCharacterCode~"utf8").

Codice non golfato:

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"]
)

"Mi piacerebbe mostrarti il ​​messaggio decodificato qui, ma non si adatta ... quindi eseguilo attraverso il decoder dell'OP.;)" - L'ho fatto e mi dà "????????? ??? ?? +++++++ ++++++++++++++++++++ ================= ~ === ~ ============ ~ :::: ~~~~~ = [... per 9773 caratteri] "
TessellatingHeckler

1
@TessellatingHeckler, è corretto. provalo con un carattere a spaziatura fissa e tieni presente che ci sono nuove righe in stile UNIX (ad es. prova in un terminale o PowerShell con almeno 180 caratteri di larghezza, o se lo stai eseguendo come script web nel tuo browser, quindi visualizzare la fonte);)
Martin Ender

2
Vedo! Molto meta. Mi aiuta anche a essere nella versione KiTTY di PuTTY 😸
TessellatingHeckler

5

PHP, 530 byte

<?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;}}}

Corri come php 25443.php -i<input image> -o<output image> -t<file to hide>.

Ed ecco un'immagine di esempio.

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

Il codice non salvato è nascosto nell'immagine di esempio. Testato con decodificatore OP. Ci scusiamo per la foto non divertente del gatto.


1
Aggiungi il codice non salvato nella tua risposta.
AL

1
È possibile ridurre 0xffa 255.
TimWolla,

È possibile salvare 4 byte se si assume tag brevi: <?function.
nyuszika7h
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.