<---------------------------------------------------------------------------->
<-    __   ___   _     ----->>---- Nascondere dati in un file JPG ----<<----->
<-   /  \ |   \ | | /\ ------------------------------------------------------>
<-  / /\ \| |\ \| |/ / --- Autore: --------------- ORK ---------------------->
<- / /__\ \    /|   /  ----Contatti: ------------- orkmail@katamail.com ----->
<- \______/ |\ \| | \  ------------------------------------------------------>
<---------|_| \_\_|\_\ ------------------------------------------------------>
<---------------------------------------------------------------------------->

Indice:

0 - Introduzione
1 - Il formato di un file JPG
2 - L'idea
3 - L'implementazione
4 - I possibili impieghi
5 - Riferimenti

0 - Introduzione
----------------
Leggendo l'articolo di valv{0} sul numero 9 di BFi mi e' tornata in mente 
un'idea che mi era passata per la testa un po' di tempo fa.

Fondamentalmente il problema e' sempre quello: come comunicare dati a
qualcuno in modo insospettabile e con il minimo rischio di essere scoperti???
L'idea ce l'ha data valv{0} nel suo articolo (in realta' io ci stavo pensando
da un po' di tempo), ovvero nascondere i dati all'interno di qualcosa di
insospettabile... e cosa puo' essere piu' insospettabile delle foto della
cresima di vostro fratello, scattate con la vostra macchina digitale??? 

Come avrete capito, quello che sto proponendo e' inserire dei dati all'interno
di files di immagini, in particolare all'interno di files JPG.
La scelta di usare i files JPG per nascondere dei dati non e' stata presa
casualmente. I files JPG negli ultimi anni hanno visto una diffusione 
altissima, infatti li si puo' trovare dovunque, partendo dalla maggior parte 
dei siti web, per arrivare agli album fotografici digitali. Sicuramente se 
provate a lanciare il seguente comando

$ find / -name *.jpg

nei vostri computer di casa salteranno fuori diverse centinaia di files
(meglio sorvolare su che immagini sono :)
Percio' per il principio che le cose si nascondono meglio nella confusione e
all'interno di altre cose che non attirano l'attenzione i files JPG mi sono 
sembrati la scelta migliore. 
Come ha detto valv{0} nel suo articolo, comunque, la maggior parte dei formati
complessi puo' essere usato come cavallo di Troia :)

1 - Il formato di un file JPG
-----------------------------
I files JPG sono formati da un certo numero di segmenti, ognuno dei quali puo'
essere lungo al massimo 65535 (2^16) Byte ed inizia con un marcatore. Ogni 
marcatore e' formato da 2 Byte, il primo sempre con valore 0xFF ed il secondo
con un valore compreso tra 0x01 e 0xFE. Il secondo byte specifica il tipo di 
marcatore. Se il segmento contiene dei dati i 2 Byte che seguono il marcatore
indicano la grandezza dei dati. Se, invece, il segmento non contiene dati dopo
il marcatore comincia subito il segmento successivo.

Ogni segmento percio' ha la seguente struttura:
 
[FFxx][nnnn][dati]
 ^     ^     ^
 |     |     Dati (nnnn Byte - 2)                           ) Parti 
 |     Intero contenente la lunghezza dei dati + 2 (2 Byte) ) Facoltative
 Marcatore (2 Byte) 

Si noti che il numero contenente la grandezza dai dati e' memorizzato con la
notazione Bin Endian, e non Little Endian come si e' abituati nei sistemi x86.
 
Tutti i files JPG iniziano con un segmento senza dati identificato dal
marcatore FFD8 e terminano con un segmento sempre senza dati identificato dal
marcatore FFD9. Tra questi 2 segmenti si possono trovare un numero qualsiasi 
di altri segmenti. 

