Introducción

Buscando y buscando librerías para ocultar mensajes en imágenes utilizando Python encontré algunas, pero ninguna funcionó en mi máquina. Ya fuera al momento de instalarla o al momento de utilizarla.

Así que decidí hacerlo a mano, y aprender un poco del proceso. Al final, pude ocultar texto para más tarde recuperarlo. A esta técnica se le llama esteganografía.

No utilicé ninguna librería, sólo PIL para obtener los pixeles de una imagen. Los métodos explicados aquí puede que sean redundantes, pero son bastante explicativos.

Antes de continuar, recomiendo y casi obligo a leer cómo es que modificamos el LSB de cada byte de cada nivel de color en un pixel.

Recuerda tener instalado Python y pip.

Nota: si quieres ver el código completo míralo en GitHub.

Ocultar mensaje en imágenes con Python

Vamos a empezar ocultando información. Veremos paso por paso.

Obtener pixeles de una imagen

Primeramente necesitamos los pixeles como un arreglo de dos dimensiones. El código es sencillo, con la altura y anchura de la imagen hacemos un ciclo dentro de otro. Luego, accedemos a los pixeles en la posición x, y. Y los vamos imprimiendo.

Nota: para evitar que salgan miles de líneas en la terminal, puedes presionar Ctrl + C unos segundos después de ejecutar el script, ya que se imprimirán muchas de ellas.

Como se observa, cada pixel se compone de R, G, B.

Obtener nivel de color por cada pixel

Sólo tenemos que modificar un poco el código anterior. Quedaría así:

Y ahora ya imprime el valor de cada color, por cada pixel.

Ya vimos cómo obtener el nivel de cada color, ahora podemos modificarlo. Pero antes, veamos cómo obtener los bits que escribiremos.

Obtener lista de bits de una palabra

Sé que este método no será el mejor ni el más óptimo, pero repito que todo es con fin de explicar las cosas adecuadamente.

Necesitamos escribir una función que, dada una cadena, devuelva una lista de bits. Por ejemplo, si escribo “Hola” debe devolver [‘0’, ‘1’, ‘0’, ‘0’, ‘1’, ‘0’, ‘0’, ‘0’, ‘0’, ‘1’, ‘1’, ‘0’, ‘1’, ‘1’, ‘1’, ‘1’, ‘0’, ‘1’, ‘1’, ‘0’, ‘1’, ‘1’, ‘0’, ‘0’, ‘0’, ‘1’, ‘1’, ‘0’, ‘0’, ‘0’, ‘0’, ‘1’].

Se ve complicado al inicio, pero no lo es. Primero, convierte cada letra al número que le corresponde en el código ascii. Luego, cada código es convertido a binario (un byte) y más tarde, por cada bit en ese byte creamos una lista:

Al ejecutarlo, se ve esto:

Pero ahora que lo pienso, necesitamos poner unos bits de terminación. Es decir, si tenemos una imagen muy grande y sólo queremos ocultar “Hola”, ¿qué pasa con los demás pixeles? no vamos a recorrer cada pixel sin escribirle nada, y tampoco lo vamos a llenar de ceros.

Mejor ponemos un carácter de terminación; ya que cuando leamos el mensaje oculto tendremos que leer únicamente hasta dicho símbolo. Entonces necesitamos modificar nuestra lista de bits para que regrese los bits de la palabra, y también unos bits de terminación:

Al ejecutarlo, se ve lo mismo que antes. Pero con la diferencia de que ahora, al final, está nuestro carácter de terminación.

Ahora que ya aprendimos esto, vamos a ir modificando un color por cada bit que haya en nuestra lista.

Modificar colores

Antes de juntar todo esto, vamos a ver cómo modificar un color. Recordemos que un pixel tiene 3 colores: Rojo, Verde y Azul. Y cada nivel tiene un valor entre 0 y 255.

Supongamos que nuestro color rojo es 200, y nuestro bit que vamos a ocultar es 1. El código quedaría así:

Al ejecutarlo…

 Juntando todo

Ya que vimos cómo hacer cada cosa, vamos a juntar todo y hacerlo funcional. Por cierto, para modificar un pixel hacemos esto:

Es decir, le pasamos una tupla. Y para guardar todo el arreglo de pixeles (es decir, la imagen con el texto oculto) hacemos esto:

Finalmente, quiero explicar que hay un contador para saber si ya terminamos de escribir el mensaje… si ya terminamos, entonces terminamos el ciclo. También sirve para saber si pudimos escribir o no el mensaje completo.

He aquí el código

Cuando lo ejecuto, sale esto:

En mi caso, la imagen es la de una oveja. Originalmente es esta:

La que tiene el mensaje oculto es esta: Descargar imagen

No la pude poner aquí, porque wordpress le hace alguna modificación. En fin, si la descargas desde mega podrás leer el mensaje.

 

No he probado con imágenes JPG, pero no lo recomiendo, ya que (creo) comprimen los pixeles o algo así, perdiendo nuestros bits ocultos. Por favor prueba  sólo con imágenes PNG.

Ya hemos terminado de ocultar. Hora de leer.

Leer mensaje oculto en imágenes

Esto es un poco más sencillo. Ahora no modificamos ningún color, sólo leemos el LSB de cada nivel. Concatenamos todo en un byte; cuando el byte es un byte (es decir, cuando la cadena mide 8) obtenemos su carácter y ese lo concatenamos en una variable llamada mensaje.

Por ejemplo, si mi byte es “01000000”, entonces su representación decimal es 64, y eso, según el código ascii es el arroba @.

Ese arroba lo concatenamos en otra variable, y así vamos formando nuestro mensaje final.

Ahh, otra cosa. Si encontramos el carácter de terminación, nos damos por bien servidos y dejamos de leer los pixeles.

He aquí el código:

En mi caso, la imagen se llama salida.png. Si quieres, descarga la imagen de la oveja modificada, pon el nombre que indico, ejecuta el script y verás que sale el mensaje:

Con eso terminamos. Ya veremos más tarde cómo podemos regar el mensaje, cifrarlo, etcétera.


Estoy disponible para trabajar en tu proyecto o realizar tu tarea pendiente, no dudes en ponerte en contacto conmigo.
Si el post fue de tu agrado muestra tu apoyo compartiéndolo, suscribiéndote al blog, siguiéndome o realizando una donación.

Suscribir por correo

Ingresa tu correo y recibirás mis últimas entradas sobre programación, open source, bases de datos y todo lo relacionado con informática

Únete a otros 3,194 suscriptores


parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

2 Comentarios

jose · febrero 3, 2020 a las 9:49 am

muy buen aporte amigo, pero como puedo ver ambas imagenes al mismo tiempo
como para saber cual es la original y la codificada, aunque no sería mucha la diferencia entre ambas.

    parzibyte · febrero 3, 2020 a las 4:00 pm

    Puede poner otro nombre a la imagen de salida.
    Saludos 🙂

Deja un comentario

Marcador de posición del avatar

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

A %d blogueros les gusta esto: