Ocultando informações com esteganografia

Esteganografia, também conhecida como a arte da comunicação invisível, é o estudo sobre a ocultação de uma informação dentro de outra sem que seja possível saber da existência da informação ofuscada. Essa palavra vem dos termos gregos “stegos”, que significa “esconder” e “grafia” que significa “escrita”.

A grande diferença entre a esteganografia para a criptografia é que, diferente da criptografia, onde o receptor sabe que alguma informação está codificada, a esteganografia busca ocultar a existência da informação, assim, só é possível ser decodificada por quem sabe que algo está escondido.

A esteganografia já tem sido utilizada a muito tempo, como por exemplo na Grécia antiga onde mensagens eram escritas em tábuas e cobertas com cera para que ficassem ocultas e somente seria possível vê-las novamente quando a cera fosse removida. Hoje em dia existem diversas formas de algoritmos diferentes capazes de realizar esse tipo de ocultação. Uma forma de esteganografia que tem sido bastante utilizada no jornalismo para criação de uma impressão digital em textos divulgados é a inserção de caracteres unicode zero width dentro do texto. Estes caracteres funcionam como qualquer outros, porém não existem representação visual, portanto não é possível identificá-los no texto se não utilizar uma ferramenta que exibe cada tipo de caractere unicode incluso.

Como funciona

Os caracteres unicode Zero-width non-joiner (U+200C) e Zero-width space (U+200B) não possuem nenhuma identificação visual em um texto, e por isso conseguimos usá-los para esconder qualquer mensagem.

Com dois caracteres diferentes conseguimos escrever qualquer mensagem utilizando codificação binária. Para isso, primeiro buscamos o valor unicode de cada caractere da mensagem, e convertemos para binário. Juntando todos esses, podemos converter o valor 1 para o caractere U+200C e o valor 0 para U+200B. Veja no código abaixo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const padZeros = text => '00000000'.slice(String(text).length) + text;
//Convertendo texto para binário
const textToBinary = text => {
return text.split('')
.map(char => padZeros(char.charCodeAt(0).toString(2)))
.join('');
}
//Alterando os caracteres do texto para caracteres "invisíveis"
const hideText = text => {
return textToBinary(text)
.replace(/1/g, '\u200c')
.replace(/0/g, '\u200b');
}

console.log(hideText('Esta informação está escondida!'));

Tendo essa string convertida, podemos inserir em qualquer outra string que ela acaba ficando “invisível” para quem está lendo o texto.
O código abaixo faz a lógica reversa. Ele busca os caracteres zero width, converte para binário e depois de volta para texto.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//Convertendo texto escondido para binário
const hiddenToBinary = text => {
return text.split('')
.filter(char => char === '\u200c' || char === '\u200b')
.map(char => char === '\u200c' ? '1' : '0')
.join('');
}
//Convertendo código binário para texto
const binaryToText = text => {
return hiddenToBinary(text).split('')
.reduce((result, value, index, array) => {
if (index % 8 === 0) result.push(array.slice(index, index + 8));
return result;
}, [])
.map(char => String.fromCharCode(parseInt(char.join(''), 2)))
.join('');
}

console.log(binaryToText(hideText('Esta informação está escondida!')));

Conclusão

Com as funções acima conseguimos esconder qualquer texto e decodificá-lo posteriormente. A string gerada pela codificação pode, por exemplo, ser inserida no meio de um texto qualquer como uma impressão digital. Desta forma, leitores sem conhecimento não irá conseguir perceber o código oculto, mas caso copiem o texto completo para outros lugares essa informação com a impressão digital continuará indo junto.

Este é só um dos algoritmos de esteganografias utilizados hoje em dia, mas a lista vai longe com muita coisa interessante. Este algoritmo aqui, por exemplo, converte um texto em jogadas de xadrez, e consegue realizar também o inverso. Este outro esconde uma imagem dentro de outra através do último bit da imagem “fonte”.