Per capire meglio si prenda in esempio la seguente rappresentazione
esadecimale (parziale) di un file JPG. Come si puo' vedere i primi 2 byte
sono esattamente il marcatore di inizio immagine FFD8. Siccome questo 
marcatore non prevede dati aggiuntivi per il segmento i seguenti 2 Byte
dovranno essere per forza il marcatore di un nuovo segmento. Ed infatti e' 
proprio cosi', il segmento seguente e' identificato dal marcatore FFE0.
Siccome questo marcatore prevede dati, i seguenti 2 Byte identificano la
grandezza della parte dati del segmento.
A questo punto per sapere a che indirizzo inizia il segmento successivo basta
sommare all'indirizzo del Byte successivo al marcatore la grandezza della
parte dati, quindi 0x00000004 + 0x0010 = 0x00000014. A questo indirizzo 
infatti si trova proprio FFED che e' un marcatore valido. Gli ultimi 2 Byte
del file sono FFD9 ovvero il marcatore che identifica la fine dell'immagine.

00000000 FFD8 FFE0 0010 4A46 4946 0001 0201 012C ......JFIF.....,
00000010 012C 0000 FFED 00AA 5068 6F74 6F73 686F .,......Photosho
00000020 7020 332E 3000 3842 494D 03ED 0000 0000 p 3.0.8BIM......
00000030 0010 012B FFD9 0002 0002 012B FFD9 0002 ...+.......+....
00000040 0002 3842 494D 03F3 0000 0000 0008 0000 ..8BIM..........
00000050 0000 0000 0000 3842 494D 2710 0000 0000 ......8BIM'.....
00000060 000A 0001 0000 0000 0000 0002 3842 494D ............8BIM
00000070 03F4 0000 0000 0012 0035 0000 0001 002D .........5.....-
...
...
...
00006780 E8DF 87EC D37C 8B6B 5F6F E1EB 5DF1 4D07 .....|.k_o..].M.
00006790 D7F5 053A 573A 469D CFD0 4AF5 A60D DF3F ...:W:F...J....?
000067A0 FFD9                                    ..

In realta' le cose sono un po' piu' complicate, ma per la comprensione e la
realizzazione di quello che voglio proporre non serve sapere di piu'.

2 - L'idea
----------
L'idea che mi e' venuta per nascondere i dati e' molto semplice.
Ogni immagine comincia con il marcatore FFD8 e termina con il marcatore FFD9.
Tutti gli eventuali dati che seguono quest'ultimo marcatore vengono ignorati
dai browser o dai programmi di gestione di immagini in quanto l'immagine e' 
gia' terminata. Quindi un ottimo posto dove nascondere i dati e' proprio la 
parte finale del file. 

Per provare che il tutto non crea problemi ai programmi di gestione di 
immagini provate a lanciare un comando del genere

$cat trash >> image.jpg

