
Esteganografía en Python | Oculta archivos o datos en archivos de imagen
Este script ocultará archivos dentro de imágenes y guardará la imagen modificada en el disco.
El tamaño máximo de archivo que se puede ocultar dentro de una imagen depende de las dimensiones de la imagen.
max_file_size = ( height_of_image * width_of_image * 6 / 8 ) bytes
'100k words.txt' está oculto en 'original_image.png' nombrado como 'image_with_100k words.png'. Ve y comprueba si puedes notar la diferencia entre estas dos imágenes. Puedes usar este Módulo para extraer '100k words.txt' de 'image_with_100k words.png'
Imagen Original

Imagen Modificada

¡Esta imagen tiene 100k palabras (un archivo de texto) ocultas en su interior!
Se basa en un principio simple: si cambiamos los LSB (Bits Menos Significativos) de cada píxel, el cambio no será significativo y no será perceptible para el ojo humano.
Por lo tanto, este Módulo toma 2 bits de datos del archivo a ocultar y reemplaza los últimos 2 bits de un píxel con esos 2 bits, y luego pasa al siguiente píxel. El cambio máximo en un píxel puede ser de 4 unidades, y el rango de valores en una imagen PNG es (0,255), por lo que este cambio no será significativo.
En una imagen PNG, cada píxel tiene 3 canales: Rojo, Verde y Azul. (Algunas imágenes PNG tienen 1 o 4 canales, pero este Programa las convertirá a 3 canales). Un píxel típico en una imagen PNG se ve así:
a_pixel = (17,32,11) # (ROJO, VERDE, AZUL)
Por lo tanto, podemos guardar 3 veces 2 bits en un píxel, es decir, 6 bits por píxel. Eso nos lleva al límite superior del tamaño de archivo que se puede ocultar en una imagen:
max_file_size = ( height_of_image * width_of_image * 6 / 8 ) bytes
Entendamos con un ejemplo. Los datos a ocultar son:
binary_data = 0b100111
Tomemos los primeros dos bits y reemplacémoslos con el canal ROJO de nuestro 'a_pixel'.
a_pixel = (0b10001, 0b100000, 0b1011) # representación binaria de los valores de a_pixel
# Cambiemos el canal ROJO de a_pixel
# 0b10001 -> 0b10010 (Los primeros 2 bits son 10)
a_pixel = (0b10010, 0b100000, 0b1011) # píxel modificado
Tomemos nuevamente 2 bits de binary_data y reemplacemos los últimos 2 bits del canal VERDE con ellos.
a_pixel = (0b10010, 0b100000, 0b1011)
# Cambiemos el canal VERDE de a_pixel
# 0b100000 -> 0b100001 (Los 2 bits son 01)
a_pixel = (0b10010, 0b100001, 0b1011) # píxel modificado
Hagamos esto una vez más con el canal AZUL y habremos terminado.
a_pixel = (0b10010, 0b100001, 0b1011)
# Cambiemos el canal AZUL de a_pixel
# 0b1011 -> 0b1011 (Los 2 bits son 11) ; Observa que el valor no cambió esta vez
a_pixel = (0b10010, 0b100001, 0b1011) # el píxel no se modificó esta vez
Entonces, hemos ocultado nuestro mensaje de 6 bits en un píxel, veamos los cambios en el píxel
a_pixel = (0b10001, 0b100000, 0b1011) = (17, 32, 11)
a_pixel_con_datos = (0b10010, 0b100001, 0b1011) = (18, 33, 11)
Como podemos ver, el cambio ni siquiera es perceptible a nivel de píxel. El Módulo hace esto repetidamente hasta que todos nuestros datos se guardan en la imagen.

NOTA: El ruido en la foto aumenta y si usamos algún software de edición de fotos y lo comparamos con la imagen original, esta imagen tendrá mucho más ruido que la original.
Solución para este problema: Nunca subas/compartas la imagen original a internet
MIT
¡Software libre, demonios sí!