Érase unha vez que escribín o meu
Hoxe tentaremos afondar un pouco máis e mirar o algoritmo LSB. Se estás interesado, benvido baixo cat. (Debaixo do corte hai tráfico: preto dun megabyte).
En primeiro lugar, é necesario facer unha pequena introdución. Todo o mundo sabe que o propósito da criptografía é facer imposible ler información secreta. Por suposto, a criptografía ten as súas aplicacións, pero hai outro enfoque para a protección de datos. Non temos que cifrar a información, pero pretender que non a temos. Precisamente por iso se inventou a esteganografía. A Wikipedia asegúranos que “a esteganografía (do grego στεγανοσ - oculto e do grego γραφω - escribo, literalmente “escritura secreta”) é a ciencia da transmisión oculta de información mantendo en segredo o feito mesmo da transmisión.
Por suposto, ninguén prohibe combinar métodos criptográficos e esteganográficos. Ademais, na práctica fan isto, pero a nosa tarefa é comprender o básico. Se estudas detidamente o artigo da Wikipedia, descubrirás que os algoritmos de esteganografía inclúen os chamados. contedor e mensaxe. Un contedor é calquera información que axude a ocultar a nosa mensaxe secreta.
No noso caso, o contedor será unha imaxe en formato BMP. En primeiro lugar, vexamos a estrutura deste ficheiro. O ficheiro pódese dividir en 4 partes: cabeceira do ficheiro, cabeceira da imaxe, paleta e a propia imaxe. Para os nosos propósitos, só necesitamos saber o que está escrito na cabeceira.
Os dous primeiros bytes da cabeceira son a sinatura BM, despois o tamaño do ficheiro en bytes escríbese nunha palabra dobre, os seguintes 4 bytes están reservados e deben conter ceros e, finalmente, outra palabra dobre contén o desplazamento desde o principio do ficheiro aos bytes reais da imaxe. Nun ficheiro bmp de 24 bits, cada píxel está codificado con tres bytes BGR.
Agora xa sabemos como chegar á imaxe, só queda entender como podemos escribir alí a información que precisamos. Para iso necesitaremos o método LSB. A esencia do método é a seguinte: substituímos os bits menos significativos nos bytes responsables da codificación de cores. Digamos que se o byte seguinte da nosa mensaxe secreta é 11001011 e os bytes da imaxe son... 11101100 01001110 01111100 0101100111..., entón a codificación terá este aspecto. Dividiremos o byte da mensaxe secreta en 4 partes de dous bits: 11, 00, 10, 11 e substituiremos os bits de orde baixa da imaxe polos fragmentos resultantes: ...11101111 01001100 01111110 0101100111…. Tal substitución xeralmente non é perceptible para o ollo humano. Ademais, moitos dispositivos de saída máis antigos nin sequera poderán mostrar cambios tan pequenos.
Está claro que pode cambiar non só os 2 bits menos significativos, senón calquera número deles. Existe o seguinte patrón: cantos máis bits cambiemos, máis información podemos ocultar e máis interferencias provocará na imaxe orixinal. Por exemplo, aquí tes dúas imaxes:
A pesar dos meus mellores esforzos, non puiden ver a diferenza entre eles, pero con todo, na segunda imaxe, usando o método descrito, o poema de Lewis Carroll "The Hunting of the Snark" está oculto. Se leu ata aquí, probablemente estea interesado en coñecer a implementación. É bastante sinxelo, pero avisarei de inmediato de que todo está feito en Delphi. Hai dúas razóns para iso: 1. Creo que Delphi é unha boa lingua; 2. Este programa naceu no proceso de elaboración dun curso sobre os fundamentos da visión por ordenador, e os rapaces aos que lles estou a impartir este curso aínda non coñecen outra cousa que non sexa Delphi. Para aqueles que non estean familiarizados coa sintaxe, hai que explicar unha cousa: shl x é un desprazamento bit a bit á esquerda por x, shr x é un desprazamento bit bit á dereita por x.
Supoñemos que estamos escribindo texto almacenado nunha cadea no contedor e substituíndo os dous bytes inferiores:
Código de gravación:
para i:=1 to length(str) do
comezar
l1:=byte(str[i]) shr 6;
l2:=byte(str[i]) shl 2; l2:=l2 shr 6;
l3:=byte(str[i]) shl 4; l3:=l3 shr 6;
l4:=byte(str[i]) shl 6; l4:=l4 shr 6;
f.ReadBuffer(tmp,1);
f.Posición:=f.Posición-1;
tmp:=((tmp shr 2) shl 2)+l1;
f.WriteBuffer(tmp,1);
f.ReadBuffer(tmp,1);
f.Posición:=f.Posición-1;
tmp:=((tmp shr 2) shl 2)+l2;
f.WriteBuffer(tmp,1);
f.ReadBuffer(tmp,1);
f.Posición:=f.Posición-1;
tmp:=((tmp shr 2) shl 2)+l3;
f.WriteBuffer(tmp,1);
f.ReadBuffer(tmp,1);
f.Posición:=f.Posición-1;
tmp:=((tmp shr 2) shl 2)+l4;
f.WriteBuffer(tmp,1);
end;
código para ler:
for i:=1 to MsgSize do
comezar
f.ReadBuffer(tmp,1);
l1:=tmp shl 6;
f.ReadBuffer(tmp,1);
l2:=tmp shl 6; l2:=l2 shr 2;
f.ReadBuffer(tmp,1);
l3:=tmp shl 6; l3:=l3 shr 4;
f.ReadBuffer(tmp,1);
l4:=tmp shl 6; l4:=l4 shr 6;
str:=str+char(l1+l2+l3+l4);
end;
Ben, para os realmente preguiceiros...
Grazas.
Fonte: www.habr.com