Esteganografía sobre imágenes

por | 17 diciembre, 2015

Les traigo una clase que aplica una de las técnicas de esteganografía pura mas sencillas sobre imágenes que consiste en insertar el mensaje en el bit menos significativo de cada componente de cada pixel de una imagen RGB.

No voy a explicar el algoritmo porque sería muy tedioso. Lo único que voy a hacer es explicar a grandes rasgos como guarda los datos.

Lo primero es que para calcular el tamaño máximo del mensaje que puede albergar la imagen hace la siguiente operación:

MAX = image_width * image_height * 3 / 8

ya que por cada pixel podemos almacenar 3 bits(1 en cada componente RGB). Luego dividimos por 8 para obtener el tamaño en bytes.

Ahora, supongamos que queremos guardar el texto ‘Hola Mundo’ con codificación ascii en una imágen de 400×200. Bien, según la formula podemos guardar hasta 30000 bytes en esta imagen, pero el mensaje solo ocupa 10 bytes ¿Que hacemos con el espacio que sobra? Podríamos ocupar los primeros pixeles para guardar el mensaje y dejar el resto como esta, ¿Pero como sabemos hasta donde leer el mensaje a la hora de extraerlo? Sencillo, agregamos la longitud del mensaje en el mensaje.

Vamos a almacenar la longitud del mensaje como un string. Lo primero que hacemos es calcular cuantos caracteres se necesita para guardar la máxima longitud del mensaje. En este caso MAX = 30000 entonces necesitamos 5 bytes para guardar el numero 30000 como string. Ademas ya no podemos almacenar un mensaje de 30000 bytes porque 5 serán ocupados por la longitud del mensaje. Nos queda así:

MAX_BYTES = image_width * image_height * 3 / 8 = 400 * 200 * 3 / 8 = 30000

OFFSET_LENGTH = len(str(MAX)) = len(‘30000’) = 5

MAX_MSG = MAX_BYTES – OFFSET_LENGTH = 29995

Y así quedaría el mensaje final ‘00010Hola Mundo’. Notar que se completo con ceros puesto que OFFSET_LENGTH = 5.

Les pongo los ejemplos que van a encontrar en el repo. El primero calcula el tamaño máximo de datos que puede almacenar una imagen dada. El segundo inyecta un mensaje y el tercero lo extrae. El cuarto inyecta un archivo mp3 y el quinto lo extrae en el directorio ‘tmp’. Para insertar el mp3 utilice la misma imagen con resolución mayor para que quepa.

from PIL import Image
from StegosaurusImageLSB import StegosaurusImageLSB

   
#Get max data size
def test_get_max_size():
    original = Image.open('chameleon_1920x1276.png')
    st = StegosaurusImageLSB()
    print 'Max message size(chameleon_1920x1276.png): %d' % st.get_max_size(original)


#Inject data
def test_inject():
    original = Image.open('chameleon_1920x1276.png')
    st = StegosaurusImageLSB()
    msg = 'Do not forget to visit my blog: lopezezequiel.com'
    injected = st.inject(original, msg)
    injected.save('chameleon_1920x1276_injected.png')
    print 'Message injected in chameleon_1920x1276_injected.png: %s' % msg


#Extract data
def test_extract():
    injected = Image.open('chameleon_1920x1276_injected.png')
    st = StegosaurusImageLSB()
    msg = st.extract(injected)
    print 'Message extracted from chameleon_1920x1276_injected.png: %s' % msg


#Inject file
def test_inject_file():
    original = Image.open('chameleon_4912x3264.png')
    st = StegosaurusImageLSB()
    injected = st.inject_file(original, 'Alan Walker - Spectre.mp3')
    injected.save('chameleon_4912x3264_injected.png')
    print 'File injected in chameleon_4912x3264_injected.png: Alan Walker - Spectre.mp3'


#Extract file
def test_extract_file():
    injected = Image.open('chameleon_4912x3264_injected.png')
    st = StegosaurusImageLSB()
    st.extract_file(injected, 'tmp')
    print 'File extracted from chameleon_4912x3264_injected.png: ./tmp/Alan Walker - Spectre.mp3'


test_get_max_size()
test_inject()
test_extract()
test_inject_file()
test_extract_file()

Por último aclaro que las imágenes deben ser RGB y en algun formato que no se degrade al guardarse. Si usan un jpg, por ejemplo, al guardarse se ejecutan una serie de algoritmos de compresión con pérdidas que corrompen los datos inyectados.

Enlace del repositorio en Github

Deja un comentario

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