El regalo que le hice a Elena

El regalo que le hice a Elena

En efecto, este es el regalo que le hice a Elena, imprimí la foto (realmente era otra versión de mayor resolución) en papel fotográfico y se la regalé con un marco.

¿Qué es lo que tiene de especial esta imagen? Pues que no es una imagen normal y corriente aunque pueda parecer que si, es una imagen con un texto oculto.

Hace 4 años si no recuerdo mal desarrollé un pequeño programa para codificar textos dentro de imagenes (bmp's), se me ocurrió como se me solián ocurrir los proyectos en aquella época, por la noche y en época de exámenes, esa misma noche dejé todo lo que estaba estudiando y me pasé la mayor parte de la noche desarrollando el sistema.

¿Qué es una imagen?

Una imagen es una matriz de píxeles de dimensiones alto*ancho, un pixel es un conjunto de bytes que especifican las canales rojo, verde y azul de cada pixel, a partir de ahora denotado por la sintaxis [rojo, verde, azul], cada uno de los canales puede ir desde 0 hasta 255, de tal manera que un pixel de rojo puro es [255,0,0] y el blanco podría representarse por [255,255,255], es decir, el blanco es la presencia de los 3 colores primarios, esto es lo que se conoce como el modelo RGB bastante usando en representación de colores en un modelo de luz (como pueden ser las pantallas de los ordenadores) en contra posición con el modelo CMYK que se suele usar en impresión (para representación de colores en luz hay más modelos a parte del RGB, una variante bastante usada por ejemplo es el RGBA o ARGB que a parte de los colores primarios también incorpora un componente alpha que otorga transparencia al pixel).

De todas maneras centrémonos en el modelo de esta imagen de cabecera, es una imagen RGB con 8 bits para cada canal, es decir, 1 byte para cada canal (de 0 a 255), como he dicho antes, el color rojo sería representado por [255,0,0] en notación decimal.

¿Como podemos entonces ocultar texto en una imagen?

Pues la solución obviamente pasa por esconder el texto en los pixeles de la imagen, pero para hacer esto nos tenemos hacer otra pregunta.

¿Qué es un texto?

Un texto, al igual que una imagen o cualquier otro elemento digital, no es más que una secuencia de 1's y 0's. Un texto está formado por letras y cada letra está formada 8 bits, es decir, 1 byte, al menos en el sistema ASCII. Por ejemplo, para escribir mi nombre, Ángel Luis, lo que entiende el ordenador es:

181 110 103 101 108 32 76 117 105 115

Eso pasado a sistema binario es lo que realmente entiende el ordenador, por ejemplo, la Á (181) sería 10110101. Mi nombre completo en binario sería

10110101 01101110 01100111 01100101 01101100 00100000 01001100 01110101 01101001 01110011

¿Como podemos entonces ocultar texto en una imagen? (De nuevo)

Visto lo anterior lo que tenemos que hacer es intentar ocultar las letras de un texto en cada uno de los píxeles, pero tenemos una limitación, un pixel en este caso son 8 bytes, al igual que una letra, si introducimos una letra por cada pixel la imagen se distorsionaria porque eliminamos por completo un canal del pixel, por tanto, lo más sencillo una vez llegado aquí es que en vez de codificar una letra por cada pixel se va a codificar 3 bits de una letra por cada pixel, esto es, para codificar una letra necesitaremos 3 píxeles, y se va a modificar el bit menos significativo para que afecte lo mínimo posible a la imagen.

Por ejemplo, si queremos codificar la letra Á (181, 10110101) dentro de una imagen totalmente roja de tamaño 3x3.

Aquí tenemos la imagen original en rojo puro

\begin{pmatrix} [255, 0, 0] &[255, 0, 0] & [255, 0, 0] \\ [255, 0, 0] &[255, 0, 0] & [255, 0, 0] \\ [255, 0, 0] &[255, 0, 0] & [255, 0, 0] \end{pmatrix}

Si lo pasamos a binario que se verá mejor, tenemos

\begin{pmatrix} [1111111\textbf{1}, 0\textbf{0}, 0\textbf{0}] &[1111111\textbf{1}, 0\textbf{0}, 0\textbf{0}] & [1111111\textbf{1}, 0\textbf{0}, 0\textbf{0}] \\ [1111111\textbf{1}, 0\textbf{0}, 0\textbf{0}] &[1111111\textbf{1}, 0\textbf{0}, 0\textbf{0}] & [1111111\textbf{1}, 0\textbf{0}, 0\textbf{0}] \\ [1111111\textbf{1}, 0\textbf{0}, 0\textbf{0}] &[1111111\textbf{1}, 0\textbf{0}, 0\textbf{0}] & [1111111\textbf{1}, 0\textbf{0}, 0\textbf{0}] \end{pmatrix}

Nota: Por simplicidad cuando es todo 0 se omite 00000000 y se pone solo 00

Nota: En negrita están los bits que van a ser sustituidos por cada uno de los bits de la letra Á (10110101)

\begin{pmatrix} [1111111\textbf{1}, 0\textbf{0}, 0\textbf{1}] &[1111111\textbf{1}, 0\textbf{0}, 0\textbf{1}] & [1111111\textbf{0}, 0\textbf{1}, 00] \\ [11111111, 00, 00] &[11111111, 00, 00] & [11111111, 00, 00] \\ [11111111, 00, 00] &[11111111, 00, 00] & [11111111, 00, 00] \end{pmatrix}

En negrita ahora se aprecian aquellos bits a los que ha afectado la codificación.

En decimal esto se traduce a

\begin{pmatrix} [255, 0, 1] &[255, 0, 1] & [254, 1, 0] \\ [255, 0, 0] &[255, 0, 0] & [255, 0, 0] \\ [255, 0, 0] &[255, 0, 0] & [255, 0, 0] \end{pmatrix}

Como se puede observar, al modificar el bit menos significativo obtenemos un error de \pm 1 en cada uno de los canales con respecto a la imagen original.

Esta es nuestra imagen con el texto códificado. Ahora solo queda automatizar el proceso mediante un programa informático, teniendo en cuenta una cosa, el texto tiene que estar delimitado entre una marca de inicio y marca de fin para saber donde empieza el texto y donde acaba.

Proceso de codificación del texto

Proceso de codificación del texto

En la imagen anterior se lista el directorio actual donde existen 4 ficheros, 2 programas, 1 texto y 1 imagen. A continuación se imprime el texto de text_hide por pantalla (Esto es una prueba de texto oculto en una imagen). Luego se ejecuta el programa codificador, se elige la imagen donde se va a codificar el texto (image1.bmp), el texto a ocultar (text_hide) y la nueva imagen que se generará (image1.bmp). Por último, mediante el comando diff nos dice que las 2 imágenes son distintas a nivel binario, es decir, algunos bytes son distintos en ambas imagenes, aunque a efectos prácticos para el ojo humano las 2 imágenes son idénticas.

Proceso de decodificación del texto

Proceso de decodificación del texto

En la imagen anterior se muestra el proceso de decodificación, primero pruebo a decodificar image.bmp y me dice que no tiene ningún texto oculto, a continuación pruebo a decodificar el fichero imagen1.bmp y en efecto me dice que hay un texto oculto en ella.

Este método tiene una desventaja. Si tenemos un texto de 100 letras en total necesitariamos una imagen de

\dfrac{100*8}{3} = 266,666 \approx 267 pixeles

No son especialmente muchos píxeles si los comparamos con una foto en alta definicion (1920 x 1080 píxeles), pero si que puede llegar a ser un factor a tener en cuenta en imágenes más pequeñas.

Conclusión

Así es como le regalé una foto especial a Elena que actualmente se encuentra en su mesita.photo

Esta técnica se llama Esteganografía, y consiste en ocultar mensajes dentro de otros objetos, en este caso una imagen. Esta técnica se lleva usando desde hace muchos siglos.

Recuerdo que el programa lo hice hace unos 4 años y en cuanto a prestaciones deja mucho que desear debido a la falta de tiempo que tenía. Este programa solo acepta imágenes bmp de 24 bytes por pixel (8 por cada canal). Si tuviese que reformar hoy en día este programa haría las siguientes mejoras

  • Aceptar más formátos de imágenes (jpg, png) esto se conseguiría facilmente con alguna librería de tratamiento de imágenes o framework, por ejemplo imagemagick, la clase Pixmap del framework Qt o la función PixBuf del framework GTK+. Una vez decodificada la imagen, el tratamiento sería el mismo que el mostrado aquí, las librerías anteriores solamente decodifican la imagen y la convierten en un mapa de bits (como un bmp nativo).
  • Ocultar el texto en una posición aleatoria de la imagen, actualmente se empieza a ocultar a partir de la posicion 54.
  • Comprimir el texto con algún algoritmo conocido, por ejemplo Base64.
  • Permitir encriptar el texto con algún algoritmo de encriptación, tanto de clave simetrica como de clave asimétrica.
  • Introducir un hash del texto en una parte aleatoria de la imagen que no coincida con la posición del texto, con esto podriamos comprobar que el texto no ha sido modificado.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *