Esteganografia e Esteganálise: transmissão e detecção de informações ocultas em imagens digitais

Teoria e implementação da técnica de Esteganografia de imagens baseada nos bits menos significativos (LSB), que visa embutir dados em imagens digitais, e das técnicas de Esteganálise (estrutural, visual e estatística), que consistem na busca de padrões que permitam identificar a existência informações ocultas nas imagens suspeitas.

[ Hits: 74.165 ]

Por: Rafael José de Alencar Almeida em 30/08/2011 | Blog: http://www.rafael-labs.com


Implementação da técnica de Esteganografia LSB



O código abaixo descreve a implementação comentada de cinco funções. A primeira, "pixels", será usada para facilitar a iteração pelos pixels das imagens.

A função "esteganografar" recebe como argumentos a imagem original, o nome com que ela será salva após receber a informação oculta e uma string contendo os bits de informação que serão embutidos.

A função "recuperar" recebe como argumento uma imagem que contenha alguma informação embutida e retorna uma string com os bits da informação extraída.

As funções "gera_bin" e "recupera_str" convertem, respectivamente, uma string de texto em sua respectiva string binária e vice-versa. Elas foram incluídas para facilitar a inserção/recuperação de mensagens de texto nas imagens.

No momento de se recuperar a informação que está embutida na imagem, é preciso saber de antemão quantos bits ela possui. Para isso, a constante PIXELS_RESERVADOS  determina quantos dos primeiros pixels da imagem serão utilizados para armazenar este valor.

A imagem resultante, também chamada de estego-objeto ou estego-imagem, será salva no formato PNG, já que outros formatos como o JPEG utilizam compressão com perdas, o que provocaria a alteração de pixels para reduzir o tamanho em disco da imagem, acarretando perda de informações.

# coding: utf-8

import re
import Image

# Define quantos pixels serão utilizados para informar o tamanho da mensagem oculta
PIXELS_RESERVADOS = 10

def pixels(tam):
    '''Facilita a iteração pelos pixels da imagem'''
    for y in xrange(tam[1]):
        for x in xrange(tam[0]):
            yield (x, y)


def esteganografar(img_orig, img_esteg, str_bin):
    # Abre a imagem e obtém seus atributos
    img = Image.open(img_orig)
    largura, altura = img.size

    # Verifica se o formato da imagem é compatível e se ela possui capacidade
    if img.mode[:3] != 'RGB' or largura * altura * 3  < len(str_bin) + PIXELS_RESERVADOS * 3:
        raise IndexError('O tamanho da mensagem excede a capacidade da imagem ou não há suporte para a mesma')

    # Os primeiros pixels definem o tamanho da informação a ser ocultada
    bits_tam = bin(len(str_bin))[2:].zfill(PIXELS_RESERVADOS * 3)
    str_bin = bits_tam + str_bin
    
    # Completa a informação tornando-a múltipla de 3 e iterável;
    str_bin = enumerate(str_bin + '0' * (3 - len(str_bin) % 3))

    # Carrega os pixels da imagem para a memória;
    pix = img.load()
    
    # Percorre cada pixel da imagem
    for x, y in pixels(img.size):
        try:
            # Altera o valor dos bits menos significativos
            rgb = map(lambda cor, bit: cor - (cor % 2) + int(bit), pix[x, y][:3], [str_bin.next()[1] for _ in xrange(3)])
            pix[x, y] = tuple(rgb)
        except StopIteration:
            # Quando não houver mais bits para se esteganografar, str_bin disparará uma
            # exceção do tipo StopIteration, e a nova imagem estará pronta para ser salva;
            img.save(img_esteg, 'PNG', quality=100)
            return


def recuperar(img_esteg):
    # Abre a imagem, obtém seus atributos e carrega os pixels para a memória
    img = Image.open(img_esteg)
    tam = img.size
    pix = img.load()

    # Obtém os primeiros pixels, que definem o tamanho da informação embutida;
    info_tam = ''
    for p in pixels(tam):
        info_tam += ''.join('1' if cor % 2 else '0' for cor in pix[p][:3])
        if len(info_tam) >= PIXELS_RESERVADOS * 3:
            info_tam = int(info_tam, 2)
            break  
    
    # Extrai a informação binária da imagem
    info_bin = ''
    for p in pixels(tam):
        info_bin += ''.join('1' if cor % 2 else '0' for cor in pix[p][:3])
    
    return info_bin[PIXELS_RESERVADOS * 3:info_tam + PIXELS_RESERVADOS * 3]


