python

Ejemplo de esteganografía en imágenes con Python

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.

See the gist on github.

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í:

See the gist on github.

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:

See the gist on github.

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:

See the gist on github.

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í:

See the gist on github.

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:

See the gist on github.

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

See the gist on github.

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

See the gist on github.

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:

See the gist on github.

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.

Encantado de ayudarte


Estoy disponible para trabajar en tu proyecto, modificar el programa del post o realizar tu tarea pendiente, no dudes en ponerte en contacto conmigo.

No te pierdas ninguno de mis posts

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
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/

Ver comentarios

  • Hola, necesitaría saber si se puede obtener
    alguna relación entre píxeles y fila/columnas.-
    Para ejemplificar, tengo un widget TEXT y necesito relacionar
    el contenido en fila/columnas para establecer las dimensiones
    de este y la ventana.-

  • 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.

Compartir
Publicado por
parzibyte

Entradas recientes

JavaScript (lado del cliente): leer pixeles de imagen

En ocasiones es necesario leer los pixeles y colores de una imagen con JavaScript del…

6 días hace

PHP y JavaScript: llenar select con AJAX

Siguiendo con los tutoriales de listas desplegables o select con JavaScript, vamos a ver cómo…

6 días hace

Imprimir PDF generado con HTML

Hoy vamos a ver programar la impresión de un PDF generado a partir de HTML…

1 semana hace

JavaScript: llenar select con arreglo

En este tutorial básico de JavaScript con HTML vamos a ver cómo llenar una lista…

2 semanas hace

Imprimir PDF a partir de URL

En este artículo se presenta una guía para imprimir un PDF a partir de una…

2 semanas hace

Imprimir PDF a partir de base64

En este post voy a enseñarte cómo imprimir un PDF a partir de su representación…

2 semanas hace

Esta web usa cookies.