e poi provate ad aprire l'immagine. Non noterete niente di strano.
Se al posto di accodare trash si accodasse un file contenente dati
significativi (ovviamente criptati... la prudenza non e' mai troppa) si
otterrebbe un file JPG perfettamente funzionante, contenente i nostri dati.
Per la maggior parte della gente questa sembrera' un'immagine normalissima, 
mentre per quelli che invece conoscono il segreto questa immagine acquistera'
un valore particolare.

Di seguito riporto i listati di due programmini pseudo-idioti che si occupano
rispettivamente di criptare e fondere un file contenente dei dati con un file
JPG e di estrarre e decriptare i dati precedentemente inseriti.

Breve descrizione di JPG-Fusion.c
Richiede in input 3 nomi di files: il nome del file JPG, il nome del file
contenente i dati da nascondere e il nome di file che verra' creato.
Il programma banalmente copia il contenuto del file JPG nel nuovo file, cripta
il file di dati e lo accoda sempre al nuovo file creato.
Come algoritmo di criptazione e' stato usato un algoritmo a chiave simmetrica.
La chiave di 16 Byte viene creata prendendo 16 Byte casuali del file JPG. I
dati vengono criptati facendo lo XOR tra essi e la chiave. Viene sfruttato il
fatto che A XOR B = C e C XOR B = A.
Il programma restituisce 2 numeri che sono necessari a JPG-Split.c per 
recuperare i dati. Il primo numero non e' altro che la grandezza del file JPG,
sapendo questo ovviamente si sa dove comincia il file dati. Il secondo numero 
invece e' il numero di Byte del file JPG da cui si comincia a prelevare la 
chiave per criptare.

Possibili Miglioramenti: 
- Sarebbe possibile senza troppi sforzi inserire anche il nome del file di
  dati all'interno del file di Output. Per il momento il nome del file viene
  perso, lo si deve infatti fornire in input a JPG-Split.
- Volendo si potrebbe cambiare algoritmo di criptazione in uno a chiave 
  pubblica e privata.
- Si potrebbe aggiungere alla fine del file creato il marcatore di fine
  immagine (FFD9) cosi' che il file possa sembrare corretto ad un'analisi
  superficiale.

Breve descrizione di JPG-Split.c
Richiede in input 4 parametri: il nome del file da cui prelevare i dati, il 
nome del file da creare, la lunghezza del file JPG e il numero del Byte da
cui iniziare a creare la chiave per decriptare i dati.
Il programma banalmente estrae i dati, li decripta e li salva sul file.

Possibili Miglioramenti: 
- Sarebbe possibile trovare in maniera automatica la lunghezza del file JPG
  in base alla posizione del marcatore FFD9.

3 - L'implementazione
---------------------
<-|jpg/JPG-Fusion.c |->
/*
<---------------------------------------------------------------------------->
<-    __   ___   _       ----->>----          JPG-Fusion.c          ----<<--->
<-   /  \ |   \ | | /\   ---                                                ->
<-  / /\ \| |\ \| |/ /   ---         Sorgente allegato all'articolo         ->  
<- / /__\ \    /|   /    ---        "Nascondere dati in un file JPG"        ->
<- \______/ |\ \| | \    ---                                                ->
<-        |_| \_\_|\_\   ---------------------------------------------------->
<---------------------------------------------------------------------------->
*/

#include 
#include 

void cript (char *, char *, int);

main(int argc, char *argv[]) 
{
FILE *file1, *file2, *file3;
char *tutto1, *tutto2, pad[16];
long file1lung, file2lung;
int startpad;
time_t secondi;

if (argc<4)
 {
   printf("USO: %s file1 file2 file3:\n",argv[0]);
   printf("file1 - file JPG\n");
   printf("file2 - file da nascondere\n");
   printf("file3 - nome del file di Output\n");
   exit(-1);
 }


file1 = fopen(argv[1], "r");
if (file1 == NULL) 
 {
   printf("Errore di apertura nel file %s\n",argv[1]);
   exit(-1);
 }

file2 = fopen(argv[2], "r");
if (file2 == NULL) 
 {
   printf("Errore di apertura nel file %s\n",argv[2]);
   exit(-1);
 }

file3 = fopen(argv[3], "w");
if (file3 == NULL) 
 {
   printf("Errore di apertura nel file %s\n",argv[3]);
   exit(-1);
 }

/* Trova la lunghezza dei 2 files */

fseek(file1, 0, SEEK_END);
file1lung = ftell(file1);
rewind(file1);

fseek(file2, 0, SEEK_END);
file2lung = ftell(file2);
rewind(file2);

/* Legge il contenuto dei 2 files */

tutto1 = (char *) malloc(file1lung);
fread(tutto1, 1, file1lung, file1);

tutto2 = (char *) malloc(file2lung);
fread(tutto2, 1, file2lung, file2);

/* Crea la chiave che servira' per criptare i dati */

secondi = time(NULL);
srand(secondi);
startpad = rand();
startpad= startpad%(file1lung-16);
strncpy(pad, tutto1+startpad, 16);

/* Cripta i dati */

cript(tutto2, pad, file2lung);

/* Crea il file scrivendo prima il file JPG e poi i dati criptati */

fwrite (tutto1, 1, file1lung, file3);
fwrite (tutto2, 1, file2lung, file3);

printf("Dati necessari per estrarre i dati:\n\nByte: %d\nPad : %d\n", file1lung, startpad);

fclose(file1);
fclose(file2);
fclose(file3);

}

void cript (char *buff, char *pad, int lung)
{
int h;

for (h=0;h

<-| jpg/JPG-Split.c |->
/*
<---------------------------------------------------------------------------->
<-    __   ___   _       ----->>----          JPG-Split.c           ----<<--->
<-   /  \ |   \ | | /\   ---                                                ->
<-  / /\ \| |\ \| |/ /   ---         Sorgente allegato all'articolo         ->  
<- / /__\ \    /|   /    ---        "Nascondere dati in un file JPG"        ->
<- \______/ |\ \| | \    ---                                                ->
<-        |_| \_\_|\_\   ---------------------------------------------------->
<---------------------------------------------------------------------------->
*/
#include 

void decript (char *, char *, int);

main(int argc, char *argv[]) 
{
FILE *file1, *file2;
char *tutto, pad[16];
long file1lung, file2lung, file3lung;

if (argc<5)
 {
   printf("USO: %s file1 file2 num:\n",argv[0]);
   printf("file1 - file JPG\n");
   printf("file2 - nome del file di Output\n");
   printf("Bytes - numero di byte dell'immagine originale\n");
   printf("Pad   - numero iniziale del pad\n");
   exit(-1);
 }

file1 = fopen(argv[1], "r");
if (file1 == NULL) 
 {
   printf("Errore di apertura nel file %s\n",argv[1]);
   exit(-1);
 }

file2 = fopen(argv[2], "w");
if (file2 == NULL) 
 {
   printf("Errore di apertura nel file %s\n",argv[2]);
   exit(-1);
 }

/* Trova la lunghezza dei 3 files */

fseek(file1, 0, SEEK_END);
file1lung = ftell(file1);
file2lung = atoi(argv[3]);
file3lung = file1lung-file2lung;

if (file2lung>file1lung) 
 {
   printf("Parametro \"Bytes\" sbagliato\n");
   exit(-1);
 }

/* Legge solo la parte dei dati criptati */

rewind(file1);
fseek(file1, file2lung, SEEK_CUR);
tutto = (char *) malloc(file3lung);
fread(tutto, 1, file3lung, file1);

/* Crea la chiave che servira' per decriptare i dati */

rewind(file1);
fseek(file1, atoi(argv[4]), SEEK_CUR);
fread(pad, 1, 16, file1);

/* Decripta i dati */

decript(tutto, pad, file3lung);

/* Salva i dati sul file  */

fwrite (tutto, 1, file3lung, file2);

fclose(file1);
fclose(file2);

}

void decript (char *buff, char *pad, int lung)
{
int h;

for (h=0;h

4 - I possibili impieghi
------------------------
Gli impieghi possibili di questa tecnica sono limitati solamente dalla
fantasia di chi ne fa uso. Alcuni suggerimenti possono essere i seguenti.
Immaginate di avere la necessita' di rendere disponibili dei dati attraverso 
Internet, in modo da poterli recuperare dovunque vi troviate. Questi dati
pero' sono altamente confidenziali e non volete che altre persone, oltre a voi
e ai vostri fidatissimi amici, ne vengano in possesso. Quale miglior 
nascondiglio potreste trovare rispetto alla sezione "Foto della gita in 
montagna" della vostra Home Page??? Sicuramente questa sara' la sezione piu'
noiosa e meno visitata del vostro sito e sicuramente nessuno pensera' che una
delle 100 foto di voi con la vostra ragazza che camminate in mezzo alle pecore
contenga una sorpresina :)
Immaginate oppure di dover far avere delle informazioni private ad un vostro 
amico attraverso un supporto fisico (tipo un CD) e sapete che nel tragitto
probabilmente passera' per mani indiscrete. Cosa c'e' meglio di una bella 
directory con un migliaio di foto XXX???
Altra applicazione possibile si puo' avere nel caso in cui si abbia la 
sensazione di avere la casella di posta elettronica controllata. Invece
di cambiare indirizzo e-mail o cominciare a criptare le mail (cose che 
darebbero nell'occhio) basta accordarsi con l'interlocutore per lo scrivere 
cose semi-inutili nel corpo della mail e allegare un'immagine che in realta'
avra' lo scopo di contenere le informazioni importanti.

Chiaramente questa tecnica ha anche pesanti limiti, non e' possibili infatti 
distribuire grosse quantita' di dati. Sicuramente uno che si trova di fronte
ad un file JPG di 50 MB si insospettisce come minimo.

5 - Riferimenti
---------------
[1] - "CRYX's note about the JPEG decoding algorithm" 
       Writed by Cristi Cuturicu (cccrx@kermit.cs.pub.ro)

<---------------------------------------------------------------------------->
<------------------- ** Information wants to be Free !! ** ------------------->
<---------------------------------------------------------------------------->
<------------------------------------------------------------------ By ORK -->
<---------------------------------------------------------------------------->