def gera_bin(msg):
    '''Para cada caractere, obtém o valor binário de seu código ASCII'''
    return ''.join(bin(ord(caractere))[2:].zfill(8) for caractere in msg)


def recupera_str(str_bin):
    '''Converte cada grupo de 8 bits no seu respectivo caractere'''
    return ''.join(chr(int(bin, 2)) for bin in re.findall(r'.{8}', str_bin))


if __name__ == '__main__':    
    # Oculta a mensagem "Viva o Linux" na imagem "img.jpg" e
    # salva o resultado como "img_msg.png";
    msg_bin = gera_bin('Viva o Linux')
    esteganografar('img.jpg', 'img_msg.png', msg_bin)
    
    # Recupera a mensagem
    msg_bin = recuperar('img_msg.png')
    print recupera_str(msg_bin)

A Figura 2 mostra a comparação entre uma imagem sem informações ocultas e sua versão após ter os bits menos significativos de todos os seus pixels esteganografados com os valores 0 e 1, alternadamente.

Até mesmo nas partes de cor homogênea como o fundo branco é impossível perceber qualquer diferença que indique a existência de uma mensagem embutida, comprovando a eficácia da técnica.
Linux: Esteganografia e Esteganálise: transmissão e detecção de informações ocultas em imagens digitais
Figura 2
Página anterior     Próxima página

Páginas do artigo
   1. Introdução, Imagens digitais e os bits menos significativos
   2. Implementação da técnica de Esteganografia LSB
   3. Esteganálise e Ataque estrutural
   4. Ataque visual
   5. Ataque estatístico e Referências
Outros artigos deste autor

Python: automatizando a extração de informações na web com expressões regulares

Automatizando a criação de uma base de conhecimento em Prolog para gerenciar os acessos a um site

Leitura recomendada

Python - Usando requests anônimos através da rede Tor

Como criar um keylogger em Python

Trabalhando com permutações em ordem lexicográfica crescente

Interagindo com servidores HTTP com Python

Gerar senhas seguras com Python

  
Comentários
[1] Comentário enviado por wadilson em 30/08/2011 - 23:29h

Rafael, muito bom.

Só não digo que esse post é uma aula por que de fato são várias aulas.

Sensacional. Para ler, guardar e usar.

[2] Comentário enviado por mauricio1241 em 31/08/2011 - 10:12h

Muito bom mesmo =D

[3] Comentário enviado por patricia.malvina em 31/08/2011 - 11:02h

Conhecia o seu projeto mas não com esse detalhamento tão completo. Parabéns, Rafael.

[4] Comentário enviado por rafael.alencar em 31/08/2011 - 13:01h

Pessoal, obrigado pelos comentários!
Patrícia, que bom que você ainda não se cansou de tanto ouvir sobre Esteganografia e Esteganálise :D

[5] Comentário enviado por julio_hoffimann em 31/08/2011 - 20:07h

Parabéns Rafael!

Fazia tempo que não lia um artigo tão interessante no Viva o Linux! Muito bom mesmo! Além de explicar os conceitos de forma clara, você forneceu o código, o que extermina qualquer dúvida. :-)

Abraço!

[6] Comentário enviado por JohnRobson em 01/09/2011 - 19:22h

http://www.larc.usp.br/~pbarreto/Tese.pdf

[7] Comentário enviado por rafael.alencar em 01/09/2011 - 19:46h

Olá John,

Excelente material esta tese de doutorado. É bem legal saber que há acadêmicos brasileiros trabalhando nesta área.
Se eu conseguir destrinchar as notações matemáticas vou implementar os algoritmos descritos na tese.
Obrigado por compartilhar!

[8] Comentário enviado por malfatti-filho em 03/09/2011 - 23:38h

Caramba , coisa de doido

Parabens , Tá tão bem explicado que lendo a gente agrega muita informação

Parabens !

[9] Comentário enviado por rodrigocontrib em 02/04/2013 - 09:26h

Tenho uma Pergunta,
A analise do objeto estegnografado so pode ser executado apartir de um objeto não estegnografado ou as analises de comparação tem uma autosuficiencia em sua analise, não precisando assim de um objeto original ?

Minha pergunta é porque nas redes sociais existe uma gama de metodos de transmissao de informação de arquivos estegnografados ou não.

[10] Comentário enviado por sprayone1 em 18/10/2016 - 21:54h

Que louco! Muito bom artigo, excelente explanação.


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts