Esteganografia

10 respostas
J

Pessoal, boa tarde!!
Recebi um desafio para decifrar uma mensagem em uma imagem.bmp.
A imagem foi ofuscada via LSB.
Admito que nunca tinha trabalhado com manipulação de imagens no Java, porém gostaria de trabalhar no desafio.
Minha dúvida é:
Por onde começar a decifrar essa imagem.
Há métodos que me ajudariam com isso?

Desde já eu agradeço a compreensão e estarei disposto a debater com todos as futuras dúvidas.

10 Respostas

ViniGodoy

A parte de imagens você pode começar por aqui:

Se quiser ver especificamente sobre esteganografia, veja:

Eu postei um código fonte que faz o processo nesse tópico. Ele está escondido na logo do GUJ.
Basta usar o .jar para extraí-lo de lá. :slight_smile:

J

ViniGodoy:
A parte de imagens você pode começar por aqui:

Se quiser ver especificamente sobre esteganografia, veja:

Eu postei um código fonte que faz o processo nesse tópico. Ele está escondido na logo do GUJ.
Basta usar o .jar para extraí-lo de lá. :)

ViniGodoy,
Muito Obrigado para disponibilizar o seu exemplo.
Nesse caso específico, por onde vc me recomendaria começar?
No seu exemplo, ele pede java -jar Esteganografia.jar -r nomedaimagem.png que no caso é a logo e pede o nome do arquivo.
Qual arquivo seria esse?

ViniGodoy

O nome do arquivo só é necessário com o parâmetro -e (de esconder).

Com o parametro -r (de revelar) basta passar o nome da imagem:

java -jar Esteganografia.jar -r logo.png

Ao dar esse comando, tanto os fontes quanto um readme irão aparecer no mesmo diretório da imagem.

Se você quiser esconder arquivos numa imagem, poderia fazer:

java -jar Esteganografia.jar -e imagem.png arquivo1.txt arquivo2.docx

O meu programa permite que uma única imagem esconda diversos arquivos dentro. Isso porque eu “zipo” todos os arquivos antes de esconde-los lá. :wink:

J

ViniGodoy:
O nome do arquivo só é necessário com o parâmetro -e (de esconder).

Com o parametro -r (de revelar) bastas passar o nome da imagem:

java -jar Esteganografia.jar -r logo.png

Ao dar esse comando, tanto os fontes quanto um readme irão aparecer no mesmo diretório da imagem.

Se você quiser esconder arquivos numa imagem, poderia fazer:

java -jar Esteganografia.jar -e imagem.png arquivo1.txt arquivo2.docx

O meu programa permite que uma única imagem esconda diversos arquivos dentro. Isso porque eu “zipo” todos os arquivos antes de esconde-los lá. ;)

Ah, agora entendi ViniGodoy,
o jar esconde dois arquivos, certo?

No caso do meu, eu já tenho uma imagem que tem uma frase oculta pela Esteganografia, pelo LSB, bit menos significativo
A lógica seria a mesma???

Eu estava pensando em fazer um for pra rodar na imagem e pegar os seus bits.
Fazendo isso, eu teria que joga-lo dentro de um array, certo?

E dai depois que eu tivesse o array de bytes, eu trataria para trazer os bits alterados.

Estou pensando errado ou complicando demais a situação? rs

ViniGodoy

Comece entendendo o princípio. Veja o post que eu fiz:

Mais legal é fazer esteganografia.

Ao invés de transformar cada letra numa cor, pegue uma imagem já pronta e limpe apenas os dois bits menos significativos de cada componente de cor (incluindo o alfa) e substitua-os pelos bits da letra.
Assim você terá uma imagem praticamente idêntica a original, mas com um texto escondido nela.

Por exemplo, vamos supor que você tenha a letra A, que representa o código 65, isso em binário é:
01[color=red"]00[/color][color=“green”]00[/color][color=“blue”]01[/color]

E sua primeira cor é 248, 248, 255, 255, ou seja, em binário:

11111000 11111000 11111111 11111111

Limpe os dois bits menos significativos:
11111000 11111000 11111100 11111100

E substitua pelos da letra:
11111001 111110[color=“red”]00[/color] 111111[color=“green”]00[/color] 111111[color=“blue”]01[/color]

Assim cada pixel “esconde” uma letra.

Se quiser gerar com mais fidelidade, você pode usar 2 pixels (8 bytes) para representar uma única letra (1 byte), apenas aproveitando o último bit de cada canal de cor.

Que explica como o princípio funciona. Como a codificação é LSB (least significant bit) é exatamente o processo que descrevi.

Se a imagem for em escala de cinza, provavelmente você terá que juntar o último bit de 8 pixels para compor 1 único byte. Se for colorida, terá que juntar 3 pixels (já que cada pixel tem 3 bytes, R, G e B). É o mesmo processo que fiz no meu programa - embora lá eu tenha usado mais de 1 bit por canal de cor.

É lógico que o meu programa não vai resolver seu problema de cara, pois o método que utilizo pode ser um pouco diferente. Mas ali já está a base para você entender como manipular imagem e isolar o bit que quiser para compor outro byte.

ViniGodoy

joao0212:
Ah, agora entendi ViniGodoy,
o jar esconde dois arquivos, certo?

O .jar esconde na imagem quantos arquivos você passar, no limite do tamanho da imagem. Uma imagem de 800x600 tem capacidade de esconder 720.000 bytes (um pouco mais pois os arquivos são compactados).

No caso do meu, eu já tenho uma imagem que tem uma frase oculta pela Esteganografia, pelo LSB, bit menos significativo
A lógica seria a mesma???

Sim, só que você quer revelar e não esconder.

Eu estava pensando em fazer um for pra rodar na imagem e pegar os seus bits.
Fazendo isso, eu teria que joga-lo dentro de um array, certo?

A classe BufferedImage já permite ler a imagem pixel a pixel. Não recomendo só ler os bits diretamente pois a codificação da imagem (PNG, TIFF, etc) pode alterar a ordem dos canais ou a forma de lê-la. Além disso, alguns bytes do arquivo de imagem provavelmente serão informação de cabeçalho e não de cores.

A classe BufferedImage já trata esses detalhes para você.

No mais, a lógica é essa mesmo. Lê byte-a-byte, isola o último bit de cada canal e compõe um novo byte. Quando esse byte estiver completo, basta usar um FileOutputStream para cuspi-lo para um arquivo qualquer. Nos fontes do meu programa mostra como realizar esse processo. :slight_smile:

J

ViniGodoy:
joao0212:
Ah, agora entendi ViniGodoy,
o jar esconde dois arquivos, certo?

O .jar esconde na imagem quantos arquivos você passar, no limite do tamanho da imagem. Uma imagem de 800x600 tem capacidade de esconder 720.000 bytes (um pouco mais pois os arquivos são compactados).

No caso do meu, eu já tenho uma imagem que tem uma frase oculta pela Esteganografia, pelo LSB, bit menos significativo
A lógica seria a mesma???

Sim, só que você quer revelar e não esconder.

Eu estava pensando em fazer um for pra rodar na imagem e pegar os seus bits.
Fazendo isso, eu teria que joga-lo dentro de um array, certo?

A classe BufferedImage já permite ler a imagem pixel a pixel. Não recomendo só ler os bits diretamente pois a codificação da imagem (PNG, TIFF, etc) pode alterar a ordem dos canais ou a forma de lê-la. Além disso, alguns bytes do arquivo de imagem provavelmente serão informação de cabeçalho e não de cores.

A classe BufferedImage já trata esses detalhes para você.

No mais, a lógica é essa mesmo. Lê byte-a-byte, isola o último bit de cada canal e compõe um novo byte. Quando esse byte estiver completo, basta usar um FileOutputStream para cuspi-lo para um arquivo qualquer. Nos fontes do meu programa mostra como realizar esse processo. :slight_smile:

Entendi ViniGodoy,
Quando eu formar esse novo byte, será a mensagem.
Muito Obrigado cara, me ajudou a clarear algumas dúvidas.
o formato da imagem é bitmap.
Muda algo??

ViniGodoy

Se você usar a classe BufferedImage ela encapsula a mudança. Aí vai ser indiferente se for bitmap, png ou tiff.

No caso do bitmap do Windows, a ordem dos canais no disco é BGR e não RGB. Se você extrair os dados em R, G e B e não der certo tente inverter.

J
ViniGodoy:
Se você usar a classe BufferedImage ela encapsula a mudança. Aí vai ser indiferente se for bitmap, png ou tiff.

No caso do bitmap do Windows, a ordem dos canais no disco é BGR e não RGB. Se você extrair os dados em R, G e B e não der certo tente inverter.

ViniGodoy,
Estou começando a mexer com a manipulação da imagem, porém esbarrei em alguns problemas, na verdade não são problemas pois não tenho conhecimento rs rs ..

public class Esteganografia{
        
        public byte[] pegarBytes() throws IOException{ 
            File file = new File("C:\\Users\\7\\Documents\\loop.testImage.bmp");
            BufferedImage imagem = ImageIO.read(file);
            int h = imagem.getHeight();
            int w = imagem.getWidth();
            int[] pixels = imagem.getRGB(h, h, h, h, null, h, h);
            return
        }
    }
criei um método do tipo array, fiquei na dúvida se já passaria parâmetros pra ele, mas acabei passando direto no file. Minha dúvida é ... Esse código serve para esse caso e se caso servir, quais são os paramêtros que devem ser passado em getRGB? esses foi o próprio netbeans que passou. Outra dúvida é onde eu vou por o for para percorrer a imagem. Desculpa o incomodo, porém estou com algumas dificuldades nesse desafio.

ps: o return deixei vazio por enquanto.

ViniGodoy

Não complique. Use o método getRgb que rece 2 inteiros, a linha e a coluna do pixel que você quer ler.

Isso te retornará um int, que você guarda dentro de um objeto do tipo Color:

Color pixel = new Color(imagem.getRgb(x, y));

O objeto do tipo color tem os métodos getRed, getGreen e getBlue para a leitura de cada canal.

Criado 3 de fevereiro de 2015
Ultima resposta 6 de fev. de 2015
Respostas 10
Participantes 2