Ocultar información en gatos

24

Eres un agente secreto que intenta comunicarte con tu patria. Por supuesto, la información debe estar oculta para que nadie deje caer su mensaje. ¿Qué sería más adecuado que un gato? ¡A todos les encantan las fotos divertidas de gatos [cita requerida] , por lo que no sospecharán que se esconde información secreta allí!


Inspirado por el algoritmo que utiliza el juego Mónaco para guardar la información de nivel de los niveles compartidos , es su tarea escribir un programa que codifique la información en el bit menos significativo de los colores de una imagen.

Formato de codificación:

  • Los primeros 24 bits determinan la longitud de la cadena de bytes codificada restante en bits
  • La imagen se lee de izquierda a derecha y de arriba a abajo, obviamente comenzando en el píxel superior izquierdo
  • Los canales se leen de rojo a verde a azul.
  • Se lee el bit menos significativo de cada canal
  • Los bits se guardan en orden Big Endian

Reglas:

  • Su programa toma una sola cadena de bytes para codificar y un solo nombre de archivo de imagen para la imagen base
  • La imagen resultante debe aparecer como un archivo PNG de color verdadero
  • Puede usar E / S en cualquier forma que desee (ARGV, STDIN, STDOUT, escritura / lectura de un archivo), siempre que indique cómo usar su programa
  • Debes elegir una imagen aleatoria de un gato divertido y codificar tu programa en ella para mostrar que funciona
  • Puede suponer que solo se le proporciona una entrada válida, si la cantidad de bits no es suficiente, la imagen no está en formato de color verdadero, la imagen no existe o problemas similares, puede hacer lo que quiera
  • Puede suponer que la imagen proporcionada no contiene ningún canal alfa
  • La longitud se cuenta en UTF-8 bytes sin BOM

Puede usar este script PHP para probar su solución, proporcione el nombre del archivo PNG como primer argumento de línea de 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));
}
TimWolla
fuente
Su especificación dice "su programa toma una sola imagen como base". En Mathematica, una imagen es en realidad solo una expresión como todo lo demás, por lo que técnicamente esta especificación me permitiría cargar el archivo fuera del código que realiza el cálculo (con el parámetro de entrada como una imagen real en lugar del nombre del archivo de la imagen) . Si no quiere cosas así, puede especificar que el programa necesita tomar el nombre de archivo de una imagen como entrada.
Martin Ender
44
ME helpimtrappedinacatfactory OW
TheDoctor
Además, ¿los bits no utilizados para la codificación deben permanecer intactos? ¿O podemos configurarlos para lo que queramos (ya que eso realmente no afectará la calidad de la imagen y no importa para la decodificación)?
Martin Ender
1
¿Puedo usar una biblioteca no incorporada para cargar y guardar el archivo png, por ejemplo, PIL en Python?
Claudiu
1
@TimWolla ¿Del gato? Manténgalo en el interior y controle la bandeja de arena. De la foto? Si toma una foto de rayos X de resolución suficientemente alta, puede ver el estado de los transistores individuales en el chip flash. Estoy seguro de que este debe ser el método más eficiente para transmitir información secreta jamás ideado, aunque el gato puede tener otras ideas.
Sonic Atom el

Respuestas:

3

Perl y ImageMagick (Linux), 198 190

Editar: Por alguna coincidencia, antes probé en una computadora con la versión Q8 (8 bits de profundidad) de ImageMagick instalada. La versión 'estándar' Q16 requiere explícito -depth 8en la línea de comando. En Linux, el identifyresultado requiere que se elimine la nueva línea también. Ambos factores conducen al aumento del tamaño del código, por lo tanto, publico la versión de Linux (probablemente Mac también) como respuesta, con correcciones aplicadas, y también con algunas cosas solo de Windows eliminadas (conversión cr-lf, binario vs texto, etc.). La versión portátil (un poco más larga) se publica cerca del final.

Con nuevas líneas de legibilidad:

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

Correr:

perl cat.pl

Se lee desde STDIN, el nombre del archivo de imagen en la primera línea, sigue el mensaje 'secreto', terminado con ctrl-D. El nombre del archivo de salida es original con .pngadjunto, no muy agradable, solo se hace por brevedad.

Aquí hay una imagen con información muy secreta oculta:

ingrese la descripción de la imagen aquí

Y con algunos comentarios:

# 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 siguiente es la versión portátil, se ejecuta tanto en Windows (usar ctrl-Zpara terminar la entrada) como en Linux, el recuento de bytes es 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
usuario2846289
fuente
10

Mathematica, 255 234 206 bytes

He visto tantos 255mensajes de correo electrónico mientras probaba esto, estoy excesivamente contento con el tamaño del código. :) Y luego mi ambición de jugar golf aún mejor me ganó ...

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

Técnicamente es una función y no un "programa", pero, de nuevo, esto es más o menos como escribir "programas" en Mathematica, si ese concepto es válido allí. Llámalo como

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

Devolverá una expresión de imagen real (porque esa es la forma más natural de devolver una imagen en Mathematica), por lo que si desea un archivo, debe exportarlo:

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

Aquí está el ejemplo requerido:

ingrese la descripción de la imagen aquí

Me encantaría mostrarte el mensaje decodificado aquí, pero no encaja ... así que ejecútalo a través del decodificador del OP. ;)

Por cierto, podría hacer que funcione con secretos UTF-8 por solo 7 bytes (cambiar ToCharacterCode@#a #~ToCharacterCode~"utf8").

Código sin golf:

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
fuente
"Me encantaría mostrarte el mensaje decodificado aquí, pero no encaja ... así que ejecútalo a través del decodificador del OP.;)" - Lo hice y me da "????????? ??? +++++++ ?? ++++++++++++++++++++ ================= ~ === ~ ============ ~ :::: ~~~~~ = [... para 9773 caracteres] "
TessellatingHeckler
1
@TessellatingHeckler, eso es correcto. pruébelo en una fuente monoespaciada y tenga en cuenta que hay nuevas líneas de estilo UNIX (por ejemplo, intente en un terminal o PowerShell con al menos 180 caracteres de ancho, o si lo está ejecutando como un script web en su navegador, luego ver la fuente);)
Martin Ender
2
¡Veo! Muy meta. Ayuda a que también esté en la versión KiTTY de PuTTY 😸
TessellatingHeckler
5

PHP, 530 bytes

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

Corre como php 25443.php -i<input image> -o<output image> -t<file to hide>.

Y aquí hay una imagen de muestra.

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

El código no oculto está oculto en la imagen de muestra. Probado con el decodificador de OP. Perdón por la imagen no divertida del gato.

Bocadillo
fuente
1
Agregue el código no reflejado en su respuesta.
AL
1
Puedes acortar 0xffa 255.
TimWolla
Puede guardar 4 bytes si se asume etiquetas cortas: <?function.
nyuszika7h