A gift that I did to Elena

A gift that I did to Elena

That photo is the present that I did to Elena. I printed the photo (well, the original photo had a higher resolution), put it on frame and give it to Elena.

So, Why this photo is special? What relation has this photo with the thematic of this blog?. Let me show the magic inside this photo.

That photo is a special photo, ¡inside it the photo hide a message!

If my memory doesn't fail, 4 years ago I develop a little program that can hide texts inside images (bmp's). As usual in me, I had the idea at night and in exams period. That night I forgot all that I had to do and started to develop the program.

What is an image?

An image is a pixel matrix of height*width dimensions, a pixel is a set of bytes that determine the amount of red, green and blue that contain each pixel (each "amount" can be called channel), from now it denote as [red, green, blue], each channel can be anu number between 0 and 255 in decimal, so the red color is [255,0,0] and the white color is [255,255,255], that is, the white color is formed by the presence of all primary colors, this model is called RGB and is frequently used for color representation in light model (as could be monitor of computers), in the other hand, for color representation in paper, the most common model is CMYK. A variation of RGB is ARGB or RGBA, in this model we have a additional channel for alpha.

We center in RGB model that is used in the header image, this image has 8 bit per each channel, this is, 1 byte per each channel (from 0 to 255 in decimal). As I mentioned before a red color in this model is [255, 0, 0]

How can we hide text in an image?

This is simple solution, obviously the solution is hide text inside pixel of the image, but to do this we must ask other question.

What is a text?

A text, same as image or whatever digital thing is a sequence of 1's and 0's. A text is formed by letters and each letter is formed by 8 bits, this is, 1 byte, this is valid for the system that we use in Spain (extended ascii). For example, to write my name, Ángel Luis, the computer understand:

181 110 103 101 108 32 76 117 105 115

If we pass this to binary, that is what computers understand, we obtain:

10110101 01101110 01100111 01100101 01101100 00100000 01001100 01110101 01101001 01110011

 

How can we hide text in a image? (Again)

What we have to do is try to hide letters of text inside pixels, but we have a limitation, our pixels has 8 bits, the same as a letter, if we store a letter per pixel the image will be distorted because we remove completely a channel of our pixel, so the mos simple way to do our task is store 3 bits per pixel (1 bit per channel), so in order to encode one letter we need 3 pixels. Other thing that we have in mind is that we have to modify the less significant bit in our channel, the purpose of this is to affect as little as possible to our image.For example, if we want encode the letter Á (181, 10110101) in a image completely red that have 3x3 size.Here is the original image in red

\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}

If we pass it to binary, we have

\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}

Note: For simplicity when a channel is completely 0 we use 00 instead 0000000.

Note: In bold the bits that will be replaced for each of our letter's bits (in that case the letter will be Á, 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}

Now, in bold the bits that has been affected by encode.

If we pass it to decimal

\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}

As you can see, when we modify the less significant bit we get an error of 1 pixel in each channel respect the original image.

This is our image with the encoded text. Now, we only have to automatize the process via program, have in mind that text must be delimited between start and end flag in order to know where start and end the text.

Proceso de codificación del texto

Process to encode text

In the above image we list the current directory where there are 4 files, 2 programs, 1 text and 1 image. Next we show the text inside text_hide (Esto es una prueba de texto oculto en una imagen). Now we run the program codificador, we choose the image where the text will be encode (image1.bmp), the text to hide (text_hide) and the new image that will be generated (image1.bmp). Finally I show that 2 images are different, for that I use a diff command. Despite this, for the human's eye both images are  identical.

Proceso de decodificación del texto

Process to decode text

In above image I show decode process. First I try to decode image.bmp, that is the original image, and the program says that it hasn't hidden text, next I try to decode the file image1.bmp and the program text that it has a hidden text.This method has a disadvantage. If we have a text of 100 letters of length, we need a image of

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

Not many pixels if we compare it with a high definition photo (1920 x 1090 pixels). But it could be a limitation with little images.

Conclusion

photo

So, this was a special gift to Elena.This technique is called Steganography, and it is based in hide messages inside other containers, in this case, a image.I want to remember you that this program has 4 years old. This program only accepts bmp images of 24 bytes per pixel (8 bytes per channel). If I have to improve this program I considerer the following points

  • Accept more images format (like jpg or png), This will be get using some processing image library or framework, for example, imagemagick, Pixmap class from Qt or PixBuf function from GTK+.
  • Hide text in a random position in the image, now the text starts encode at position 54.
  • Compress the text with well-known, for example Base64.
  • Encrypt the text with well-known algorithm (symmetric or asymmetric) like RSA or AES.
  • Also hide a text's hash in a random position of the image, with this we can check that message hasn't been modified.

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.