università politecnica delle marche facoltà di ingegneria

Transcript

università politecnica delle marche facoltà di ingegneria
UNIVERSITÀ POLITECNICA DELLE MARCHE
FACOLTÀ DI INGEGNERIA
Corso di Laurea Triennale in
Ingegneria Elettronica
GESTIONE DELLA SICUREZZA DI UN PORTALE WEB
MEDIANTE CONTROLLO CONDIZIONATO DEGLI
ACCESSI E CRIPTAZIONE DEI DOCUMENTI DEPOSITATI
Relatore:
Prof. Aldo Franco Dragoni
Anno Accademico 2006/2007
Rapporto Finale di:
Alessandro Rossi
INDICE
INTRODUZIONE
1
CAPITOLO 1
2
1.1 La sicurezza
1.1.1 La sicurezza su Internet
3
3
1.2 Aspetti giuridici sulla sicurezza
1.2.1 Un quadro comunitario per le firme elettroniche
1.2.2 Il nuovo “testo unico sulla privacy”
4
4
5
1.3 La crittografia
1.3.1 La crittografia simmetrica
1.3.1.1 Cifratura a blocchi
1.3.1.2 Cifratura a flusso
1.3.1.3 I principali algoritmi a chiave simmetrica
1.3.2 La crittografia asimmetrica
1.3.2.1 Algoritmi a chiave di cifratura pubblica
1.3.2.2 Algoritmi a chiave di decifratura pubblica
1.3.2.3 Algoritmi ibridi
1.3.2.4 I principali algoritmi a chiave asimmetrica
1.3.3 Stima sulla sicurezza degli algoritmi crittografici
1.3.4 La funzione di hash
1.3.4.1 I principali algoritmi per la funzione di Hash
1.3.4.2 Stima sulla sicurezza della funzione di Hash
1.3.5 La firma digitale
6
8
9
10
10
11
12
13
14
15
16
18
19
19
20
1.4 La public key infrastructure
1.4.1 Il certificato a chiave pubblica
1.4.1.1 Richiesta, ottenimento, durata e revoca di un certificato
1.4.2 Autorità di certificazione
1.4.3. Standard X.509
1.4.4 Standard PKCS
23
23
25
27
28
30
I
1.5 La steganografia
1.5.1 Steganografia iniettiva e generativa
1.5.2 Modelli steganografici
1.5.2.1 Steganografia sostitutiva
1.5.2.2 Steganografia selettiva
1.5.2.3 Steganografia costruttiva
1.5.3 La steganografia applicata ai files digitali
1.5.3.1 Steganografia dei files Bitmap
1.5.3.2 Steganografia dei files Wave
1.5.3.3 Steganografia dei files compressi
1.5.4 Stima sulla sicurezza degli algoritmi steganografici
32
33
33
33
34
35
35
36
41
44
47
1.6 I protocolli web
1.6.1 Il protocollo http
1.6.2 Il protocollo https
49
49
54
CAPITOLO 2
61
2.1 La Phi.d’αlpha s.r.l.
62
2.2 Descrizione del progetto
63
CAPITOLO 3
64
3.1 Analisi delle specifiche
65
3.2 Modellazione dei pericoli
65
3.3 Anali delle contromisure
3.3.1 Uso insicuro della crittografia
3.3.2 Controlli di accesso insufficienti
3.3.3 Iniezioni di comandi
3.3.4 Gestione insicura delle sessioni
3.3.5 Gestione inadeguata degli errori
68
69
70
72
72
72
3.4 Implementazione del software lato client
3.4.1 Software per la gestione della crittografia
3.4.2 Software per la gestione della steganografia
73
73
75
3.5 Implementazione dell’applicazione web
3.5.1 Login e logout degli utenti
3.5.2 Upload e download dei files
80
81
83
II
CONCLUSIONI E SVILUPPI FUTURI
87
APPENDICE
89
Codice VB.NET del software di crittografia
Codice VB.NET del software di steganografia
Codice ASP del software web
BIBLIOGRAFIA
90
96
104
120
III
INTRODUZIONE
Nel settembre del 1969, negli USA, l’ARPA (Advanced Research Projects
Agency), sotto il controllo del Dipartimento della Difesa degli Stati Uniti, diede
vita ad una rete di computer: ARPANET.
Negli anni successivi il progetto subì un enorme ampliamento fino alla
definizione del protocollo TCP/IP che segnò l’inizio effettivo di quello che oggi
viene definita “Internet”.
Quando il protocollo TCP/IP fu progettato, la rete collegava tra loro università e
laboratori di ricerca ed era uno strumento per la condivisione delle risorse e delle
informazioni da parte della comunità scientifica, in virtù di ciò gli utenti della rete
erano una comunità ristretta e fidata, e per questo non si fece particolare
attenzione alle problematiche relative alla sicurezza.
Oggi Internet è diventato uno strumento di comunicazione globale, quindi la
situazione è molto diversa e il tema della sicurezza in rete assume una grande
importanza, basti pensare che anche la giurisprudenza italiana con il D.L. 30
giugno 2003, n. 196 fissa delle regole concrete sul trattamento dei dati ai fini della
sicurezza e della privacy e sancisce regole da applicarsi alla trasmissione dei
documenti informatici e alla firma digitale con il D.P.R. 10 novembre 1997, n.
513.
In questa tesi verrà progettato un portale web in cui viene garantito un elevato
grado di sicurezza mediante il controllo condizionato degli accessi e la criptazione
dei documenti depositati.
Per lo scambio delle chiavi segrete, necessarie per l’utilizzo di tecniche di
crittografia, verrà introdotto un approccio all’uso della steganografia.
Per la realizzazione del progetto si utilizzeranno diversi linguaggi di
programmazione:
• Visual Basic Script;
• Java Script;
• ASP;
• Visual Basic .NET.
Le pagine web verranno create tramite il linguaggio di mark-up HTML.
-1-
CAPITOLO 1
In questo capitolo verrà descritto che cosa si intende per sicurezza su Internet,
dopodichè verranno forniti dei cenni sulla crittografia, sulle public key
infrastructure, sulla steganografia e sui protocolli per il web.
-2-
1.1 La sicurezza
Che cosa si intende con il termine sicurezza?
Se consultiamo il dizionario Treccani (www.treccani.it) vediamo che per
sicurezza si intende:
“il fatto di essere sicuro, come condizione che rende e fa sentire d’essere esente
da pericoli, o che dà la possibilità di prevenire, eliminare o rendere meno gravi
danni, rischi, difficoltà, evenienze spiacevoli, e sim”.
1.1.1 La sicurezza su Internet
Per quanto riguarda Internet, o una qual si voglia rete di computer, tale termine
deve essere usato per commisurare il grado di immunità ai rischi che possono
presentarsi, in quanto una rete completamente sicura non esiste e forse non
esisterà mai.
Per garantire la sicurezza di una rete, ci si trova a dovere fronteggiare aspetti e
problematiche diverse, per risolvere le quali si usano approcci differenti.
I principali servizi per la tutela della sicurezza sono i seguenti:
• autenticazione d’identità: garantire l'identità degli interlocutori;
• autenticità dei dati: garantire i dati identificativi del mittente;
• riservatezza: impedire letture non autorizzate, garantendo la segretezza
del contenuto della comunicazione;
• integrità: garantire che dati e informazioni non subiscano modifiche non
autorizzate, in particolare durante il transito dal mittente al destinatario;
• non ripudio: impedire che le parti neghino di aver inviato (o ricevuto) dati
che hanno effettivamente inviato (o ricevuto);
• autorizzazione: permettere l'accesso a determinate risorse o servizi solo a
chi è autorizzato a farlo;
• disponibilità: garantire l'operatività di un servizio e la sua fruibilità da
parte degli utenti autorizzati, evitando che azioni di disturbo possano
compromettere la disponibilità del sistema.
Gli attacchi alla sicurezza di un sistema possono essere dunque molteplici,
colpendo l'uno o l'altro di questi aspetti.
Un intruso può ad esempio intercettare dei dati (colpendo quindi la riservatezza),
modificare le informazioni in transito (integrità), sostituirsi ad uno degli
interlocutori (autenticazione), rendere indisponibile un servizio.
Un attacco classico è il cosiddetto “man-in-the-middle” (MITM), in cui un intruso
si inserisce nella comunicazione impersonando ciascun interlocutore agli occhi
dell'altro, e può così leggere tutti i dati scambiati, modificarli, inserirne altri.
-3-
1.2 Aspetti giuridici sulla sicurezza
Dimostrare l’autenticità di un documento, sia esso giuridico o privato, dipende dal
fatto di poter palesare la sua inalterabilità o delle eventuali tracce che hanno
portato ad una modifica.
Per quanto riguarda i documenti cartacei questo avviene tramite l’apposizione di
una firma autografa.
Con l’avvento e la successiva espansione dei sistemi informatici, la
giurisprudenza si è trovata di fronte al problema di dover produrre una normativa
capace di poter efficacemente convalidare l’autenticità di un documento.
Un altro punto focale che i legislatori hanno dovuto risolvere è stato quello di
sancire delle regole affinché sia tutelato il tema della riservatezza.
1.2.1 Un quadro comunitario per le firme elettroniche
In questo paragrafo verrà descritto l’iter legislativo che ha portato
all’equiparazione del documento informatico firmato digitalmente alla scrittura
privata.
In materia di formazione, archiviazione e trasmissione di atti, documenti e
contratti in forma elettronica, fino al 1997, esisteva un quadro normativo alquanto
frammentario e generico.
Il 15 marzo 1997 con la legge n. 59, detta legge Bassanini, il legislatore italiano
ha realizzato una vera e propria rivoluzione di diritto pubblico e di diritto privato
introducendo nell'ordinamento la nozione di documento informatico e telematico,
provvedendo a dettare una specifica disciplina in materia.
All'art. 15, secondo comma, dispone “gli atti, i dati e i documenti formati dalla
pubblica amministrazione e dai privati con strumenti informatici e telematici, i
contratti stipulati nelle medesime forme, nonché la loro archiviazione e
trasmissione con strumenti informatici, sono validi e rilevanti a tutti gli effetti di
legge”, e rinvia a successivi regolamenti la precisazione sulle modalità di
applicazione della legge, sia per la Pubblica Amministrazione sia per i privati.
Uno di questi regolamenti è il D.P.R. n. 513 del 10 novembre 1997, finalizzato
alla creazione di un sistema di firma sicura, che disciplina i criteri e le modalità
per la formazione, l'archiviazione e la trasmissione di documenti con strumenti
informatici e telematici.
La caratteristica principale del decreto è costituita dalla definizione di documento
informatico e dalla precisa determinazione della sua validità.
Il D.P.R. n. 513 stabilisce indirettamente l’equivalenza tra documento informatico
e documento cartaceo, infatti l’equiparazione degli effetti probatori del primo
rispetto al secondo è subordinata alla conformità del documento (informatico),
alle disposizioni del regolamento e delle regole tecniche che sono state emanate
con D.P.C.M. 8 febbraio 1999.
-4-
Le norme di questo decreto sono state successivamente incorporate nel D.P.R. n.
445 del 28 dicembre 2000 detto “testo unico sulla documentazione
amministrativa”.
L'ultima tappa è rappresentata dal D.Lgs. n. 10 del 23 gennaio 2002, attuativo
della direttiva n. 1999/93/CE, relativa a “un quadro comunitario per le firme
elettroniche”, il quale ha completamente stravolto il sistema esistente affiancando
la firma elettronica a quella digitale.
1.2.2 Il nuovo “testo unico sulla privacy”
Come in precedenza accennato, anche la giurisprudenza italiana, ha disciplinato, il
tema della sicurezza nel trattamento dei dati.
In questo paragrafo verrà decritto il D.L. 30 giugno 2003, n. 196, entrato in vigore
il 1 Gennaio 2004 sostituendo la legge 675/1996 e successivi decreti legislativi,
detto anche “testo unico sulla privacy”.
Tale legge si rivolge a tutti coloro che trattano dati personali di clienti, fornitori,
dipendenti, utenti, pazienti, colleghi, soci o associati. Quindi vengono coinvolte
aziende, liberi professionisti, amministrazioni pubbliche, associazioni e
cooperative.
La legge sancisce una serie di regole e procedure gestionali rivolte a garantire la
sicurezza dei dati personali all’interno delle aziende, attraverso l’adozione di
requisiti minimi di sicurezza che dovranno essere utilizzati nell'espletamento delle
suddette attività.
Con scadenza ultima al 31 Dicembre 2004 tutte le aziende dovranno adeguarsi
alle disposizioni imposte dal D.L. 30 giugno 2003, n. 196 e redigere il Documento
Programmatico sulla Sicurezza in cui dovranno essere riassunte le misure a cui
saranno vincolati ad adottare per garantire la sicurezza dei dati.
Per mancato adempimento di tale obbligo sono previste sanzioni pecuniarie e
penali, con multe che possono arrivare fino 60.000 Euro e sanzioni penali che
possono raggiungere la pena di tre anni di reclusione.
Per adeguarsi alle disposizioni del nuovo codice sulla privacy, le attività
interessate dovranno, adottare una modulistica, individuare i soggetti incaricati del
trattamento dei dati e verificare l’adeguamento dei propri sistemi informatici
secondo quanto previsto dall'Allegato B (Disciplinare tecnico in materia di misure
minime di sicurezza).
Paul Baran in un rapporto per la Rand Corporation sancisce l’importanza dell’uso
delle pratiche di sicurezza, anche se non imposte da un sistema giuridico, dicendo:
"...non aspettiamoci che il contributo dei giuristi possa sostituire una buona
progettazione tecnica, anche se non si volesse tenere conto del ritardo sociale dei
procedimenti legislativi e giudiziari, gli specifici problemi del mondo dei
computer si collocano in una dimensione che ad essi, ai giuristi, sfugge
completamente...".
-5-
1.3 La crittografia
L’etimologia del termine “crittografia” è data dall’associazione di due parole di
origine greca: “criptos” che significa nascondere, e “grafèin” che significa
scrivere, da cui “scrivere di nascosto”.
L’arte di scrivere messaggi segreti che possano essere letti e compresi solo dal
destinatario risale alla più remota antichità, già la Bibbia parla di un codice
segreto per scrivere il nome di Babele, il codice “Atbash”, esso consisteva
nell’inversione delle lettere alfabetiche, ovvero la “a” diventava “z”, la “b”
diventava “y” e così via, fino a giungere ai tempi più recenti in cui durante la
seconda guerra mondiale i tedeschi avevano ideato “Enigma” un algoritmo
simmetrico per trasmettere in modalità protetta i propri messaggi, in cui ogni
mese le chiavi venivano consegnate ai cifratori scritte in un foglio con inchiostro
solubile che doveva essere custodito gelosamente dagli stessi.
Figura 1a. Cifrario Atbash
Figura 1b. Soldati tedeschi che lavorano
su Enigma
Per secoli quest’arte è stata appannaggio quasi esclusivo dei militari e dei
diplomatici ed i metodi crittografici erano specifici per l’invio di messaggi
materiali che venivano affidati ai corrieri.
In contrapposizione e non solo, nasce contemporaneamente alla crittografia una
nuova disciplina che prende il nome di “crittoanalisi” che studia come recuperare
il contenuto di un messaggio cifrato senza disporre delle informazioni necessarie
alla decifratura.
La crittografia e la crittoanalisi si basano su una branca della matematica che
prende il nome di “crittologia”.
L’evoluzione delle tecniche crittografiche ha avuto una svolta quando si è deciso
di rendere pubblici gli algoritmi di cifratura e decifratura dei messaggi; infatti la
-6-
pubblicazione degli algoritmi ha reso possibile lo studio da parte dei crittoanalisti,
consentendo di scoprirne eventuali debolezze e quindi di selezionare gli algoritmi
più sicuri, e ha reso possibile la fruizione degli stessi a chiunque, anche a coloro
inesperti di scienza crittologica.
La crittografia moderna è in grado di garantire i seguenti servizi di sicurezza:
• autenticazione d’identità: verifica dell’identità di una o entrambe le parti
coinvolte in una comunicazione;
• integrità dei dati: il documento trasmesso deve contenere tutte le
informazioni in esso presenti sin dalla redazione, con la possibilità di
verificare le eventuali alterazioni, intenzionali o meno, che i dati possono
aver subito attraversando un canale insicuro;
• autenticità dei dati: verifica dell’effettiva identità del mittente;
• non ripudio: impossibilità, da parte sia del mittente che del destinatario,
di negare l’avvenuto scambio di dati.
La comunicazione fra due entità, “mittente” e “destinatario”, può avvenire in due
modi:
• comunicazione in modo chiaro:
Figura 2. Schema di principio di una comunicazione in chiaro fra due entità
Il messaggio viene inviato dal mittente verso il destinatario attraverso il canale in
modo trasparente (privo di cifratura). Lungo il canale il messaggio è visibile a tutti
e questo va a compromettere la sicurezza della trasmissione
• comunicazione in modo cifrato:
Figura 3. Schema di principio di una comunicazione cifrata fra due entità
-7-
Il messaggio in chiaro viene innanzitutto cifrato per mezzo di una chiave dal
mittente, il quale lo trasmette attraverso il canale al destinatario. Una volta giunto
a quest’ultimo, il destinatario tramite l’apposita chiave decifrerà il messaggio,
ottenendo il messaggio in chiaro originale. Lungo il canale il messaggio è visibile
a tutti ma questo non compromette la sicurezza della trasmissione in quanto,
essendo cifrato, solo chi è in possesso dell’apposita chiave è in grado di
comprenderne il significato.
1.3.1 La crittografia simmetrica
La crittografia simmetrica utilizza algoritmi che si avvalgono di un’unica chiave
sia per le operazioni di cifratura sia per quelle di decifratura, per questo viene
detta anche a chiave segreta.
Lo schema di principio di una comunicazione con crittografia a chiave simmetrica
è il seguente:
Figura 4. Schema di principio di una comunicazione cifrata con crittografia a chiave simmetrica
Il mittente prima dell’invio del messaggio genera una chiave con cui cifra il
messaggio e lo manda al destinatario tramite un canale insicuro; quindi chiunque
può leggere il messaggio ma non avendo la chiave di decodifica non può
interpretarlo. La chiave che ha generato il mittente e che serve al destinatario per
decifrare il messaggio viene mandata al destinatario attraverso un canale sicuro in
modo tale che nessuno possa intercettarla e leggerla.
La sicurezza di questa tecnica crittografica è garantita fintantoché la chiave
rimane a conoscenza dei due soli interlocutori.
-8-
Il difetto principale della crittografia simmetrica sta nel fatto che anche se si
adotta un canale sicuro, la trasmissione della chiave può essere comunque
intercettata. Nel caso in cui un terzo interlocutore, non desiderato, venisse in
possesso della chiave, andrebbe a provocare il decadimento di alcuni servizi di
sicurezza che invece la trasmissione criptata dovrebbe garantire, quindi
verrebbero meno i requisiti di segretezza, di integrità del messaggio e di
autenticazione del mittente, infatti la compromissione del terzo interlocutore in
possesso della chiave, potrebbe consistere nell’intercettazione del messaggio
cifrato, nella modifica e cifratura di uno nuovo, senza che il destinatario si
accorga di nulla.
Un altro svantaggio della crittografia simmetrica riguarda il fatto che ogni utente
deve disporre di una chiave diversa per ogni interlocutore con cui voglia
comunicare, sapendo che il numero di chiavi cresce con legge quadratica, nella
nostra situazione, ponendo n come numero di presunti interlocutori, un utente si
n ( n − 1)
troverebbe a gestire
chiavi segrete, quindi se il numero di interlocutori è
2
estremamente elevato, l’utente si trova a gestire un’infinità di chiavi.
Gli algoritmi di crittografia simmetrica si possono suddividere in due tipologie in
base alla tecnica utilizzata per la cifratura:
• algoritmi a blocchi: l’operazione di cifratura o decifratura viene effettuata
su gruppi di bit, byte o word di lunghezza finita organizzati in blocco;
• algoritmi a flusso: l’operazione di cifratura o decifratura viene effettuata
sui singoli bit, byte o word.
1.3.1.1 Cifratura a blocchi
Negli algoritmi a blocchi il messaggio da cifrare, o decifrare, viene suddiviso in
blocchi di lunghezza prefissata e l’algoritmo viene applicato ad ognuno di questi
blocchi singolarmente. Visto ciò risulta ovvio che il messaggio debba avere una
lunghezza esattamente multipla della dimensione del blocco, altrimenti si
andrebbe a verificare un errore; per ovviare a questa anomalia si provvede a
riempire l’ultimo blocco con opportuni caratteri di allineamento. Questa
operazione è nota con il termine di “pad”.
Esistono diversi metodi per eseguire il “pad” di un blocco, essi si diversificano in
base alla tipologia di dato che contengono.
Di seguito si elencheranno le metodologie di “pad” più comuni, ma in realtà ne
esistono innumerevoli altre.
Il metodo più semplice è quello di aggiungere zeri fino al raggiungimento della
lunghezza prefissata del blocco; se i dati sono binari si completa il blocco con bit
che sono l’opposto degli ultimi bit costituenti il messaggio; nel caso di caratteri
ASCII si usano byte di riempimento casuali specificando nell’ultimo byte il
carattere ASCII corrispondente al numero di byte aggiunti.
-9-
1.3.1.2 Cifratura a flusso
Negli algoritmi a flusso, il messaggio in chiaro si mostra come uno stream di dati
e l’operazione di cifratura, o decifratura, viene effettuata su ogni singolo bit, byte
o word, in ingresso.
Questa tipologia di algoritmi fa uso di un generatore di bit che produce una
sequenza di bit pseudo-casuale in relazione alla chiave fornita dagli utenti.
Essenziale risulta il generatore pseudo-random, in quanto in fase di cifratura i dati
in ingresso vengono messi in XOR con i dati provenienti dal generatore, questo
per fare in modo che messaggi identici cifrati con la stessa chiave non diano mai
origine a messaggi cifrati uguali.
Gli algoritmi a flusso possono essere suddivisi in due categorie:
• algoritmi autosincronizzanti: in questo tipo di algoritmi il generatore di
numeri pseudo-random prende in ingresso, ad ogni step, anche un certo
numero di bit cifrati precedentemente, quindi, qualunque sia la chiave
segreta, uno stesso bit, o byte, potrà essere cifrato ogni volta in modo
diverso a seconda delle precedenti informazioni elaborate dal flusso in
ingresso.
• algoritmi sincroni: in questo tipo di algoritmi, il generatore pseudorandom è completamente indipendente dal flusso di dati in ingresso. Gli
algoritmi sincroni risultano essere molto vantaggiosi su canali di
trasmissioni rumorosi, in quanto riducono la propagazione degli errori, si
pensi per esempio alla trasmissione di un messaggio in un canale
rumoroso. Quando il ricevitore riceverà un bit errato, dovuto alla
rumorosità del canale, l’errore non si ripercuoterà su altri bit, in quanto
non c’è la dipendenza dagli stati precedenti, come avviene negli algoritmi
autosincronizzanti.
1.3.1.3 I principali algoritmi a chiave simmetrica
I principali algoritmi a chiave simmetrica sono:
• DES (Data Encryption Standard): fu sviluppato dalla IBM come
evoluzione dell’algoritmo Lucifer, risalente agli anni ’70. Fu il primo
algoritmo di cifratura a diventare uno standard nazionale negli Stati Uniti
nel 1977. Il DES rientra nella classe dei codici a blocchi, ogni blocco ha la
dimensione di 64 bit e la chiave di cifratura è di 56 bit. Il DES fu violato
per mezzo di un attacco di forza bruta nel 1998, quindi risulta essere poco
robusto per l’utilizzo odierno.
• TDES (Triple DES): è una evoluzione del DES, è così denominato in
quanto utilizza tre chiavi indipendenti in tre diversi passaggi: una cifratura
con la prima chiave, una decifratura con la seconda ed infine un’altra
cifratura con la terza chiave. Il TDES è sicuramente un algoritmo più
complesso e più costoso rispetto al DES, specialmente in termini di burst
time, ma è anche molto più sicuro, infatti non è stato ancora violato.
- 10 -
•
•
IDEA (International Data Encryption Algorithm): fu proposto da due
scienziati svizzeri dello Swiss Federal Institute of Technology di Zurigo in
collaborazione con la Ascom Communications inc.: il Dr. Xuejja. Lai e il
Prof. James. Massey. IDEA rientra nella classe dei codici a blocchi, ogni
blocco ha la dimensione di 64 bit e sfrutta chiavi di lunghezza di 128 bit.
IDEA è generalmente considerato sicuro, poiché sfrutta chiavi di 128 bit.
AES (Advanced Encryption Standard): fu sviluppato dai crittografi
belgi Joan Daemen e Vincent Rijmen, è noto anche come algoritmo di
Rijndael, nome derivato dal nome degli inventori. È stato adottato dalla
National Institute of Standards and Technology (NIST) e dalla US Federal
Information Processing Standard (FIPS) nel novembre 2001. L’AES
rientra nella classe dei codici a blocchi, ogni blocco ha la dimensione di
128 bit e possono essere impiegate chiavi di 128, 192 o anche 256 bit.
L’AES risulta essere un algoritmo molto robusto poiché permette
l’impiego di chiavi di lunghezza fino a 256 bit. L’AES è di facile
implementazione sia hardware che software e le sue richieste di risorse
sono limitate, rendendolo utilizzabile su qualsiasi strumento capace di
eseguire operazioni crittografiche.
1.3.2 La crittografia asimmetrica
Nel 1976 Whitfield Diffie e Martin Hellmann, ricercatori all’università di
Stanford USA, ipotizzarono un nuovo tipo di crittografia radicalmente nuovo. La
loro idea era quella di utilizzare un cifrario asimmetrico, cioè un sistema in cui si
sarebbero dovute usare due chiavi distinte, in cui una era utilizzata per la cifratura
ed una per la decifratura ma la conoscenza di una chiave non permetteva la
generazione dell’altra, nonostante fossero legate da una relazione matematica.
Una delle due chiavi deve rimanere nota al solo possessore e per questo viene
detta chiave privata. L’altra chiave invece può essere resa liberamente nota ed è
utilizzabile da qualsiasi utente necessiti il suo impiego in una comunicazione, per
questo viene detta chiave pubblica. Le due chiavi sono legate matematicamente
tra loro, ma costruite in modo che sia impossibile risalire alla chiave privata
partendo da quella pubblica.
La crittografia asimmetrica incrementa notevolmente il grado di sicurezza rispetto
a quello che si otterrebbe dall’impiego della crittografia simmetrica, in quanto
viene eliminata l’esigenza di scambiare la chiave fra i due utenti.
Nella crittografia asimmetrica un messaggio cifrato con una chiave appartenente
alla coppia chiave privata, chiave pubblica, può essere decifrato solo con una
chiave associata alla coppia.
Per cifrare o decifrare un messaggio si può utilizzare indipendentemente una delle
due chiavi della coppia, quindi l’utilizzo delle chiavi risulta essere completamente
arbitrario ai fini della corretta applicazione dell’algoritmo.
In base all’utilizzo di una o l’altra chiave in fase di cifratura o decifratura si
possono dividere gli algoritmi in due categorie:
- 11 -
•
algoritmi a chiave di cifratura pubblica: impiegano la chiave pubblica
in cifratura e quella privata in decifratura;
• algoritmi a chiave di decifratura pubblica: impiegano la chiave privata
in cifratura e quella pubblica in decifratura.
Una differenza importante con gli algoritmi a chiave simmetrica sta nel fatto che
gli algoritmi a chiave pubblica possono essere implementati solo come algoritmi a
blocchi, in quanto non sarebbe possibile cifrare i dati in ingresso bit a bit.
1.3.2.1 Algoritmi a chiave di cifratura pubblica
Lo schema di principio di una comunicazione con crittografia a chiave di cifratura
pubblica è il seguente:
Figura 5. Schema di funzionamento di un algoritmo a chiave di cifratura pubblica
Prima di analizzare l’effettiva trasmissione del messaggio bisogna analizzare la
tipologia di chiavi di cui sono in possesso il mittente ed il destinatario.
Il destinatario è in possesso di una coppia valida di chiavi: una chiave privata:
K privD ed una chiave pubblica: K pubD . Il destinatario invierà a tutti i suoi
interlocutori la propria chiave pubblica in modo che essi possano effettuare la
cifratura di un messaggio. In questo modo anche il mittente avrà la chiave
pubblica del destinatario.
Il mittente cifra il messaggio utilizzando la chiave pubblica del destinatario, invia
il messaggio attraverso il canale insicuro al destinatario il quale lo riceve e tramite
l’utilizzo della propria chiave privata riesce a decifrarlo.
- 12 -
Il messaggio che passa attraverso il canale insicuro può essere letto da chiunque
ma non avendo la chiave appartenente alla coppia: K privD , K pubD non potrà
interpretarlo, quindi è garantito il servizio di segretezza.
Il difetto fondamentale di questo tipo di algoritmo di cifratura asimmetrica
consiste nel fatto che il destinatario non può essere sicuro dell’effettiva identità
del mittente, in quanto chiunque può procurarsi la sua chiave pubblica e spedirgli
dei messaggi cifrati.
1.3.2.2 Algoritmi a chiave di decifratura pubblica
Lo schema di principio di una comunicazione con crittografia a chiave di
decifratura pubblica è il seguente:
Figura 6. Schema di funzionamento di un algoritmo a chiave di decifratura pubblica
Prima di analizzare l’effettiva trasmissione del messaggio bisogna analizzare la
tipologia di chiavi di cui sono in possesso il mittente ed il destinatario.
Il mittente è in possesso di una coppia valida di chiavi: una chiave privata: K privM
ed una chiave pubblica: K pubM . Il mittente invierà a tutti i suoi interlocutori la
propria chiave pubblica in modo che essi possano effettuare la cifratura di un
messaggio. In questo modo anche il destinatario avrà la chiave pubblica del
mittente.
Il mittente cifra il messaggio utilizzando la propria chiave privata, invia il
messaggio attraverso il canale insicuro al destinatario il quale lo riceve e tramite
l’utilizzo della chiave pubblica del mittente riesce a decifrarlo.
- 13 -
Il messaggio che passa attraverso il canale insicuro può essere letto ed interpretato
da chiunque poiché chiunque può avere la chiave pubblica del mittente, quindi in
questo caso il servizio di segretezza non è garantito.
Il vantaggio fondamentale di questo tipo di algoritmo di cifratura asimmetrica si
rileva nel fatto che il destinatario se riesce a decifrare il messaggio con la chiave
pubblica del mittente è sicuro che il messaggio è stato cifrato da quest’ultimo,
quindi è garantito il servizio di autenticazione d’identità.
Gli algoritmi a chiave di decifratura pubblica trovano largo impiego nei sistemi
che fanno uso della firma digitale.
1.3.2.3 Algoritmi ibridi
Si è visto che gli algoritmi a chiave di cifratura pubblica garantiscono il servizio
di segretezza ma non quello di autenticazione di identità mentre gli algoritmi a
chiave di decifratura pubblica garantiscono gli stessi servizi in modo opposto.
Sarebbe molto proficuo utilizzare contemporaneamente una combinazione dei due
algoritmi per ottenere entrambi i servizi che costituiscono delle caratteristiche
estremamente importanti ai fini della sicurezza.
Lo schema di principio dell’utilizzo combinato delle due tecniche è il seguente:
Figura 7. Schema di utilizzo della cifratura asimmetrica per l’invio di un messaggio autenticato e
segreto
Appurato il fatto che il mittente sia in possesso della sua chiave privata: K privM ,
della sua chiave pubblica: K pubM e della chiave pubblica del destinatario: K pubD e
che il destinatario è in possesso della sua chiave privata: K privD , della sua chiave
- 14 -
pubblica: K pubD e della chiave pubblica del mittente: K pubM , è possibile analizzare
l’effettiva trasmissione del messaggio.
Il mittente cifra il messaggio con la propria chiave privata ottenendo un
messaggio cifrato intermedio, dopodichè cifrerà il medesimo con la chiave
pubblica del destinatario, ottenendo un messaggio cifrato finale diverso da quello
intermedio. Ora il mittente invia tramite il canale insicuro il messaggio cifrato che
giungerà al mittente. Il mittente per ottenere il messaggio in chiaro dovrà
decifrarlo prima con la sua chiave privata e poi con quella pubblica del mittente.
In realtà, in cifratura, l’ordine di utilizzo delle due chiavi è arbitrario, ma deve
essere noto, in quanto chi riceve il messaggio dovrà eseguire la decifratura
impiegando le chiavi in ordine inverso.
Il servizio di autenticazione del messaggio è garantito dall’utilizzo della chiave
privata del mittente mentre il servizio di segretezza è garantito dall’impiego della
chiave privata del destinatario.
Un vantaggio che si ha rispetto alla crittografia simmetrica sta nel numero di
chiavi che gli utenti devono gestire. Nella crittografia asimmetrica ogni utente
dispone di una propria coppia di chiavi ed utilizza sempre questa per comunicare
con qualsiasi altro utente. In questo modo si ha un incremento lineare del numero
di chiavi in funzione del numero di utenti.
Il modello presentato risulta essere molto complicato da applicare in casi reali,
quindi si opta per l’utilizzo di tecniche miste che uniscono la semplicità della
crittografia simmetrica con la sicurezza di quella asimmetrica. Un esempio
eccellente riguarda la tecnica impiegata nel protocollo SSL in cui, nella
comunicazione tra due entità, viene creata “al volo” una chiave segreta, detta
chiave di sessione, per cifrare il messaggio. La chiave a sua volta viene cifrata con
la chiave pubblica del destinatario ed allegata al messaggio stesso.
1.3.2.4 I principali algoritmi a chiave asimmetrica
I principali algoritmi a chiave asimmetrica sono:
• RSA (Rivest Shamir Adelman): fu sviluppato da Ron Rivest, Adi Shamir
e Len Adelman, nel 1977 e poi brevettato nel 1983 negli Stati Uniti dal
MIT. Si basa sul problema matematico della fattorizzazione di un numero,
che consiste nel trovare quei numeri primi che, moltiplicati tra loro,
forniscono il numero dato. Questo è un problema tanto più complesso
quanto più è grande il numero iniziale. Basti pensare che una possibile
soluzione al problema sarebbe nel verificare l’ipotesi di Riemann che, a
tutt’oggi, è uno dei sette problemi del millennio per cui l’istituto
matematico Clay offre un milione di dollari a chi riesca a risolverlo.
L'RSA è solitamente combinato insieme ad un algoritmo a chiave privata.
Combinandolo ad esempio con il DES l'RSA fornisce dimensioni di chiavi
sino a 2048 bit. L'RSA è considerato sicuro se sono usate chiavi
- 15 -
•
abbastanza lunghe in quanto la sua sicurezza si basa sulla difficoltà di
fattorizzare numeri interi molto grandi.
DSA (Digital Signature Algorithm): è stato proposto nel 1991 dal NIST
per l’utilizzo nell’ambito dello standard DSS (Digital Signature Standard),
è stato progettato appositamente per la realizzazione di firme digitali. Il
procedimento di cifratura infatti prevede anche l’utilizzo di una funzione
di Hash (nello specifico la funzione SHA) ed apposite operazioni di
verifica della firma. Esso si basa sulla difficoltà di risoluzione del
problema del logaritmo discreto. Il logaritmo discreto è definito come il
logaritmo, in una certa base n , su un gruppo algebrico (a differenza del
logaritmo tradizionale che è definito sull'insieme dei numeri reali). Ad
esempio, si consideri il gruppo moltiplicativo degli interi modulo p :
G = Z *p con p numero primo. Si consideri poi l'equazione: a x = b mod p
dove l’operatore “mod” è il resto della divisione b p . Il problema del
logaritmo discreto consiste nel trovare il valore di x tale che l'equazione è
soddisfatta. Non sono noti ad oggi algoritmi efficienti per il calcolo dei
logaritmi discreti. Si tratta in pratica di un problema NP (non-polinomiale)
la cui soluzione richiede un tempo di calcolo esponenziale rispetto alle
dimensione del gruppo algebrico G . È proprio l'appartenenza alla classe
dei problemi NP che pone il problema del logaritmo discreto alla base
nella realizzazione di sistemi crittografici a chiave pubblica. In linea
teorica sarebbe possibile ricavare la chiave privata calcolando il logaritmo
discreto di quella pubblica. Nella realtà però questa operazione è
impraticabile a causa della grandezza dei numeri in gioco. Tale algoritmo
però non viene molto impiegato in quanto esistono algoritmi ritenuti molto
più sicuri.
1.3.3 Stima sulla sicurezza degli algoritmi crittografici
Agli albori della crittografia, un algoritmo veniva valutato sicuro seguendo il
principio di “security by obscurity”, secondo il quale esso risultava sicuro
fintantoché rimaneva segreto a chi non era autorizzato ad accedervi, in quanto la
mancata conoscenza non permetteva che questo potesse essere violato. Questa
metodologia era radicata profondamente in quanto gli algoritmi erano poco
elaborati e quindi era facile violarli.
La crittografia moderna non si basa più su questa idea ma sul postulato enunciato
da August Kerckhoffs nel 1883 per cui: “la sicurezza di un sistema crittografico è
basata esclusivamente sulla conoscenza della chiave”.
I maggiori algoritmi utilizzati per la crittografia sono di dominio pubblico e quindi
chiunque ne conosce la metodologia di lavoro ma nonostante ciò questo non
costituisce una minaccia alla sicurezza dell’algoritmo stesso ma anzi, al contrario,
- 16 -
è un incentivo al loro sviluppo, in quanto è più facile scoprirne difetti e debolezze
e quindi porvi rimedio.
La sicurezza di un algoritmo crittografico dipende dalle particolari proprietà
matematiche della classe dei problemi NP, la cui soluzione necessita di una
quantità di tempo che aumenta esponenzialmente con i dati in ingresso, rendendo
gli attacchi a questi sistemi tanto più impraticabili quanto più aumenta la
lunghezza delle chiavi coinvolte nei processi di cifratura e decifratura.
La chiave non è altro che una sequenza di bit generata in modo più o meno
casuale che, in linea teorica, può sempre essere ricavata.
Esistono infatti dei metodi di ricerca esaustiva che consentono di risalire alla
chiave utilizzata nella cifratura provando ad applicare l’algoritmo ad un testo
cifrato, impiegando chiavi sempre diverse, fino a che non si ottiene un risultato
sensato. Questo modo di procedere è noto come “attacco di forza bruta” (brute
force attack). Il successo di questo tipo di attacchi dipende dal numero massimo di
tentativi che possono essere fatti, ovvero dal numero massimo di chiavi che quel
particolare algoritmo può accettare, cioè dal keyspace.
La tabella sotto mostra quanto influisce la lunghezza della chiave in un attacco a
forza bruta sui tempi necessari a trovare la chiave giusta ipotizzando una forza di
calcolo pari a un milione di tentativi al secondo.
Lunghezza della chiave
32 bit
40 bit
48 bit
56 bit
64 bit
Dimensioni del keyspace
4,29 · 109
1,1 · 1012
2,81 · 1014
7,21 · 1016
1,84 · 1019
Tempo di ricerca
1,2 ore
13 giorni
8,9 anni
2.300 anni
580.000 anni
Tabella 1. Tempo di ricerca necessario per un attacco di forza bruta nell’ipotesi che si possano
effettuare un milione di tentativi al secondo
Si ribadisce che, per quanto riguarda la sicurezza del sistema, la chiave gioca un
ruolo fondamentale ed in particolare in relazione alla sua lunghezza.
Si potrebbe pensare, in via teorica di creare una chiave estremamente lunga, in
grado di vanificare ogni attacco di forza bruta, ma ciò avrebbe come svantaggio
un tempo notevolmente grande per implementare l’algoritmo di cifratura e
decifratura del messaggio. Dunque ci si trova di fronte ad un problema di
ottimizzazione fra il vantaggio della sicurezza che induce una chiave moto lunga e
lo svantaggio di notevoli tempi che rallenterebbero la fase di cifratura e
decifratura.
Per risolvere questo problema si va a valutare la tipologia di dati che si sta
tentando di proteggere: il livello di sicurezza del sistema deve essere tanto più alto
quanto più sono sensibili le informazioni in gioco. Secondo quanto detto, è
opportuno tener presente il costo richiesto per violare l’algoritmo che deve essere
superiore al valore dei dati protetti ed il tempo richiesto per violare l’algoritmo
che deve risultare superiore al tempo per cui i dati cifrati devono rimanere segreti.
- 17 -
Tenendo da conto quanto appena esposto, qualsiasi tentativo di attacco, anche se
andasse a buon fine, non comporterebbe alcun vantaggio a colui che appronta il
tentativo d’intrusione.
1.3.4 La funzione di Hash
La funzione di Hash è un processo di trasformazione dei bit, che si differenzia dai
normali algoritmi crittografici, in quanto dopo la cifratura del messaggio non è
possibile effettuare la decifratura.
Quando si applica un messaggio ad una funzione di Hash essa restituisce una
stringa di bit di lunghezza fissa, che rappresenta una sorta di sintesi matematica
del messaggio, detta “message digest” (impronta digitale).
La funzione di Hash gode di alcune proprietà che la rendono crittograficamente
sicura:
• è applicabile a qualsiasi sequenza di dati di qualsiasi tipo e dimensione;
• il risultato della sua applicazione è una stringa di bit di dimensione fissa
indipendente dalla dimensione del messaggio originale;
• la variazione di un solo bit del messaggio originale comporta la variazione
dell’intero digest;
• è una funzione a senso unico (one way), cioè risulta impossibile risalire al
messaggio originale partendo dal digest;
• è una funzione senza collisioni (collision free), nel senso che è impossibile
trovare due messaggi diversi tra loro che restituiscano lo stesso digest.
In realtà la funzione di Hash è una applicazione non iniettiva caratterizzata da un
dominio con uno spazio di dimensione infinita che rappresenta l’insieme di tutti i
messaggi in chiaro di qualsiasi lunghezza e un codominio con uno spazio a
dimensione finita che rappresenta l’insieme di tutti i possibili digest di lunghezza
prefissata.
Risulta però matematicamente impossibile che ad ogni elemento del dominio
corrisponda un unico elemento del codominio, è comunque talmente bassa la
probabilità che a due elementi distinti del dominio corrisponda uno stesso
elemento del codominio che si può dire che la funzione di Hash è una relazione
senza collisioni ed a senso unico.
Si può dunque dire che due messaggi che hanno lo stesso digest sono uguali tra
loro e questo ci permette di utilizzare la funzione di Hash ogni qualvolta il fine è
quello di confrontare due messaggi tra loro per verificarne l’uguaglianza. Essendo
i messaggi di dimensioni arbitrarie, risulta sicuramente più comodo eseguire il
confronto direttamente sui digest che sono a lunghezza fissa.
Questa tecnica apre la strada ad una delle più importanti applicazioni della
funzione di Hash: la firma digitale.
- 18 -
1.3.4.1 I principali algoritmi per la funzione di Hash
I principali algoritmi che la funzione di Hash utilizza sono:
• MD5 (Message Digest 5): è un algoritmo sviluppato dai laboratori RSA
che fornisce digest di 128 bit, nel 2006 si sono presentati casi di collisioni;
• SHA (Secure Hash Algorithm): chiamato anche Secure Hash Standard
(SHS) è un algoritmo pubblicato dal Governo degli Stati Uniti che produce
digest di 160 bit;
• SHA-1: è la versione migliorata del precedente algoritmo. Produce
anch’esso digest di 160 bit, ma, a differenza del suo predecessore, l’SHA1 non è stato ancora violato;
• SHA-256, SHA-512, SHA-384: sono stati sviluppati e proposti nel Draft
Federal Information Processing Standard (FIPS) nel 2001; rispettivamente
producono un digest di 256 bit, 512 bit e 384 bit aumentando quindi la
sicurezza rispetto a SHA-1.
1.3.4.2 Stima sulla sicurezza della funzione di Hash
La funzione di Hash è un algoritmo di cifratura one-way che codifica secondo
funzioni matematiche non invertibili un messaggio, cioè non è possibile
decodificare il digest a partire dal risultato cifrato.
Il digest è teoricamente univoco, non dovrebbero quindi esistere due stringhe
diverse che codificate generino lo stesso risultato cifrato, tale eventualità è
chiamata collisione e una sua scoperta porterà lentamente l’algoritmo ad essere
dichiarato non sicuro.
Le combinazioni possibili, variano da algoritmo a algoritmo, sono superiori
all’ordine di milioni di miliardi, lasciando l’ingannevole fiducia
sull’indecifrabilità del digest.
Negli anni ottanta il matematico americano Martin Hellman studiò una tecnica
chiamata “time memory trade-off” (compromesso tempo-memoria) per decifrare
il digest generato da una funzione di Hash.
In pratica Hellman propose di creare dei dizionari in cui venivano inseriti tutti i
digest generati da ogni possibile messaggio. La conseguenza è la creazione di un
grande vantaggio nella ricerca del digest, infatti in un attacco di forza bruta, il
maggiore spreco di burst time sta nella codifica ripetuta della generazione del
digest e non nel confrontarlo, mentre con l’uso del dizionario si va ad effettuare
direttamente il confronto.
Il problema di questa tecnica sta nella dimensione del dizionario infatti un
dizionario capace di contenere tutti i digest frutto delle combinazioni
alfanumeriche di messaggi sufficientemente lunghi supererebbe le decine di
terabyte.
Per ovviare a ciò Philippe Oechsin, un esperto in sicurezza, ha ideato un
procedimento per ridurre il dizionario di digest in una tabella molto più piccola
chiamata “rainbow tables”.
- 19 -
Come prima cosa si codificano i messaggi e si ottengono i digest corrispondenti;
ora viene definita una formula di riduzione R ( hash ) tale che ad un digest faccia
corrispondere un messaggio: ovviamente non sarà quello di partenza, poiché è
impossibile invertire una funzione di Hash.
Si itera t volte il seguente procedimento: si genera l’hash del nuovo messaggio e
si applica la formula di riduzione Ri ( hashi ) con i = 1, 2,… , t dove i indica i
passaggi effettuati.
Si verrà quindi a definire che: f i +1 = Ri ( Hash Algorithm ( f i ) ) dove
f i = messaggioi , ovvero il messaggio al passo i + 1 è il risultato della formula di
riduzione i -esima applicata all’ i -esimo digest.
In questo modo si genererà una catena “password-hash-password-hash” di
migliaia di elementi ma di questi solo il primo e l’ultimo verranno conservati su
disco con un risparmio di memoria pari a t volte.
Ora quando si vorrà confrontare un digest si applicherà f t e si controllerà che il
risultato non sia l’ultimo elemento di una delle catene (di cui come appena detto
conserviamo solo l’inizio e la fine); se ciò non fosse vero si applicherà in
sequenza ft −1 e f t e si riconfronterà il risultato con l’ultimo elemento delle
catene. Continuando con questo procedimento all’ i -esimo passaggio si ricaverà
che il digest ricercato fa parte di una certa catena X e quindi con discreta
probabilità il messaggio che l’ha generato sarà quello che precede nella catena.
Non è possibile risalire la catena (si dovrebbe invertire una funzione di Hash) ma
è stato memorizzato l’inizio di tale catena e si può perciò riapplicargli in sequenza
gli t − i passi necessari a ritrovare il messaggio del passo precedente.
Si ricava il digest del messaggio e lo si confronta con il risultato, scoprendo che è
quello giusto.
Questo metodo porta raramente a falsi allarmi dovuti a eventuali collisioni,
generati dalle formule di riduzione lungo la catena; al contrario la versione
originale di tale metodo applicava un’unica R ( hashi ) ad ogni passo, con rilevanti
percentuali di errore.
Tale procedimento è velocissimo ed il tempo di cracking si riduce col quadrato
della grandezza della tabella, cioè incredibilmente, usare una tabella da 1 gigabyte
è 16 volte più veloce di una da 256 megabyte.
Questo metodo risulta molto efficace quando i messaggi sono relativamente corti
e quindi ottimale nel violare le password.
1.3.5 La firma digitale
In quasi tutte le attività lavorative risulta indispensabile per verificare l’autenticità
di un atto l’apposizione di una firma autografa.
In ambito informatico questo è possibile per mezzo della firma digitale.
- 20 -
L’implementazione e la validazione di una firma digitale richiedono l’utilizzo di
una funzione di Hash e di un algoritmo di crittografia asimmetrica.
Lo schema di principio con cui si realizza la firma digitale di un documento
informatico è il seguente:
Figura 8. Processo di firma digitale di un documento informatico
Il messaggio originale viene elaborato mediante una funzione di Hash generando
così il suo digest, a questo punto il digest viene cifrato utilizzando la chiave
privata del mittente K priv M , infine si costituisce un documento finale costituito
dal messaggio originale, dalla firma ed eventualmente dal certificato contenente la
chiave pubblica di decifratura.
Il documento così ottenuto viene trasmesso al destinatario, che dovrà verificarne
l’autenticità al fine di garantire la correttezza della trasmissione.
Lo schema di principio con cui si verifica l’autenticità della firma digitale di un
documento informatico è il seguente:
Figura 9. Processo di verifica della firma digitale
Il documento firmato viene ripartito in due parti, in una è contenuta il messaggio
originale e nell’altra è contenuta la firma. Il messaggio in chiaro viene elaborato
mediante una funzione di Hash generando così il suo corrispondente digest.
- 21 -
La firma viene decifrata con la chiave pubblica del mittente K pub M , recuperata
dal certificato relativo al mittente stesso, ottenendo così il “digest presunto”.
A questo punto si effettua il confronto fra il digest ottenuto ed il “digest
presunto”. Questa operazione può portare a due situazioni: i digest sono uguali,
allora la firma è valida ed il documento è integro oppure i digest sono diversi e
questo segnala che il documento ha subito delle modifiche che potrebbero essere
di natura dolosa o accidentale, dal momento in cui è stato firmato dal mittente a
quello in cui è stato ricevuto dal destinatario.
La firma digitale così ottenuta lega l’entità, che detiene l’uso esclusivo della
chiave privata, ai dati, tramite l’impiego del digest, infatti ogni firma, anche se
apposta con la stesa chiave privata, è unica e diversa in relazione ad un diverso
documento.
Si può, inoltre, precisare che il documento e la sua firma non devono
necessariamente essere trasmessi sullo stesso canale, infatti un invio separato non
toglie il legame esistente fra di esse.
La firma digitale offre tutte le garanzie di sicurezza di una normale firma
autografa, apportando una maggiore difficoltà alla falsificazione del documento,
in quanto si dovrebbe entrare in possesso della chiave privata del mittente, e
garantisce l’integrità del documento, in quanto una qualsiasi modifica del
documento implicherebbe la variazione dell’intero digest.
La fase di trasmissione avviene su canali sicuri, come ad esempio l’SSL,
garantendo così la sicurezza anche da attacchi del tipo “man in the middle”.
- 22 -
1.4 La public key infrastructure
Precedentemente si è discusso sulla validità degli algoritmi crittografici e sul
vantaggio di utilizzare la firma digitale al fine di garantire la sicurezza e la
segretezza della trasmissione di un messaggio.
Il problema non è stato completamente risolto in quanto, ipotizzato un corretto
utilizzo da parte dell’utente delle metodologie prima elencate, per esempio la
creazione ed il mantenimento di riservatezza della chiave, la firma digitale lega un
documento non al suo autore, ma alla chiave che esso ha utilizzato
nell’operazione di cifratura, si necessita quindi di un’entità che assicuri che quella
chiave appartenga effettivamente all’autore del messaggio. Inoltre si deve
garantire che lo scambio e la divulgazione delle chiavi pubbliche avvengano in
modo sicuro.
Per questo si deve introdurre il concetto di “infrastruttura a chiave pubblica”, in
cui un’autorità fidata si preoccupa di identificare e autenticare tutti gli utenti che
vogliano usufruire dei suoi servizi garantendo, inoltre l’appartenenza di una
chiave pubblica ad uno specifico utente mediante l’emanazione di un certificato.
L’ infrastruttura a chiave pubblica, definita acronicamente come “PKI”, può
essere definita in vari modi, per esempio il NIST, nel documento “Introduction to
Pulic Key Technology and the Federal PKI Infastructure” del 2001, la definisce
come “una gerarchia monopolizzata usata per l’amministrazione di certificati e
delle chiavi pubbliche”, oppure può essere definita come una infrastruttura che
fornisce servizi di cifratura e firma digitale ad utenti. Inglobando le varie
definizioni in una unica, si può dire che una PKI risulta essere un insieme di
hardware, software, risorse umane, protocolli, regole e procedure necessarie per
rendere possibile l’utilizzo su larga scala dei sistemi di crittografia asimmetrici.
1.4.1 Il certificato a chiave pubblica
Un certificato a chiave pubblica è un documento informatico che associa una
chiave pubblica ad un soggetto, per essere valido ai fini di legge deve essere
firmato digitalmente da una entità preposta, detta autorità di certificazione che
autentica l’effettiva appartenenza della chiave al soggetto.
Un certificato a chiave pubblica deve quindi contenere:
• i dati anagrafici del soggetto titolare, denominato subject;
• la chiave pubblica del soggetto ed informazioni relative allo stesso come
l’algoritmo di cifratura utilizzato, impieghi previsti, etc;
• il periodo di validità del certificato;
• i dati identificativi dell’emettitore del certificato, denominato issuer;
• un digest delle informazioni precedenti cifrato con la chiave privata
dell’emettitore, denominato signature.
- 23 -
Gli schemi sotto mostrano i processi di firma e verifica di un certificato:
Figura 10. Firma del certificato da parte di un soggetto e di una autorità di certificazione.
Figura 11. Verifica di un certificato a chiave pubblica.
Quando il mittente vuole stabilire una comunicazione con il destinatario richiede
ad una autorità di certificazione di farsi rilasciare un certificato a chiave pubblica.
A questo punto il mittente appone la firma sul documento originale ed invia al
destinatario sia il documento firmato sia il certificato.
Il destinatario all’arrivo del messaggio, verifica l’attendibilità del certificato e
l’autenticità del documento firmato. Per fare ciò il destinatario decifra la signature
con la chiave pubblica della dell’issuer ottenendo un digest presunto da
confrontare con il digest ricavato da tutti gli altri campi del certificato elaborati
con la funzione di Hash. Se il digest presunto è uguale al digest ricavato allora il
- 24 -
certificato è valido e si procede alla verifica della firma, nel caso siano diversi, ciò
implica che il certificato non è originale.
L’utilizzo dei certificati a chiave pubblica è necessario solo se si vuole conseguire
la validità ai fine di legge, quindi è del tutto lecito scambiare documenti con la
tecnica delle chiavi asimmetriche senza ricorrere all’uso dei certificati, se ad
esempio i documenti da scambiare non hanno una grande riservatezza.
1.4.1.1 Richiesta, ottenimento, durata e revoca di un certificato
Un utente che desidera richiedere un certificato ad una autorità di certificazione
deve come prima cosa registrarsi presso una autorità di registrazione.
La procedura di registrazione costituisce una prima importante relazione tra
l’utente e l’autorità di certificazione.
Una volta attestata l'autenticità dell’identità dell’utente, l’autorità di registrazione
lo registra in un suo dominio di fiducia.
Il fine primario della registrazione è quindi quello di garantire che la chiave
pubblica richiesta da un utente sia effettivamente associata e quindi appartenga
solo a quel determinato utente.
Terminata la fase di registrazione, l'utente può richiedere l'emissione di un
certificato.
Durante la procedura di generazione di un certificato l'utente sottopone all'autorità
di certificazione le informazioni da certificare e quest'ultima verifica l'accuratezza
delle stesse in accordo a politiche e standard applicabili. L'autorità di
certificazione firma poi le informazioni, generando il certificato e lo pubblica sul
sistema scelto per la distribuzione dei certificati. L’autorità di certificazione può
anche archiviare una copia del certificato e registrare ogni operazione di
generazione di certificati su di un proprio archivio.
La richiesta di un certificato è realizzata di solito in formato PEM.
Il formato PEM prevede l’utilizzo di due Encapsulation Block, che indicano la
posizione di inizio e di fine del certificato memorizzato nel file. All’interno di
ogni Encapsulation Block viene utilizzata la codifica Base64.
Figura 12. Frammento di file contenente una richiesta di certificato
L'utente genera sul proprio computer una coppia di chiavi utilizzando il software
fornito dall’autorità di certificazione oppure utilizzando quello già incluso nei
browser.
La chiave privata viene memorizzata localmente in un file nascosto. Se è richiesta
una maggiore sicurezza la coppia di chiavi può venire generata tramite una Smart
- 25 -
Card collegata ad un computer e la chiave privata resta sempre memorizzata solo
sulla Smart Card protetta quindi da PIN.
Tramite posta elettronica l'utente invia una richiesta di certificato unitamente alla
chiave pubblica generata, all’autorità di certificazione di sua fiducia.
L’autorità di certificazione verifica l'identità del richiedente, di solito è prevista la
richiesta di presentarsi di persona presso l’autorità di certificazione. Effettuato poi
il controllo, l’autorità di certificazione emette il certificato come documento
elettronico, lo invia al richiedente tramite posta elettronica e lo inserisce nel
registro delle chiavi pubbliche.
Ogni certificato generato ha una validità temporale limitata al cui termine va
sostituito. Il periodo di validità di un certificato, in assenza di compromissioni o di
usi illeciti, garantisce all'utente che deve utilizzare tale certificato, che la chiave
pubblica può essere utilizzata per lo scopo per cui è stata generata e che
l'associazione tra la chiave pubblica e le altre informazioni contenute nel
certificato è ancora valida.
L’autorità di certificazione deve poter garantire misure efficaci contro usi
fraudolenti ed illeciti di un certificato; lo strumento che può utilizzare è la revoca.
Un certificato deve essere revocato in presenza delle seguenti condizioni:
• compromissione rilevata o semplicemente sospettata della chiave privata
corrispondente alla chiave pubblica contenuta nel certificato;
• cambiamento di una qualsiasi delle informazioni contenute nel certificato
o delle condizioni iniziali di registrazione.
Un'autorità di certificazione che necessita di revocare dei certificati prima della
loro scadenza naturale deve pubblicare un elenco degli stessi nel “Certificate
Revocation List” (CRL), in modo che tutti gli utenti appartenenti alla stessa
infrastruttura siano informati delle avvenute revoche.
Le liste di revoca giocano un ruolo di fondamentale importanza in tutti i processi
crittografici, in quanto devono essere consultate sia in fase di cifratura che in fase
di verifica di una firma, poichè prima di cifrare un messaggio, va verificato che la
chiave pubblica che si deve usare appartenga ad un certificato valido.
Analogo discorso vale per la verifica di una firma, che può essere ritenuta valida
solo se il certificato del firmatario, oltre ad essere autentico ed integro, non è stato
revocato. L'autenticità e l' integrità del certificato si controlla verificando la firma
dell’autorità di certificazione che ha emesso il certificato. Lo stato di revoca si
controlla verificando che il certificato in questione non compaia nella lista di
revoca emessa dall’autorità di certificazione competente.
Il metodo di distribuzione della notifica di revoca attraverso CRL, distribuite
periodicamente dall'autorità di certificazione, è detto di tipo “pull”, in quanto sono
gli stessi utenti finali a fornirsi delle CRL dal sistema di distribuzione quando è
necessario.
Il limite legato al metodo di distribuzione delle notifiche delle revoche tramite
CRL, è quello della latenza introdotta, infatti quest’ultima dipende dalla
periodicità di emissione delle CRL, che deriva dalle politiche di sicurezza stabilite
dall'organizzazione. Una determinata politica potrebbe richiedere la pubblicazione
- 26 -
di una nuova CRL ogni qualvolta si richiede una revoca ma tale procedura risulta,
tuttavia, molto dispendiosa dal punto di vista amministrativo.
Per ovviare a questo problema, lo standard X.509 introduce una tipologia
particolare di CRL definita “Delta CRL”.
Con cadenza stabilita viene pubblicata una CRL base a cui viene associata una
Delta CRL che contiene gli aggiornamenti alla CRL base. Date le dimensioni
ridotte, le Delta CRL possono essere pubblicate con maggiore frequenza senza
comportare un eccessivo consumo di risorse di rete.
1.4.2 Autorità di certificazione
Come descritto nel paragrafo precedente esistono due entità che si occupano della
sicurezza dei certificati: l’autorità di registrazione e l’autorità di certificazione.
L’autorità di registrazione si occupa di verificare l’effettività identità dell’utente
richiedente in quanto il certificato deve appartenere ad un solo utente: il suo
possessore.
Una volta che l’autorità di registrazione ha attestato la validità dell'identità
dell'utente attraverso una serie di procedure definite da una determinata politica di
sicurezza, ha il compito di abilitare l'utente come appartenente ad uno specifico
dominio di fiducia.
Spesso la funzionalità di autorità di registrazione viene espletata dall'autorità di
certificazione.
Una volta che l’autorità di registrazione ha abilitato l’utente come appartenente ad
uno specifico dominio di fiducia l’autorità di certificazione crea un certificato per
quell’utente.
L’attività di un’autorità di certificazione non si limita esclusivamente alla
generazione dei certificati, ma deve poterne gestire l'intero ciclo di vita, deve
quindi occuparsi anche delle fasi successive quali l’aggiornamento e la revoca.
Un ulteriore compito dell'autorità di certificazione è stabilire relazioni di fiducia
con le altre autorità di certificazione.
Un'autorità di certificazione può operare in modo autonomo, oppure appartenere
ad una struttura più articolata.
Le autorità di certificazione possono essere collegate essenzialmente in due modi:
• modello reticolare;
• modello ad albero.
Nel modello reticolare ogni autorità di certificazione nasce come autorità locale di
cui si fidano tutti e solo gli utenti appartenenti ad essa, e le altre autorità di
certificazione comunicano tra loro la veridicità di un certificato attraverso un
certificato particolare detto “cross certificate”. Lo svantaggio di un tale modello
sta nel fatto che le autorità di certificazione potrebbero adottare politiche di
sicurezza diverse e quindi il passaggio di un cross certificate da un’autorità che
garantisce una sicurezza maggiore ad una che ne garantisce di inferiori produrrà
un decadimento sulla sicurezza del certificato.
- 27 -
Nel modello ad albero è prevista un’autorità di certificazione globale, la quale
garantisce per se stessa autocertificandosi, che demanda ed organizza il compito
di certificazione a strutture inferiori, firmando il loro certificato con la propria
chiave privata e le autorità inferiori possono avere a loro volta la responsabilità
sulla certificazione di altre autorità di livello inferiore. Lo svantaggio sulla
riduzione della sicurezza che si verifica nel modello reticolare, non si presenta in
questo modello, in quanto è l’autorità globale a dettare le politiche di sicurezza
per tutte le altre autorità facenti parte alla struttura.
Pensando ad una rete globale, è facile immaginare che esistano una molteplicità di
autorità di certificazione, con diverse politiche di sicurezza, che devono operare
fra loro, è quindi impensabile che ogni utente abbia diretta conoscenza delle
chiavi pubbliche di ogni potenziale interlocutore, o delle chiavi pubbliche delle
corrispondenti autorità di certificazione. Per risolvere questo problema si
utilizzano le cosiddette catene di certificazione, in cui l'utente che riceve un
messaggio firmato verifica prima di tutto l'autenticità del certificato con la chiave
pubblica dell’autorità di certificazione che lo ha emesso e poi la firma del mittente
con la sua chiave pubblica contenuta nel certificato. In questo modo è possibile
allegare ad un messaggio che si vuole autenticare più certificati, definendo una
vera e propria gerarchia di certificati, in cui ognuno attesta l'autenticità del
precedente.
1.4.3 Standard X.509
Lo standard X.509 definisce il formato per i certificati a chiave pubblica e ne
regola l’esistenza.
Lo standard X.509 è descritto nelle specifiche ITU-T corrispondenti alle
specifiche ISO/IEC 9594-8.
La prima versione dello standard X.509 fu presentata nel 1998, prevedeva un
sistema gerarchico delle autorità di certificazione per l’emissione dei certificati, in
cui solo l’autorità di certificazione poteva validare un certificato, in
contrapposizione ai modelli allora esistenti di fiducia in cui chiunque poteva
firmare e quindi attestare la validità delle chiavi altrui.
Trascorsi degli anni la versione 1 risultò inadeguata e vennero introdotte la
seconda e la terza versione in cui vennero aggiunti dei nuovi controlli di accesso
dei campi, di sostegno e dell’indice e furono integrate la compatibilità con altre
topologie, aumentando la flessibilità; ad esempio fu permesso l’utilizzo in reti di
fiducia peer to peer.
- 28 -
La struttura di un certificato X.509 v3 è mostrata in figura:
Figura 13. Struttura di un certificato X.509 v3
•
•
•
•
•
•
•
•
•
•
Version: indica la versione del formato del certificato.
Serial Number: è un codice numerico che identifica univocamente il
certificato.
Signature Algorithm: specifica l’algoritmo utilizzato dall’autorità di
certificazione per firmare il certificato.
Issuer X.500 Name: indica il nome dell’autorità di certificazione secondo
lo standard di naming X.500.
Validity Period: specifica la data e l’ora di inizio validità e fine validità
del certificato.
Subject X.500 Name: nome del possessore del certificato.
Subject Public Key Information: contiene il valore della chiave pubblica
del possessore del certificato e l’algoritmo con cui tale chiave viene usata.
Issuer Unique Identifier: è una stringa di bit aggiuntivi, opzionale, usata
nel caso in cui nella struttura ad albero ci siano due autorità di
certificazione.
Subject Unique Identifier: stringa opzionale di bit usata nel caso di
omonimia tra due membri di una stessa autorità di certificazione.
Extensions: è suddiviso in tre sottocampi: l’identificatore del tipo di
estensione, un indicatore di criticità e il valore effettivo dell’estensione.
L’indicatore di criticità facilita l’interoperabilità tra sistemi che non
utilizzano certificati con determinate estensioni e sistemi che, invece
interpretano tutte le estensioni definite a livello di standard. Tale
indicatore è un flag che indica se l’estensione è critica o non critica;
nell’ultimo caso il sistema che deve elaborare il certificato può
- 29 -
•
eventualmente ignorare l’estensione in questione se non è in grado di
interpretarla.
CA Signature: è la firma digitale dell’autorità di certificazione sul
certificato.
1.4.4 Standard PKCS
PKCS (Public Key Cryptography Standard) è uno standard rilasciato dalla RSA
Laboratories nel 1991 che permette di incrementare lo sviluppo e l’impiego delle
tecniche di crittografia asimmetrica.
Il PKCS nel corso del tempo è diventato lo standard per questo tipo di tecnologie
ed è usato in molte applicazioni come ad esempio nel protocollo S/MIME
utilizzato per la posta elettronica e nel protocollo SSL impiegato per fornire
sicurezza nelle comunicazioni su Internet.
Il PKCS è costituito da quindici normative che definiscono gli algoritmi di
crittografia, la sintassi e le interfacce per l’utilizzo dei vari strumenti crittografici:
• PKCS#1: RSA Cryptography Standard. Definisce le linee guida per
l’implementazione dell’algoritmo RSA sui calcolatori digitali. Lo standard
PKCS#1 incorpora PKCS#2 e PKCS#4.
• PKCS#3: Diffie-Hellman Key Agreement Standard. Descrive un
metodo per l’implementazione dell’algoritmo di Diffie-Hellman.
• PKCS#5: Password-Based Criptography Standard. Prescrive delle
raccomandazioni per l’implementazione della cifratura basata su
password.
• PKCS#6: Extended-Certificate Sysntax Standard. Propone una sintassi
ASN.1 che estende quella dei certificati X.509.
• PKCS#7: Cryptographic Message Syntax Standard. Descrive la
sintassi generale per i dati crittografati. Su questo formato si basa ad
esempio il protocollo di posta elettronica S/MIME e molti altri formati di
interscambio per le informazioni di identificazione personale.
• PKCS#8: Private-Key Information Syntax Standard. Descrive la
sintassi per le informazioni relative ad una chiave privata, e per le chiavi
private cifrate.
• PKCS#9: Selected Attribute Types. Definisce i tipi ASN.1 degli attributi
usati in PKCS#6, PKCS#7, PKCS#8 e PKCS#10.
• PKCS#10: Certification Request Syntax Standard. Descrive una
sintassi per la richiesta di firma di un certificato.
• PKCS#11: Cryptographic Token Interface Standard. Specifica una
API (Cryptoki) per i dispositivi in grado di eseguire operazioni
crittografiche e trattare le informazioni relative (chiavi e certificati). È lo
standard de facto per l’interoperabilità tra i diversi modelli e tipi di HSM
(Hardware Security Module). Definisce un modello ad oggetti del token
indipendente dall’hardware sottostante e dalla piattaforma operativa.
- 30 -
•
•
•
PKCS#12: Personal Information Excange Syntax Standard. Specifica
un formato per la memorizzazione o il trasporto di informazioni personali,
come chiavi private, certificati e altro. È il formato utilizzato nei browser
più comuni per l’importazione e l’esportazione di chiavi e certificati.
PKCS#13: Elliptic Curve Cryptografy Standard. Specifica molti aspetti
della crittografia basata sulla teoria delle curve ellittiche, è ancora in fase
di sviluppo.
PKCS#15: Cryptographic Token Information Format Standard.
Propone un modello generalizzato per l’accesso ai token crittografici, al
fine di favorire maggiormente la compatibilità tra l’hardware di diverse
marche, viene utilizzato ad esempio nelle Smart Card.
- 31 -
1.5 La steganografia
L’etimologia del termine “steganografia” è data dall’associazione di due parole di
origine greca: “stèganos” che significa nascosto, e “grafèin” che significa
scrivere, da cui “scrittura nascosta”.
Nonostante il significato di steganografia e di crittografia sia molto simile, tra le
due tecniche esiste una differenza sostanziale.
Lo scopo della crittografia è quello di nascondere il contenuto di un messaggio,
cioè fare in modo che lo stesso sia interpretabile solo dagli stretti interlocutori,
mentre la steganografia si prefigge di nascondere il messaggio facendo in modo
che sia nascosta la comunicazione in sé, cioè solo gli interlocutori sanno di
scambiarsi un messaggio e nessun altro.
La stenografia nasce dall’esigenza di andare a colmare le lacune che presentano le
tecniche crittografiche, si pensi ad esempio ad un soldato che viene sorpreso a
scambiare messaggi cifrati con un governo ostile: indipendentemente dal
contenuto del messaggio, il solo fatto che vengano scambiati messaggi cifrati
desta ovvi sospetti.
Esempi sull’uso della steganografia risalgono all’epoca dell'impero persiano.
Erodoto, racconta la storia di un nobile persiano che fece tagliare a zero i capelli
di uno schiavo fidato al fine di poter tatuare un messaggio sul suo cranio; una
volta che i capelli furono ricresciuti, inviò lo schiavo alla sua destinazione, con la
sola istruzione di tagliarseli nuovamente.
Esempi più elaborati sono le griglie di Cardano che sono fogli di materiale rigido
nei quali venivano ritagliati fori rettangolari ad intervalli irregolari dove
l’apposizione su un testo né mostrava il messaggio nascosto in quanto bastava
leggere solo i caratteri contenuti in ogni foro, oppure la tecnica delle cifre nulle
che venne utilizzata nella seconda guerra mondiale dalle truppe tedesche, la quale
consisteva nell'inserire il messaggio nascosto in un altro messaggio di testo, in
pratica il messaggio trasmesso veniva composto in modo tale che, unendo le
lettere secondo un preciso schema (prime lettere di ogni capoverso, seconde
lettere di ogni parola, etc), faceva ottenere il messaggio nascosto. Un'altra tecnica
molto usata dai nazisti era quella dei micropunti fotografici, i quali erano
fotografie della dimensione di un punto dattiloscritto che, una volta sviluppate e
ingrandite, potevano diventare pagine stampate di buona qualità.
In tempi recenti la steganografia viene usata per inserire in un file digitale un
“watermark” che in caso di uso illecito, ad esempio una copia, permette di
verificare l’effettiva paternità del file.
Un altro tipo di marchio digitale è il “fingerprint” che sono inseriti in diverse
copie nello stesso file per distribuirlo ad utenti diversi. Il motivo è quello di
ottenere una specie di numero seriale sul file che rende possibile al proprietario
l’identificazione degli utenti che lo hanno distribuito a terzi, ad esempio
gratuitamente.
- 32 -
1.5.1 Steganografia iniettiva e generativa
La steganografia si basa sull’esistenza di due messaggi: uno detto messaggio
contenitore e l’atro detto messaggio segreto. Il compito del messaggio contenitore
è quello di incapsulare il messaggio segreto in modo tale che nessuno, all’infuori
degli interlocutori, sappia che il messaggio segreto sia nascosto dentro quello
contenitore.
L’evoluzione delle tecniche informatiche ha favorito lo sviluppo di algoritmi
steganografici sempre più sofisticati, sicuri e pratici da usare, ed ha allargato le
tipologie di messaggi contenitori, infatti si potranno usare ogni tipo di files
presenti su un computer, anche se solitamente si usano immagini, files sonori e
files video.
In base all'origine del file contenitore si possono distinguere due tipi di algoritmi
steganografici:
• algoritmi di steganografia iniettiva;
• algoritmi di steganografia generativa.
Gli algoritmi di steganografia iniettiva consentono di “iniettare” il messaggio
segreto all'interno di un messaggio contenitore già esistente modificandolo in
modo tale che sia in grado di contenere il messaggio nascosto, in più devono
cercare di rendere il messaggio steganografato indistinguibile dall'originale, in
maniera tale da non produrre sospetti a chi potrebbe esaminare la comunicazione.
Gli algoritmi di steganografia generativa, partendo dal messaggio segreto
producono un opportuno contenitore atto a nascondere nel migliore dei modi il
messaggio segreto.
1.5.2 Modelli steganografici
Le tecniche steganografiche possono essere suddivise in tre categorie:
• steganografia sostitutiva;
• steganografia selettiva;
• steganografia costruttiva.
1.5.2.1 Steganografia sostitutiva
La steganografia sostitutiva è la tecnica più diffusa, al punto che quando si parla
di steganografia in generale ci si riferisce ad essa.
La steganografia sostitutiva si basa sul fatto che la maggior parte dei canali di
trasmissione introducono un rumore ai messaggi che vi scorrono.
Figura 14. Effetto sulla trasmissione di un messaggio in un canale rumoroso
- 33 -
Gli algoritmi di steganografia sostitutiva si basano sulla sostituzione del rumore
introdotto dal canale con il messaggio che si vuole nascondere e quindi, a meno di
conoscere la chiave segreta, è indistinguibile dal rumore vero e proprio, e quindi
può essere trasmesso senza destare sospetti.
L’introduzione di rumore nei files che vengono usati come contenitori proviene
dal fatto che essi, se prendiamo ad esempio immagini, files sonori e files video,
vengono informatizzati dalla realtà attraverso una conversione analogico digitale,
è quindi in questa fase di acquisizione che si introduce il rumore. Le immagini
vengono digitalizzate per mezzo di scanner e fotocamere, i files sonori attraverso
schede di acquisizione audio, mentre i files video utilizzando videocamere.
In pratica gli algoritmi di steganografia sostitutiva vanno a sostituire i bit meno
significativi dei files digitalizzati con i bit che costituiscono il messaggio segreto
in quanto i bit meno significativi corrispondono ai valori meno evidenti di una
misura, cioè proprio quelli che possono essere facilmente affetti da errore. Il
messaggio segreto viene introdotto nel file contenitore attraverso un'iniezione
steganografica, il file risultante si presenta in tutto e per tutto simile all’originale,
con differenze difficilmente percettibili ai sensi umani e quindi, a meno di
confronti approfonditi con il file originale, utilizzando tecniche apposite che
verranno descritte successivamente, è difficile valutare se le eventuali perdite di
qualità siano da imputare al rumore od alla presenza di un messaggio segreto
steganografato, in più si può notare che spesso il file originale non è disponibile
all’analista quindi l’effettuazione di metodologie di confronto risulta
impraticabile.
1.5.2.2 Steganografia selettiva
La steganografia selettiva è una tecnica puramente teorica e non viene utilizzata
quasi mai in pratica. Gli algoritmi di steganografia selettiva si basano sull'idea di
procedere per tentativi fino a quando non si riesce a trovare un file contenitore che
sia adatto a contenere un certo messaggio segreto senza doverlo modificare o
introdurre una variazione sul rumore.
Questa tecnica non viene impiegata perché è molto dispendiosa in termini di
tempo, ed oltretutto permette di nascondere una quantità d'informazione molto
modesta, infatti aumentando la lunghezza del messaggio nascosto diventerebbe
sempre più elevata la possibilità di trovare un file contenitore adeguato.
- 34 -
1.5.2.3 Steganografia costruttiva
La steganografia costruttiva, come la steganografia sostitutiva, inietta il
messaggio nascosto nel file contenitore ma nel modificare il file contenitore tiene
conto di un modello di rumore, cioè non va a modificare le proprietà intrinseche
del file contenitore rendendo il file stenografato estremamente simile a quello
originale.
Questa tecnica sembrerebbe la migliore, ma in realtà la costruzione del modello di
rumore è molto complicata ed immaginando che un possibile attaccante conosca
un modello più elaborato per lui sarebbe semplice individuare il messaggio
nascosto.
Inoltre, se un possibile attaccante venisse in possesso del modello di rumore
utilizzato, lo potrebbe analizzare ottenendo la chiave di lettura per tutti i files
steganografati con quel modello.
1.5.3 La steganografia applicata ai files digitali
In questo paragrafo verranno descritti i principali algoritmi steganografici che
sono applicati a diverse tipologie di files.
Verranno essenzialmente presi in esame:
• files Bitmap;
• files Wave;
• files compressi con algoritmi loss less e lossy;
in modo da rendere evidente la differenza che intercorre fra la manipolazione di
un file non compresso con uno compresso.
- 35 -
1.5.3.1 Steganografia dei files Bitmap
Bitmap è un tipo di formato dati utilizzato per la rappresentazione di immagini
raster sui sistemi operativi Microsoft Windows e OS/2, fu introdotto con
Windows 3.0 nel 1990.
I files Bitmap, hanno generalmente l'estensione .bmp, o meno frequentemente .dib
(device-independent bitmap).
L’immagine è costituita da una successione di pixel a cui si fa corrispondere un
colore definito in una tavolozza (palette). Il numero di bit che costituiscono il
colore determina la “profondità” dell’immagine. Per files di profondità maggiore
di 8 bit i colori non sono indicizzati ma si utilizza la codifica RGB. La codifica
RGB è stata descritta nel 1931 dalla CIE (Commission Internationale
dell’Enclairage), è un modello di rappresentazione dei colori di tipo additivo che
si basa sui tre colori fondamentali: rosso (Red), verde (Green) e blu (Blue). Per
sintesi additiva si intende che unendo i tre colori fondamentali con la loro
intensità massima si ottiene il colore bianco.
Un file Bitmap ha la seguente struttura:
• BITMAPFILEHEADER: contiene informazioni sulla grandezza in byte
del file e l'offset del primo byte nella mappa dei pixel;
• BITMAPINFOHEADER: contiene le dimensioni in pixel dell'immagine
e il numero di colori utilizzati, sono indicate inoltre la risoluzione
orizzontale e verticale del dispositivo di output che uniti alla larghezza e
all'altezza in pixel, determinano le dimensioni di stampa dell'immagine in
grandezza reale;
• RGBQUAD: contiene la rappresentazione di tutti i pixel che compongono
la Bitmap.
Ora si esamineranno in modo accurato le varie sezioni della struttura indicando
offset e descrizione dei vari bit.
Il BITMAPFILEHEADER è costituito da:
Byte
iniziale
1
Dimensione
3
4
7
2
9
2
11
4
2
Descrizione
bfType (Identificatore di formato)
Deve essere settato a “BM” in codifica ASCII per
dichiarare che è un file Bitmap
bfSize (Grandezza complessiva del file)
Specifica la grandezza del file in bytes
bfReserved1 (Riservato1)
Deve essere settato sempre a 0
bfReserved2 (Riservato2)
Deve essere settato sempre a 0
bfOffBits (Lunghezza intestazione)
Specifica l'offset del primo byte nella mappa dei
pixel
Tabella 2. Descrizione del BITMAPFILEHEADER
- 36 -
Il BITMAPINFOHEADER è costituito da:
Byte
iniziale
15
Dimensione
Descrizione
4
19
4
23
4
27
2
29
2
31
4
35
4
39
4
43
4
47
4
51
4
biSize (Dimensione del BITMAPINFOHEADER)
Specifica la dimensione in bytes del
BITMAPINFOHEADER
biWidth (Larghezza della Bitmap)
Specifica la larghezza della Bitmap in bytes
biHeight (Altezza della Bitmap)
Specifica l’altezza della Bitmap in bytes
biPlanes (Numero di pani del dispositivo di output)
Deve essere settato sempre a 0
biBitCount (Contatore di bit)
Specifica il numero di bits per pixel, i valori accettati
sono: 1 (bianco e nero), 4 (16 colori), 8 (256 colori),
24 (16,7 milioni di colori)
biCompression (Tipo di compressione)
Viene settato a 0 se non c’è compressione
biSizeImage (Dimensione della Bitmap)
Specifica la dimensione dell’immagine in bytes, se
non c’è compressione deve essere settato a 0
biXPelsPerMeter (Risoluzione Orizzontale)
Specifica la risoluzione orizzontale in pixel per
metro del dispositivo di output
biYPelsPerMeter (Risoluzione Verticale)
Specifica la risoluzione verticale in pixel per metro
del dispositivo di output
biClrUsed (Numero di colori usati)
Specifica il numero di colori usati nella Bitmap, se è
settato a 0 il numero di colori viene calcolato usando
il bBitCount
biClrImportant (Numero dei colori importanti)
Specifica il numero di colori che sono importanti per
la Bitmap, se è settato a 0 tutti i colori sono
importanti
Tabella 3. Descrizione del BITMAPINFOHEADER
- 37 -
Il RGBQUAD è costituito da:
Byte
iniziale
1
Dimensione
2
1
3
1
4
1
1
Descrizione
rgbBlue (Componente di colore blu)
Specifica la parte blu del colore
rgbGreen (Componente di colore verde)
Specifica la parte verde del colore
rgbRed (Componente di colore rosso)
Specifica la parte rossa del colore
rgbReserved (Riservato)
Deve essere settato a 0
Tabella 4. Descrizione del RGBQUAD
La numerazione dell’offset è stata fatta ripartire da 1 ma in realtà è seguente a
quella del BITMAPINFOHEADER.
Da notare il fatto che la struttura della RGBQUAD descritta si avvale della
codifica RGB, se invece si fosse utilizzata una tavolozza non sarebbe stato
possibile definirne una, in quanto ogni colore avrebbe un codice a se non
definibile attraverso una codifica universale.
Dopo aver definito in modo rigoroso la struttura di una Bitmap si può affermare
che non considerando l’intestazione, essa può essere definita come una matrice
M ⋅ N dove M ed N sono rispettivamente la larghezza e l’altezza in pixel
dell’immagine.
La dimensione totale dell’immagine sarà data dalla formula 54 + ( M ⋅ N ⋅ P ) dove
54 sono i bytes dell’intestazione e P è la profondità dell’immagine in bytes.
Una cosa particolare pertinente la dimensione dell’immagine riguarda il fatto che
il formato Bitmap prevede che ogni riga sia rappresentata con un numero di bytes
multiplo di 4 e gli eventuali bytes aggiuntivi avranno valore 0.
Nel corso della trattazione successiva si farà riferimento ad immagini Bitmap a
24bit.
Ad esempio per una immagine 2 ⋅ 2 si avranno: 54 bytes per l’intestazione a cui
vanno aggiunti 2 ⋅ 3 = 6 bytes della prima riga, che diventano 8 bytes (multiplo di
4), a cui si sommano altri 2 ⋅ 3 = 6 bytes della seconda riga, che diventano 8 bytes,
cioè un totale di 54 + 8 + 8 = 70 bytes.
Si immagini di avere l’immagine 2 ⋅ 2 , esaminata in precedenza, tutta bianca,
quindi per la codifica RGB tutte le componenti di colore fondamentale avranno la
massima intensità, non considerando l’intestazione, il file avrà la seguente
struttura:
- 38 -
N. byte
B1
B2
B3
B4
B5
B6
B7
B8
B9
B10
B11
B12
B13
B14
B15
B16
Sequenza
decimale
originale
255
255
255
255
255
0
0
255
255
255
255
255
255
255
0
0
Sequenza
binaria
originale
11111111
11111111
11111111
11111111
11111111
00000000
00000000
11111111
11111111
11111111
11111111
11111111
11111111
11111111
00000000
00000000
Tabella 5. Codifica binaria e decimale di una bitmap 2 ⋅ 2 tutta bianca
Si ricorda che i pixel sono rappresentati da sinistra a destra e dal basso verso l’alto
e la sequenza RGB è invertita, per cui sarà BGR.
A questo punto si pensi di voler nascondere un messaggio segreto dentro
l’immagine contenitore, utilizzando un algoritmo di steganografia.
Ad esempio se si volesse nascondere il carattere “A” ed il carattere “B” in
codifica ASCII (A=01000001 e B=01000010) si andrà a modificare in ogni bytes
dell’immagine contenitore il bit meno significativo ottenendo questo risultato:
- 39 -
N.
byte
B1
B2
B3
B4
B5
B6
B7
B8
B9
B10
B11
B12
B13
B14
B15
B16
Sequenza Sequenza Sequenza Sequenza Sequenza Sequenza
decimale
binaria
decimale
binaria
binaria
binaria
originale Originale modificata modificata
di “A”
di “B”
255
11111111
254
11111110
0
255
11111111
255
11111111
1
255
11111111
254
11111110
0
255
11111111
254
11111110
0
255
11111111
254
11111110
0
0
00000000
0
00000000
0
0
00000000
1
00000001
1
255
11111111
254
11111110
0
255
11111111
255
11111111
1
255
11111111
254
11111110
0
255
11111111
254
11111110
0
255
11111111
254
11111110
0
255
11111111
254
11111110
0
255
11111111
254
11111110
0
0
00000000
1
00000001
1
0
00000000
0
00000000
0
Tabella 6. Confronto tra la bitmap originale e quella steganografata
Come si può notare confrontando la sequenza originale con quella modificata la
variazione sui colori è minima.
Per calcolare la dimensione necessaria all’inserimento di un messaggio nascosto
M ⋅ N ⋅3
di lunghezza in byte L bisogna risolvere la seguente equazione: L =
8
dove al denominatore si ha la quantità che esprime il numero di byte del file
contenitore necessari per contenere un carattere del messaggio nascosto. Per un
file 2 ⋅ 2 risolvendo l’ equazione si verifica che è possibile nascondere al massimo
2 caratteri, come era anche intuibile dall’esempio sopra.
Sfruttando solo il bit meno significativo di ogni byte diventa estremamente palese
che servirebbe un file contenitore di dimensione molto elevata, per sopperire a
questo problema si può pensare di sostituire nel file contenitore i 2 bit meno
significativi o i 4 bit meno significativi aumentando così la lunghezza massima
M ⋅ N ⋅3
come mostrato dalle rispettive equazioni a L =
= 4 caratteri e
3
M ⋅ N ⋅3
L=
= 8 caratteri.
1, 5
Tuttavia aumentare la possibile dimensione del messaggio segreto utilizzando non
più il singolo bit meno significativo di ogni byte, ma i due, tre o quattro bit meno
significativi produce ovviamente una diminuzione della qualità dell’immagine e
quindi una differenza maggiore fra l’immagine steganografata e l’immagine
originale incrementando così la possibilità di destare sospetti. Quindi si deve
trovare un giusto punto di equilibrio fra la lunghezza del messaggio nascosto e la
- 40 -
qualità dell’immagine ad esempio testando che la differenza di luminosità tra un
pixel e quelli che lo circondano non sia troppo alta.
1.5.3.2 Steganografia dei files Wave
Il WAVEform audio format è un formato audio sviluppato dalla Microsoft e dalla
IBM come variante del formato RIFF, capace di gestire vari tipi di frequenze di
campionamento, di canali audio e compressioni, la sua estensione è “wav”. Il
Wave è costituito da sequenze di byte incapsulate in blocchi detti “chunks”.
Un file Wave è costituito da tre blocchi:
• RIFF WAVE Chunk: descrive il fatto che il file RIFF concerne un file
Wave che richiede due sotto blocchi: il Format Chunk e il Sound Data
Chunk;
• Format Chunk: contiene la descrizione sul tipo di formato che verrà
usato nel Sound Data Chunk;
• Sound Data Chunk: contiene informazioni sulla lunghezza del suono ed
la codifica del suono stesso.
Il RIFF WAVE Chunk è costituito da:
Byte
iniziale
0
Dimensione
Descrizione
4
4
4
8
4
ChunkID (Identificatore del blocco)
Deve essere settato a “RIFF” in codifica ASCII
ChunkSize (Dimensione del blocco)
Specifica la lunghezza del resto del blocco, in pratica è
la lunghezza dell’intero file in byte meno 8 byte per i
due campi ChunkID e ChunkSize. In pratica sarà
settato a:
4 + (8 + SubChunk1Size) + (8 + SubChunk2Size)
Format (Formato del blocco)
Deve essere settato a “WAVE” in codifica ASCII
Tabella 7. Descrizione del RIFF WAVE Chunk
- 41 -
Il Format Chunk è costituito da:
Byte
iniziale
12
Dimensione
16
4
20
2
22
2
24
4
28
4
32
2
34
2
36
2
38
4
Descrizione
Subchunk1ID (Identificatore del sotto blocco 1)
Deve essere settato a “fmt ” in codifica ASCII
Subchunk1Size (Dimensione del sotto blocco 1)
Specifica la lunghezza del resto del blocco. Se la
codifica usata è la PCM deve essere settato a 16
AudioFormat (Formato audio)
Specifica il tipo di formato audio. Deve essere settato
a 1 se la codifica usata è la PCM altrimenti valori
maggiori di 1 indicano che è stata effettuata
compressione
NumChannels (Numero di canali)
Specifica il numero di canali. Deve essere settato a 1
se il suono è mono, a 2 se il suono è stereo, etc
SampleRate (Frequenza di campionamento)
Specifica la frequenza di campionamento del suono
ByteRate
Deve essere settato a:
SampleRate ⋅ NumChannels ⋅ BitsPerSample
8
BlockAlign
Deve essere settato a:
NumChannels ⋅ BitsPerSample
8
BitsPerSample (Bit per campione)
Specifica il numero di bit per campione.
ExtraParamSize
Viene utilizzato solo se la codifica non è PCM
ExtraParams
Viene utilizzato solo se la codifica non è PCM
Tabella 8. Descrizione del Format Chunk
- 42 -
Il Sound Data Chunk è costituito da:
Byte
iniziale
1
Dimensione
5
4
9
4
Descrizione
Subchunk2ID (Identificatore del sotto blocco 2)
Deve essere settato a “data” in codifica ASCII
Subchunk2Size (Dimensione del sotto blocco 2)
Specifica la lunghezza del resto del blocco. Deve
essere settato a:
NumSample ⋅ NumChannels ⋅ BitsPerSample
8
Data (Dati)
Deve essere settato con la sequenza di bit che
costituisce il suono
Tabella 9. Descrizione del Sound Data Chunk
La numerazione dell’offset è stata fatta ripartire da 1 ma in realtà è seguente a
quella del Format Chunk.
Per comprendere come è strutturato il campo Data del Sound Data Chunk si
prenda ad esempio un suono mono, campionato a 44100 Hz a 16 bit. In fase di
digitalizzazione, il suono sarà formato da 44100 stringhe di 16 bit al secondo,
quindi nel campo Data si avrà una successione di campioni lunghi 16 bit. Nel caso
di un suono stereo campionato a 44100 Hz a 16 bit, le stringhe di 16 bit ottenute
sono due, una per il canale destro ed una per il sinistro, quindi nel campo Data
ogni campione sarà costituito da due sottocampioni lunghi 16 bit, uno per il canale
destro e l’altro per il canale sinistro.
Nel caso di codifica PCM il file Wave avrà dimensione totale data dalla formula
36 + ( Bits per campione ⋅ Frequenza di campionamento ⋅ Numero di canali ⋅ Tempo )
dove 36 sono i bytes che costituiscono la dimensione del RIFF WAVE Chunk e
del Format Chunk, la frequenza di campionamento è definita in Hz ed il tempo è
definito in secondi.
Come nel caso del file Bitmap è evidente che per applicare un algoritmo di
steganografia basterà sostituire i bit meno significativi di ogni campione.
Per calcolare la dimensione necessaria all’inserimento di un messaggio nascosto
di lunghezza in byte L bisogna risolvere la seguente equazione:
Bits per campione ⋅ Frequenza di campionamento ⋅ Numero di canali ⋅ Tempo
L=
d
dove d è il numero di byte del file contenitore necessari per contenere un
carattere del messaggio nascosto.
- 43 -
1.5.3.3 Steganografia dei files compressi
I formati esaminati precedentemente, il file Bitmap ed il file Wave, hanno la
caratteristica di essere dei formati molto pesanti e per questo non sono molto usati
per le trasmissioni su Internet.
Per ovviare a questo problema sono stati sviluppati degli algoritmi di
compressione che diminuiscono la dimensione del file originale cercando di
preservare le caratteristiche visive o sonore del file a seconda che siano immagini
o suoni.
Gli algoritmi di compressione si suddividono in due categorie:
• algoritmi loss less: comprimono il file originale senza causare perdita di
qualità, sono quindi invertibili;
• algoritmi lossy: comprimono il file originale causando una diminuzione
della qualità e sono per questo non invertibili.
Un tipico esempio di file in cui viene utilizzato l’algoritmo loss less LZW
(Lempel Ziv Welch) è il formato per le immagini GIF (Graphics Interchange
Format).
Nei files GIF, ogni pixel viene rappresentato da un singolo byte che identifica un
colore della palette fra i 256 possibili.
In questo tipo di files non è possibile applicare l’algoritmo di steganografia
elaborato in precedenza.
Un primo algoritmo consiste nell’acquisire un'immagine con una profondità di
colore qualsiasi, limitare il numero di colori ad un numero inferiore a 256
cercando di mantenere comunque una buona qualità visiva, convertire l’immagine
così ottenuta in GIF completando la palette con dei colori molto simili a quelli
rimasti. In questo modo sarà possibile rappresentare un colore in due modi, con il
colore originale oppure con il colore aggiunto simile all'originale. Ora per iniettare
un messaggio nascosto basterà controllare nella GIF dove esiste la possibilità di
scelta fra più colori interscambiabili. Se le alternative sono due si potrà
nascondere un solo bit: se il bit è 0 si sceglierà la prima, se è 1 la seconda; se le
alternative sono quattro si potranno nascondere due bit: 00 per la prima, 01 per la
seconda, 10 per la terza, 11 per la quarta e così via.
Questa tecnica non è molto sicura in quanto è facile individuare sottoinsiemi di
colori simili che potrebbero evidenziare la presenza di un messaggio
steganografato.
Un secondo algoritmo più sicuro del precedente sfrutta la struttura della palette
della GIF. Essa si compone di 256 colori, di cui non è importante l’ordine in cui i
medesimi compaiono è quindi possibile ottenere 256! permutazioni e questo a
patto di cambiare la sequenza dei puntatori dei colori permette di rappresentare
una stessa immagine GIF in 256! modi diversi. In questa maniera sarà possibile
codificare log 2 ( 256!) = 1683 bit , cioè 210 byte, e questo indipendentemente dalle
dimensioni dell’immagine, in quanto basterà semplicemente permutare in modo
opportuno la palette. Questo algoritmo risulta essere molto conveniente se il file
contenitore risulta essere di piccole dimensioni.
- 44 -
Un terzo algoritmo, interessante per la tecnica usata, non va a modificare un file
contenitore già esistente ma genera una immagine frattale, utilizzando ad esempio
quelle dell’insieme di Mandelbrot attraverso una funzione matematica apposita.
L’immagine creata è una GIF ed il messaggio segreto viene nascosto per mezzo
della palette.
Tipici esempi di files in cui vengono applicati algoritmi distruttivi sono il file
JPEG per le immagini ed il file MP3 per l’audio.
Nei files JPEG viene applicato un algoritmo di compressione che può essere
schematizzato come in figura:
Figura 15. Schema che rappresenta l’algoritmo di compressione JPEG
L’immagine originale, usualmente codificata con uno spazio di colore RGB, viene
convertita in codifica YUV che scompone l’informazione relativa a ciascun pixel
in due componenti: la luminanza (Y), che definisce il grado di luminosità nel
range da nero a bianco, e la crominanza (UV), che definisce il colore in base al
rapporto tra due assi, uno che va dal blu al giallo (U) e l’altro che va dal rosso al
verde (V).
Poiché l’occhio umano è più sensibile alla luminanza piuttosto che alla
crominanza, l’algoritmo va a diminuire il grado di definizione della crominanza
lasciando inalterata la luminanza, riducendo fino a metà la dimensione del file
iniziale, introducendo però perdita di informazione.
A questo punto a ciascun blocco di 64 pixel viene applicata la DCT, acronimo di
Discrete Cosine Transform, cioè un insieme di operazioni matematiche che
trasformano i valori di luminosità e colore in valori di frequenza, in pratica i
valori dei pixel contenuti nei blocchi di 8 ⋅ 8 presi dall’immagine originale che
variano da 0 a 255 vengono trasformati in frequenze che variano da -721 a 721.
Ciascuno dei 64 valori di frequenza viene diviso per uno specifico coefficiente di
quantizzazione ed il valore approssimato all’intero più vicino, introducendo
perdita di informazione. I coefficienti hanno un peso in modo tale da preservare le
frequenze che l’occhio umano percepisce in modo maggiore, quindi le frequenze
più basse memorizzate nell’angolo superiore di ogni blocco vengono mantenute,
mentre le altre vengono eliminate.
I valori ottenuti dal passaggio precedente vengono compressi attraverso un
algoritmo loss less, utilizzando l’algoritmo di Huffman o il Q-coding. Infine
vengono inseriti nel file la tabella contenente i coefficienti di quantizzazione ed i
valori della codifica entropica.
- 45 -
Una possibile applicazione di un algoritmo steganografico ad una immagine JPEG
si basa sul fatto che la matrice dei coefficienti ottenuti dalla DCT è un insieme di
valori non interi, e poiché la loro rappresentazione informatica è intera deve
essere applicato un processo di arrotondamento, proprio con esso, modificandolo
appositamente è possibile inserire un messaggio nascosto.
Questo algoritmo risulta essere molto robusto in quanto riesce ad evitare la perdita
del messaggio nascosto anche se il file viene compresso nuovamente con un
algoritmo lossy.
La codifica MP3 sfrutta la psico-acustica per eliminare la ridondanza che esiste in
un segnale audio. L’orecchio umano, come studiato da Fletcher e Munson, risulta
essere maggiormente sensibile alle frequenze comprese tra 2 e 5 kHz.
Figura 16. Soglia di udibilità di un singolo tono
Quindi è possibile eliminare dallo spettro del segnale in analisi le frequenze che
comunque l’orecchio umano medio non percepirebbe: le bassissime e le alte
frequenze.
Un altro fattore che deve essere esaminato è il cosiddetto mascheramento.
Si parla di mascheramento nel dominio della frequenza quando un suono di
debole intensità ad una certa frequenza viene sovrastato da un suono ad alta
intensità nei pressi della stessa frequenza, nell’ordine di qualche centinaio di Hz e
l’orecchio umano riesce a percepire solo il secondo.
Si parla di mascheramento nel dominio del tempo, quando ad esempio si hanno
due suoni, uno debole ed uno forte nei pressi della stessa frequenza, quando
quello forte cessa, l’orecchio umano non percepisce immediatamente il suono
debole, ma dovrà trascorrere un certo tempo di latenza, in quanto la membrana del
timpano deve assestarsi.
In conclusione, l’effetto del mascheramento permette di eliminare una grande
quantità di spettro del segnale audio perchè non udibile.
Per codificare un file audio in MP3, si suddivide il segnale in 32 sottobande
attraverso dei filtri, per ognuna delle stesse viene calcolato il valore per la soglia
di mascheramento nel tempo ed in frequenza relativi alle bande adiacenti. Se il
segnale audio è stereo si riesce ad eliminare ancora della ridondanza dovuta al
fatto che l’orecchio umano al di sotto di certe frequenze non percepisce la
posizione spaziale dei suoni, quindi è possibile per le stesse usare il segnale ad un
unico canale.
A questo punto vengono effettuate le operazioni di quantizzazione in modo tale da
introdurre il minor rumore possibile e di codifica entropica con algoritmi loss less,
- 46 -
nella fattispecie si utilizza l’algoritmo di Hufmann. Per limitare il disturbo dovuto
alla quantizzazione vengono applicati dei fattori di scala ad ogni banda.
Infine si crea il file immagazzinando il flusso di bit in uscita.
Come per il file JPEG, per applicare un algoritmo steganografico al file MP3 si
procede andando a modificare i valori ottenuti dalla quantizzazione a cui sono
stati applicati i fattori di scala per limitare il rumore da loro introdotto.
1.5.4 Stima sulla sicurezza degli algoritmi steganografici
La steganografia, ha lo scopo di occultare la trasmissione del messaggio segreto,
nel senso che un possibile attaccante non dovrebbe neanche sapere che si sta
effettuando una trasmissione.
Seguendo il principio di robustezza proposto da Kerckhoff per cui la sicurezza del
sistema deve basarsi sull'ipotesi che il “nemico” abbia piena conoscenza dei
dettagli di progetto e sull’implementazione del sistema stesso, tutti gli algoritmi
proposti non sono sicuri.
Per aumentare la sicurezza di una trasmissione si può pensare di usare in modo
combinato la steganografia e la crittografia, cioè il messaggio segreto viene prima
cifrato e poi occultato in un file contenitore. Però questa soluzione non aumenta in
sé la robustezza dell’algoritmo steganografico in quanto solo il fatto che un
possibile attaccante sia riuscito a sapere che il file contiene un messaggio segreto
rende minima la robustezza dell’algoritmo utilizzato.
Come per la crittografia esiste una scienza che studia il modo di svelare le
procedure steganografiche chiamata stegoanalisi.
Le principali tecniche di stegoanalisi sono:
• stego only: lo stegoanalista dispone solo del file steganografato e deve
cercare di svelare il messaggio nascosto;
• know cover: lo stegoanalista dispone sia del file steganografato che del
file contenitore, può quindi effettuare dei confronti in modo da cercare
differenze tra i due files;
• know message; lo stegoanalista dispone sia del file steganografato sia del
messaggio nascosto, può quindi cercare di scoprire il metodo utilizzato per
nascondere l’informazione segreta;
• chosen stego: lo stegoanalista dispone sia del file steganografato che
dell’algoritmo di steganografia utilizzato;
• chosen message; lo stegoanalista genera alcuni files steganografati
servendosi di opportuni strumenti steganografici partendo da un messaggio
preciso, cercando degli elementi che lo aiutino ad identificare l’uso di un
metodo specifico.
L’attacco know cover risulta essere il più efficace in quanto se i due files che
dovrebbero essere uguali presentano delle differenze, potrebbe significare che ci
sia un messaggio nascosto, anche se la differenza potrebbero essere dovuta
semplicemente da una diversa informatizzazione e quindi dal diverso rumore
introdotto.
- 47 -
Tenuto conto delle possibili tecniche di stegoanalisi per migliorare la robustezza
di un algoritmo bisognerà seguire alcune regole:
• mai usare come files contenitore, files pubblici o facilmente reperibili;
• mai usare più volte lo stesso file come contenitore;
• distruggere i files originali dopo averli usati;
poichè darebbe allo stegoanalista la possibilità di effettuare un attacco know
cover.
Un altro punto cruciale per valutare la robustezza di un algoritmo è il fatto che
una possibile compressione del file steganografato possa cancellare il messaggio
segreto, quindi gli algoritmi proposti per i files Bitmap e Wave sono da questo
punto di vista inutilizzabili, mentre risultano essere abbastanza robusti gli
algoritmi utilizzati sui files JPEG e MP3 se accortamente progettati.
L’algoritmo che sfrutta la modifica della palette sui files GIF risulta essere
robusto sotto questo punto di vista ma è banalmente riconoscibile da un attacco
chosen stego.
Le metodologie pratiche che si utilizzano per effettuare controlli sulle immagini
sono due:
• analisi visuali;
• analisi statistiche.
Le analisi visuali sfruttano degli algoritmi di filtering che riescono a rendere
evidente la presenza di un messaggio nascosto ma risultano essere molto lente se
la mole di file da esaminare è notevole.
Le analisi statistiche confrontano la distribuzione di frequenza dei colori in un
potenziale file steganografato con la distribuzione di frequenza teoricamente
attesa per un file steganografato, per scoprire la presenza di un eventuale
messaggio nascosto.
- 48 -
1.6 I protocolli web
In questo paragrafo verranno descritti i protocolli http e https.
Verrà in primo luogo fornita una breve storia del loro sviluppo, dopodichè
verranno spiegate le modalità di scambio dei dati utilizzate.
Infine saranno esposti pregi e difetti dei due protocolli.
1.6.1 Il protocollo http
Http, acronimo di Hyper Text Transfer Protocol, è un protocollo di trasferimento
per il world wide web.
Fu progettato alla fine del 1980 da Tim Berners-Lee, la versione 0.9 venne
utilizzata per la condivisione delle informazioni tra la comunità dei fisici.
Nel 1991 fu sviluppata, sempre dallo stesso Bernere-Lee, la versione 1.0 che fu
classificata nel 1996 dalla IETF come RFC 1945.
Con l’avvento dei browser grafici il protocollo http 1.0 risultò essere inadeguato,
in quanto non era in grado di ospitare più siti www su uno stesso server, non
permetteva il riuso delle connessioni disponibili e non garantiva una sicurezza
adeguata.
Nel 1997 si passò quindi alla versione 1.1, presentata come RFC 2068 nel 1997 ed
aggiornata nel 1999 come descritto dal RFC 2616.
L’http sfrutta il protocollo TCP/IP per fornire i propri servizi di trasmissione.
La porta TCP utilizzata usualmente è la 80.
Figura 17. Architettura del protocollo http
L’http a differenza di protocolli come l’Ftp, il Telnet e l’Smtp, non è stato
progettato esplicitamente per trasferire dati specifici ma permette il trasferimento
di qualsiasi tipo file.
L’http è un protocollo di tipo request/response.
Fino alla versione 1.0 la connessione veniva stabilita da un client tramite una
request e chiusa dal server per mezzo di una response, con la versione 1.1 dopo la
- 49 -
response la connessione non viene terminata ma è possibile procedere con una
nuova coppia request/response in modo da gestire transazioni multiple.
L’introduzione di questo metodo è dovuta alla grande complicatezza delle pagine
html, che contengo immagini, suoni, etc, quindi per poterle scaricare avrebbero
innescato un numero enorme di request/response singole che avrebbero occupato
molte risorse del server mentre usando request/response multiple il server
gestisce, ad esempio, il client fino alla consultazione completa dell’intera pagina.
La request e la response sono gestite come un messaggio MIME, Multipurpose
Internet Mail Extension, ossia come un messaggio di testo, quindi anche
immagini, suoni, etc sono trattati come tali, questo perché l’http implementa i
protocolli già forniti da Internet a livello più basso.
La request è formata da tre campi:
• request line;
• header fields;
• message body.
La request line è composta dal metodo di richiesta, dall’URI e dalla versione del
protocollo.
L’URI, Uniform Resource Identifier, identifica la risorsa su cui è applicata la
request.
I metodi di richiesta indicano il tipo di operazione che dovrà compiere il server
sull’URI.
I metodi di richiesta più comuni sono:
• GET, viene usato per ottenere il contenuto della risorsa dell’URI, ad
esempio una pagina html;
• HEAD, viene usato per ottenere l’header dell’URI, ad esempio per
controllare la data di modifica di un file, questo metodo non prevede l’uso
del body;
• POST, viene usato per inviare informazione al server, l’URI identifica
cosa si sta inviando ed il body ne racchiude il contenuto, viene ad esempio
utilizzato per inviare i dati contenuti in un form di una pagina html.
Gli header permettono al client di trasmettere ulteriori informazioni sulla richiesta
e su se stesso.
Gli header di richiesta più comuni sono:
• Host: contiene il nome del server a cui si riferisce l'URI. Con il protocollo
http/1.1 risulta essere un campo obbligatorio in quanto permette l'uso dei
virtual host;
• User-Agent: contiene informazioni sul client: tipo browser, produttore,
versione, etc.
La response è formata da tre campi:
• status line;
• header fields;
• message body.
- 50 -
La status line contiene un codice a tre cifre che identifica un messaggio di risposta
alla request formato in base al seguente schema, dove il carattere “x” identifica un
numero da 0 a 9:
• 1xx: Informational: contiene messaggi informativi;
• 2xx: Success: indica se la richiesta è stata eseguita con successo;
• 3xx: Redirection: contiene indicazioni su come ottenere la richiesta
effettuata, poiché il server non è in grado di eseguirla in modo immediato;
• 4xx: Client error: contiene informazioni sul tipo di errore eseguito nella
richiesta del client che rende impossibile il soddisfacimento dal server;
• 5xx: Server error: contiene informazione sul tipo di errore eseguito dal
server per cui non riesce a soddisfare la richiesta.
Gli header permettono al server di inserire ulteriori informazioni che non sarebbe
stato possibile inserire nella status line.
Gli header più comuni sono:
• Server: contiene informazioni sul server: tipo e versione;
• Content-Type: contiene informazioni sul tipo di contenuto restituito. Tali
informazioni, dette “Media type”. Per esempio ad una risposta HTML
sono frequenti i tipi MIME (RFC 1521):
• text/html: identifica un documento html;
• text/plain: identifica un documento di testo non formattato;
• image/jpeg: identifica un’immagine di formato JPEG.
Il protocollo http offre la possibilità gestire la request/response chain ossia, di
regolare il percorso logico che seguirà la request/response dal client al server
anche tramite l’inserimento di entità intermedie.
Una request/response chain può essere modificata da tre entità:
• Proxy;
• Gateway;
• Tunnel.
- 51 -
Il proxy è una entità software che si trova fra il client ed il server.
Quando il client inoltra una request, essa viene indirizzata al proxy che la rinvia al
server, dopodichè il server invia la response al proxy che la rinvia al client.
Il proxy ha la funzione di caching, ossia memorizza tutte le pagine che i client
richiedono e quelle raggiungibili dalle stesse, poichè hanno un’alta probabilità di
essere richieste, quindi l’utilizzo del proxy risulta vantaggioso quando la linea tra
esso ed il server è più veloce rispetto a quella tra il client ed il server.
Da notare è il fatto che la connessione risulta essere sempre client-proxy,
qualunque sia il server finale.
Figura 18. Connessione http con proxy
Il gateway è un’entità che si trova tra il client ed il server, ma a differenza del
proxy, il client vede il gateway come il server finale.
Il gateway prende la request inviata dal client verso il server interessato, attende la
response e la rinvia al client, in modo trasparente.
Il gateway risulta essere vantaggioso quando ci si trova a comunicare con una
serie di server che rispondono allo stesso nome, infatti esso smisterà le varie
request ai server opportuni facendo percepire al client di comunicare con un unico
server e quindi ottimizzando la connessione.
Figura 19. Connessione http con gateway
Il tunnel è un’entità che permette lo scambio tra due collegamenti senza
modificare la comunicazione; è usato quando la comunicazione necessita di
- 52 -
passare da un punto ad un altro attraversando un’entità che non è in grado di
trasmettere tale messaggio.
Un esempio di utilizzo del tunnel avviene quando sulla rete è presente un firewall.
Il tunnel permette di instaurare una connessione punto-punto ai capi del firewall,
in modo da far “vedere” al client il server che altrimenti sarebbe stato nascosto,
quindi il tunnel viene attivato solo quando avviene una request per il server
nascosto, mentre rimane disattivato per le altre richieste. L’utilizzo del tunnel
risulta essere trasparente al client, in quanto se la request viene lasciata passare al
server, il client avrà la sua response, mentre se il tunnel la blocca il client riceverà
un errore dal browser.
Figura 20. Connessione http con tunnel
Il protocollo http ha essenzialmente tre difetti.
Un primo difetto è dovuto al fatto che la connessione TCP, quando viene aperta
ha una velocità molto bassa, questa poi aumenta fino ad andare a regime, una
transazione request/response spesso non dura abbastanza per raggiungere tale
velocità e quindi l’http risulta essere inefficiente. Un miglioramento è stato
apportato con le request/response multiple, che aumentando la durata della
connessione, aumentano la probabilità di raggiungere la velocità di regime.
Un secondo difetto si ha perché l’http usa uno scambio dei dati stateless, cioè non
esiste una memoria delle richieste del client e delle risposte del server, quindi se
ad esempio si sta compilando una serie di form concatenate e cade la linea quando
ancora non è stata terminata la procedura, tutta la compilazione viene cancellata
poiché quasi sicuramente alla nuova connessione l’indirizzo IP sarà diverso,
oppure potrebbe accadere che ad un altro utente, che si collega allo stesso server
appena è caduta la linea dell’altro, venga assegnato l’indirizzo IP precedente
dell’altro utente ed esso si ritroverebbe con le form compilate dal precedente
utente. Una possibile soluzione è l’utilizzo dei cookies che sono dei file che
vengono inviati dal server al client in cui sono contenute informazioni riguardanti
la connessione ed il server può richiederle se necessario al client.
Il terzo difetto deriva dal fatto che la trasmissione dati dell’http è in chiaro, quindi
risulta relativamente facile osservare lo scambio che avviene tra il client ed il
- 53 -
server anche quando essa risulta essere riservata, ad esempio nello scambio di
credenziali di autenticazione.
1.6.2 Il protocollo https
L’https è stato introdotto per migliorare la sicurezza del protocollo http, che
attraverso l’utilizzo di tecniche di crittografia e di autenticazione riesce a garantire
un elevato livello di protezione nella trasmissione dei dati.
L’https in pratica interpone fra il TCP e l’http il protocollo SSL.
Figura 21. Architettura del protocollo https
Il protocollo SSL, acronimo di Secure Socket Layer, fu sviluppato
originariamente da Netscape, successivamente fu migliorato ed adottato come
standard per Internet sotto il nome di TLS, Transport Layer Security, come
descritto nel RFC 2818.
Il protocollo SSL garantisce che solamente il client ed il server siano in grado di
conoscere il contenuto della comunicazione.
La porta TCP utilizzata usualmente è la 443.
Una tipica trasmissione di un messaggio utilizzando il protocollo SSL si basa su
due fasi.
La prima fase ha la funzione di effettuare l'autenticazione reciproca del client, del
server e di scambio della chiave di cifratura da utilizzare nel corso della
connessione.
La seconda fase è quella vera e propria di trasmissione del messaggio in cui lo
stesso viene suddiviso in blocchi di lunghezza prefissata, ciascun blocco viene
compresso e gli viene aggiunto il codice MAC atto a garantire l'autenticità dei
dati, il blocco complessivo viene cifrato utilizzando un algoritmo simmetrico ed in
testa viene posto l’header SSL.
Il blocco così composto viene inviato al server tramite il protocollo TCP/IP.
- 54 -
Il server alla ricezione del blocco effettuerà il procedimento inverso rispetto a
quello effettuato dall’utente, quindi eliminerà l’header SSL decifrerà il messaggio
utilizzando la chiave opportuna, verificherà che il codice MAC sia quello del
client, eliminerà il codice MAC, decomprimerà il blocco risultante ed infine,
riunendo i vari frammenti, otterrà il messaggio originale.
Riassumendo, la procedura di criptazione si basa su una chiave pubblica che il
server invia al client ad ogni connessione, per mezzo di essa vengono generati
pacchetti criptati che possono essere letti solo dal server che ha rilasciato la chiave
pubblica poiché sarà l’unico host a possedere la chiave privata.
L'SSL Handshake protocol coordina gli stati del client e del server, permettendo
così ai sistemi operativi di ognuno di operare in modo efficace. Lo stato è
rappresentato in modo doppio: una volta come lo stato operativo corrente, e,
durante la fase di handshake, come lo stato in attesa; inoltre sono mantenuti
separati gli stati di lettura da quelli di scrittura.
Una sessione SSL può includere più di una connessione sicura; inoltre le
applicazioni possono avere più sessioni simultanee.
Lo stato della sessione è costituito dai seguenti elementi:
• session identifier: è una sequenza arbitraria di bytes scelta dal server per
identificare uno stato attivo della sessione, o comunque riesumabile;
• peer certificate: è un certificato X.509 del peer. Può essere nullo;
• compression method: specifica l'algoritmo usato per comprimere i dati
prima della crittografia;
• cipher spec: specifica l'algoritmo di crittografia bulk (ad es. null, DES,
etc.) e l'algoritmo MAC (per es. MD5 o SHA). Stabilisce inoltre alcuni
parametri dell’algoritmo di cifratura;
• master secret: sono 48 bytes segreti, condivisi dal client e dal server;
• is resumable: è un flag che indica se la sessione può essere usata per
iniziare nuove connessioni.
Lo stato della connessione è costituito dai seguenti elementi:
• server and client random: è una sequenza di bytes scelti dal server e dal
client per ogni connessione;
• server write MAC secret: è la sequenza segreta usata nelle operazioni
MAC sui dati scritti dal server;
• client write MAC secret: è la sequenza segreta usata nelle operazioni
MAC sui dati scritti dal client;
• server write key: è la chiave per i dati cifrati dal client e messi in chiaro
dal server;
• initialization vectors: se è usato un blocco cifrato con algoritmo CBC,
allora per ogni chiave è mantenuto un vettore d'inizializzazione (IV).
Questo campo è inizializzato dal protocollo SSL handshake. Poi il codice
cifrato finale di ogni record è salvato per essere usato con i record
seguenti;
- 55 -
•
sequence numbers: ognuna delle due parti comunicanti mantiene separati
numeri di sequenza per i messaggi spediti e ricevuti per ogni connessione.
Quando uno dei due manda o riceve un messaggio di change cipher spec,
il numero appropriato della sequenza è posto a zero. I numeri di sequenza
sono espressi da 64 bits e non possono quindi eccedere 264-1.
Il protocollo SSL Record layer riceve i dati dai livelli superiori senza
interpretarli, in forma di blocchi non vuoti di dimensione arbitraria. Esso
frammenta i blocchi di informazioni in SSLPlaintext records, di dimensione
massima di 214 bytes.
L’SSLPlaintext record è costituito da:
• ProtocolVersion: specifica la versione del protocollo in uso;
• ContentType: è formato da 4 campi:
o change_cipher_spec: specifica il cambio di cifratura usato per la
comunicazione;
o alert: indica eventuali condizioni di errore;
o handshake: negoziazione che avviene nella sessione SSL;
o application_data: sono i dati trasmessi nella sessione SSL.
Quando viene applicato un algoritmo di compressione la SSLPlaintext si
trasforma in una SSLCompressed.
Tutti i records sono compressi tramite un algoritmo definito nello stato corrente
della sessione anche se all'inizio viene definito come CompressionMethod.null.
Nel caso in cui venisse usata una CipherSpec i dati relativi agli algoritmi di
compressione vengono cancellati dallo stato.
L’algoritmo di compressione deve essere di tipo loss less e non può aumentare la
lunghezza del contenuto più di 1024 bytes. Se la decompressione incontra un
SSLCompressed.fragment che scompattato fosse più lungo di 214 bytes, deve
segnalare un fatal decompression_failure alert.
Tutti i records vengono protetti utilizzando algoritmi di crittografia e MAC
definiti nel CipherSpec. Anche se inizialmente il CipherSpec è settato a
SSL_NULL_WITH_NULL_NULL vengono comunque utilizzati gli algoritmi di
cifratura e MAC.
Le tecniche usate per le operazioni di crittografia e di MAC sono stabilite nel
CipherSpec.cipher_type; tali metodi trasformano una struttura SSLCompressed in
una SSLCiphertext. La decifratura inverte tale trasformazione. Le trasmissioni
includono anche un numero di sequenza, in modo che i messaggi persi, alterati o
intrusi siano rilevabili.
Possono essere utilizzati due tipi di cifratura, quella a flusso e quella a blocchi.
Gli algoritmi stream ciphers convertono le strutture SSLCompressed.fragment in
stream SSLCiphertext.fragment e viceversa.
Il MAC sarà definito come:
hash(MAC_write_secret + pad_2 + hash(MAC_write_secret + pad_1 + seq_num + length + content))
- 56 -
dove:
• +: denota la concatenazione;
• pad_1: è il carattere 0x36 ripetuto 48 volte per MD5 o 40 volte per il
SHA;
• pad_2: è il carattere 0x5c ripetuto lo stesso numero di volte del
precedente;
• seq_num: è il numero di sequenza del messaggio;
• hash: è l'algoritmo hash definito nella CipherSpec.
Concludendo la lunghezza del SSLCiphertext sarà:
SSLCiphertext.lenght = SSLCompressed.lenght + CipherSpec.hash_size
Gli algoritmi block ciphers, trasformano la struttura SSLCompressed.fragment in
un blocco SSLCiphertext.fragment, dove però ci sarà una particolare attenzione ad
operazioni di padding, le quali aggiungono caratteri per forzare la lunghezza del
plaintext ad essere un multiplo della lunghezza dei blocchi cifrati dall'algoritmo di
crittografia.
Il protocollo SSL Change cipher spec è finalizzato a segnalare le transizioni
nelle strategie di crittografia. Il protocollo consiste di un singolo messaggio, che è
cifrato e compresso secondo il Current CipherSpec. Il messaggio consiste di un
singolo byte di valore uno.
Il messaggio di change cipher spec è mandato sia dal client che dal server per
notificare all'altro che da quel momento in poi i records saranno protetti usando le
nuove, appena negoziate CipherSpec e chiavi. La ricezione di questi messaggi
causa al ricevente la copia del pending read state nel current read state: infatti sia
il server che il client mantengono separato questo doppio stato. Quando il client o
il server manda un messaggio di change cipher spec, esso copia il pending write
state nel current write state.
Il client manda allora un messaggio di change cipher spec seguente i messaggi di
handshake key exchange and certificate verify, ed il server ne manda uno dopo
aver processato con successo il messaggio di key exchange ricevuto dal client.
Quando l'handshake è completato il client ed il server si scambiano i messaggi di
change cipher spec ed iniziano a comunicare, usando le nuove proprietà appena
concordate. Un messaggio di change cipher spec inaspettato provoca un
unexpected_message alert. Quando si riesuma una sessione, il messaggio di
change cipher spec è spedito subito dopo il messaggio di hello.
Il protocollo SSL Alert ha lo scopo di inviare messaggi di alert in caso di
anomalie. Ogni alert ha una priorità, ad esempio un messaggio con livello fatal si
risolve con l’immediata terminazione della connessione. Come gli altri messaggi
anche quelli di alert sono cifrati e compressi come specificato nello stato corrente
della connessione.
Esistono due tipi di alert: quelli di chiusura e quelli di errore.
- 57 -
Gli alert di chiusura vengono inviati quando il client ed il server devono
comunicarsi che la connessione sta terminando per evitare un attacco. Entrambi
possono iniziare lo scambio dei messaggi di chiusura. In particolare il messaggio
close_notify che notifica al ricevente che il mittente non trasmetterà più su quella
connessione. La sessione diviene non riesumabile se qualche connessione è
terminata senza il dovuto messaggio close_notify con livello warning.
Gli alert di errore vengono inviati quando uno dei due interlocutori riscontra un
errore, allora la parte che lo ha rivelato manda un messaggio all'altra; dopo la
trasmissione/ricezione di un messaggio di fatal alert, entrambe le parti
immediatamente chiudono la connessione. Sia il server che il client sono obbligati
a cancellare ogni identificatore di sessione, chiave, e altri segreti associati con la
connessione fallita.
I principali messaggi di alert di errore sono:
• unexpected_message: identifica che un messaggio inappropriato è stato
ricevuto. Questo tipo di allerta è sempre fatale;
• bad_record_mac: questa allerta è spedita quando un record è ricevuto con
un errato MAC; questo messaggio è sempre fatale;
• decompression_failure: identifica che la funzione di decompressione ha
ricevuto un errato input, ad esempio dati che si espandono oltre la
lunghezza loro assegnata; questo messaggio è sempre fatale;
• handshake_failure: indica che il mittente è incapace di negoziare un set
accettabile di parametri di sicurezza tra quelli possibili; questo messaggio
è sempre fatale;
• no_certificate: può essere mandato in risposta ad un certificate request se
non è disponibile una certificazione appropriata;
• bad_certificate: viene mandato in caso di certificazione errata, contenente
una firma che non è verificata correttamente, etc;
• unsupported_certicate: identifica una certificazione non supportata;
• certificate_revoked: indica che una certificazione è stata revocata dal suo
firmatario;
• certificate_expired: indica che una certificazione è scaduta o attualmente
non valida;
• certificate_unknown: indica che un problema non meglio specificato è
sorto nel processare la certificazione;
• illegal_parameter: indica che un campo dell’handshake è di dimensione
errata o inconsistente con altri campi; questo messaggio è sempre fatale.
Il protocollo SSL Handshake fornisce i parametri per la crittografia che
compongono lo stato della sessione, ed opera interfacciandosi con il protocollo
SSL Record Layer. Quando un client ed un server iniziano a comunicare,
concordano sulla versione del protocollo, scelgono gli algoritmi di crittografia, si
autenticano a vicenda, ed usano la crittografia a chiave pubblica per generare dati
segreti condivisi. Questi processi sono eseguiti nel protocollo handshake, in
particolare il client spedisce un messaggio di client hello al quale il server deve
- 58 -
rispondere con un messaggio di server hello, altrimenti si verificherebbe un errore
fatale e la connessione fallirebbe. I messaggi client hello e server hello sono usati
per stabilire le policy di sicurezza ottenibili fra client e server.
Ad esempio il messaggio client hello avrà i seguenti attributi:
• protocol version: contiene la versione del protocollo utilizzato;
• session ID: contiene un numerio identificativo;
• cipher suite: contiene le combinazioni di algoritmi di crittografia
supportati dal client, il server sceglierà una cipher suite oppure, se non c'è
una scelta accettabile chiuderà la connessione;
• compression method: contiene una lista di algoritmi di compressione
supportati dal client, se il server non ne supporta nessuno la sessione sarà
chiusa.
In modo analogo si avranno gli attributi del server hello dove nella cipher suite
sarà contenuta la singola cipher suite, scelta dalla lista fornita dal client e nella
compression method sarà contenuto il singolo metodo di compressione scelto dal
server dalla lista fornita dal client.
Inoltre, hanno due valori casuali che vengono generati e scambiati: il
ClientHello.random ed il ServerHello.random, i quali devono essere
indipendenti l’uno dall’altro.
Dopo il messaggio di hello il server spedisce il suo certificato, se deve essere
autenticato, oppure invia un messaggio di server key exchange se ad esempio il
server non ha certificato, o se il suo certificato è solo per la firma. Se il server
viene autenticato, può richiedere un certificato al client se ciò è in accordo con la
cipher suite scelta.
A questo punto il server manderà il messaggio di server hello done, indicando che
la fase hello-message dell'handshake è completa, ed attenderà una risposta dal
client.
Se il server ha mandato un messaggio di certificate request, il client dovrà spedire
o un certificate message o una no certificate alert. Il messaggio di client key
exchange verrà mandato adesso, il cui contenuto dipende dall'algoritmo a chiave
pubblica selezionato con il client hello ed il server hello. Se il client ha spedito un
certificato con abilitazione alla firma, allora un messaggio di certificate verify
verrà spedito per verificare esplicitamente il certificato.
A questo punto un messaggio di change cipher spec viene mandato dal client, che
copia il pending Cipher Spec nel current Cipher Spec. Il client manda
immediatamente il messaggio di finished usando i nuovi algoritmi, chiavi e
stringhe segrete concordate . Il server risponde con un messaggio di change cipher
spec, copia il pending Cipher Spec nel current Cipher Spec, e spedisce il suo
messaggio di finished in accordo con la nuova Cipher Spec.
In questo modo la fase di handshake è terminata ed il client ed il server possono
cominciare a scambiare dati del livello applicazione.
Se il client ed il server decidono di riabilitare una precedente sessione o di
duplicarne una esistente, il client manderà un client hello usando la Session ID
della sessione da riesumare, il server controllerà la sua session cache per trovare
una corrispondenza: se questa viene trovata il server manda un server hello con lo
- 59 -
stesso Session ID. Adesso sia il client che il server devono mandare un messaggio
di change cipher spec e procedere direttamente fino al messaggio di finished. Una
volta che il ripristino è completo, il client ed il server possono iniziare a
scambiarsi dati di livello applicazione. Se il server non trova una corrispondenza
di Session ID nella propria session cache, allora il server genera un nuovo Session
ID e verrà eseguito un handshake completo.
Il protocollo SSL risulta essere non sicurissimo se utilizza algoritmi di cifratura
poco robusti, ad esempio l’RC4 con chiave a 40 bits risulta essere poco affidabile
poichè alcuni gruppi indipendenti sono riusciti a forzarlo in circa 8 giorni.
Un altro difetto del protocollo SSL sta nel fatto che non protegge da attacchi agli
host, quindi sarebbe conveniente proteggersi con software di garanzia
dell’integrità dei dati come ad esempio Tripwire.
Tripwire usa funzioni hash sicure per garantire che i documenti non siano
cambiati rispetto ad una versione di riferimento protetta in scrittura, se verifica un
eventuale attacco, notifica all’amministratore del sistema con una email
l’avvenuta intrusione e ripristina i file alla situazione iniziale.
Un ultimo difetto del protocollo SSL, è quello per cui esso riduce le prestazioni
del server, in quanto lo stesso si trova a cifrare la pagina web richiesta dal client e
se essa è molto pesante si potrebbero riscontrare notevoli rallentamenti o
addirittura il timeout della pagina; quindi risulta conveniente progettare le pagine
che useranno l’https con poca grafica e più contenuti testuali.
- 60 -
CAPITOLO 2
In questo capitolo verrà presentata l’azienda presso la quale è stato effettuato il
tirocinio.
Si illustrerà poi la situazione di partenza in seguito alla quale è stato sviluppato il
progetto, evidenziando le specifiche richieste poste in corso d’opera.
- 61 -
2.1 La Phi.d’α
αlpha s.r.l.
La Phi.d'αlpha s.r.l. è un’azienda di consulenza strategica di impresa che si occupa
dello sviluppo di sinergie estremamente articolate e mette in comunicazione i vari
comparti di una azienda, intervenendo tempestivamente sulle aree deboli al fine di
seguire costantemente ed ottimizzare i processi aziendali con soluzioni integrate.
In altri termini, la Phi.d'αlpha s.r.l., aiuta le imprese ad organizzarsi e strutturarsi
per far fronte al mercato globale partendo dalla individuazione del merito
creditizio sino ad arrivare alla valutazione dell'azienda.
Essenzialmente, la Phi.d'αlpha s.r.l., si occupa di consulenza finanziaria ed
economica, permettendo così alle aziende clienti di creare valore ottemperando i
seguenti obiettivi:
• ottimizzazione dei flussi di cassa relativi alla gestione operativa;
• minimizzazione del livello di rischio aziendale;
• minimizzazione nel costo delle fonti di finanziamento.
L'attività della Phi.d'αlpha si esplica nelle seguenti possibili fasi di intervento:
• analisi andamentale;
• analisi quantitativa;
• analisi qualitativa e dei rischi operativi.
Per analisi andamentale si intende l’analisi dei rapporti che l’azienda cliente
instaura con il sistema bancario, quindi si effettua una verifica: dei rapporti
bancari tramite web-banking, dei movimenti, dei saldi contabili e liquidi e delle
condizioni di tenuta conto, della coerenza tra il numero di banche affidanti e le
dimensioni aziendali, studiando i dati storici, attuali ed incrementali.
Per analisi quantitativa si intende l’analisi della struttura patrimoniale e
dell’equilibrio finanziario dell'azienda, quindi ci si troverà ad analizzare bilanci
aziendali in modo da misurare la capacità dell'azienda di svilupparsi, di produrre
risorse adeguate e reddito sufficiente per la copertura del debito e di remunerare il
capitale di rischio.
Per analisi qualitativa e dei rischi operativi si intende l’analisi dell’attività
aziendale e della sua presenza sul mercato, studiando la tipologia della clientela e
dei fornitori, analizzando rischi aziendali, nella fattispecie anche quelli dovuti ai
contratti utilizzati sia per operazioni commerciali sia per rapporti con gli istituti di
credito.
- 62 -
2.2 Descrizione del progetto
Da quanto descritto nel paragrafo precedente è facile evincere che la Phi.d'αlpha
s.r.l. si occupa in maniera frequente della trattazione di documenti finanziari ed
economici, quindi di dati sensibili e riservati che devono essere trasmessi per la
loro natura, con modalità sicure.
Fino ad oggi la Phi.d'αlpha s.r.l. ha utilizzato per la trasmissione di tali documenti,
o mezzi non multimediali o semplici email.
Con l’avvento di nuove normative giuridiche più restrittive e con l’aumento di
possibili azioni di spionaggio aziendale dovuto ad hacker, la Phi.d'αlpha s.r.l. ha
deciso di dotarsi di un portale web in cui fosse possibile trasmettere documenti di
elevata sensibilità in modo sicuro.
La Phi.d'αlpha s.r.l. possedeva già un sito web ma non predisposto a tale esigenza,
in quanto sviluppato diversi anni orsono risultava essere statico in quanto creato in
semplice linguaggio html.
Il vecchio sito risiede su un server Microsoft in hosting con supporto database
Microsoft Access e linguaggio ASP, implementato su protocollo http.
La Phi.d'αlpha s.r.l. ha richiesto esplicitamente di utilizzare tali tecnologie per la
realizzazione del loro progetto.
Il progetto richiesto consiste nell’implementazione di un portale web ad accesso
riservato con controllo condizionato degli accessi e criptazione dei documenti
depositati.
Essenzialmente la loro esigenza era quella di avere una “zona” su web dove poter
condividere in modo sicuro documenti che poi sarebbero potuti essere consultati
anche da diversi clienti e collaboratori.
La gestione delle credenziali di autenticazione sarà gestita dalla Phi.d'αlpha s.r.l.
stessa che, con cadenza trimestrale, fornirà ai suoi clienti e collaboratori un
username ed una password per accedere all’area riservata, quindi non sarà
implementata una sezione di registrazione in quanto tale area è di possibile
accesso ai soli collaboratori o clienti.
Punto focale per la realizzazione è il fatto che i clienti ed i collaboratori sono in
numero limitato, nell’ordine di qualche decina.
Una richiesta essenziale era quella di creare una tecnologia che rendesse il file
trasmesso attribuibile solo ad una certa persona.
Un requisito fondamentale, sollecitato fin dall’inizio del tirocinio, era quello di
realizzare un’interfaccia molto semplice, friendly, utilizzabile anche da persone
poco pratiche nell’uso dei computers.
Infine è stato richiesto di aggiornare tutto il sito in modo da mantenere i vecchi
contenuti ma modificandone la struttura in modo da renderlo più dinamico, per
esempio creando sulle pagine web un’area dove fossero presentate le news del
sito, aggiornabili tramite un database.
- 63 -
CAPITOLO 3
In questo capitolo verrà descritta in modo accurato la realizzazione del progetto
stesso, giustificando le eventuali scelte progettuali, in modo da far comprendere i
vantaggi e gli svantaggi di alcune tipologie di decisioni.
- 64 -
3.1 Analisi delle specifiche
L’obiettivo principale di questo tirocinio è stato la realizzazione di un portale
web, che facesse collimare la sicurezza con la semplicità di utilizzo.
Prima di descrivere la fase realizzativa vera e propria si spiegheranno le
motivazioni che hanno portato a certe scelte progettuali.
Innanzitutto sono state esaminate le tecnologie disponibili per la realizzazione, in
questo caso un server Microsoft in hosting con supporto database Microsoft
Access e linguaggio ASP con supporto del protocollo http.
Per quanto riguarda l’utilizzo di un database Microsoft Access, la scelta è stata
avallata e non è stata richiesta una eventuale modifica con un DBMS (DataBase
Management System) come MySQL o Oracle, in quanto il numero di dati da
immettere e le query da effettuare in tale archivio risultano essere in numero
esiguo, e quindi è adatto a tale scopo anche ad un database Microsoft Access
senza precludere prestazioni sulla consultazione del portale.
Visto che il portale sarà eseguito su di un server Microsoft e programmato in
linguaggio ASP si è dovuto installare sul computer preposto allo sviluppo del
progetto l’IIS (Internet Information Service) per poter collaudare in remoto le
pagine sviluppate.
Per quanto riguarda il fatto di utilizzare un protocollo insicuro come l’http, sono
state fatte delle proposte di implementazione su protocollo https, ma visto il
tempo ridotto del tirocinio, non è stato realizzato.
A questo punto si può passare ad esaminare le specifiche richieste che possono
essere riassunte in due punti:
• accesso riservato con controllo condizionato degli accessi;
• criptazione dei documenti depositati.
Per esaminare queste specifiche si è proceduto con una prima fase di
modellazione dei pericoli.
3.2 Modellazione dei pericoli
La modellazione dei pericoli consente di individuarli in modo sistematico e di
classificare quelli con la maggiore probabilità di incidenza sull’applicazione da
sviluppare.
Si può dire, senza suscitare grandi obiezioni, che non esiste un sistema sicuro al
100% quando un'applicazione web è esposta ad un ambiente ostile come Internet,
quindi l'unica soluzione possibile per sviluppare un’applicazione web robusta è
riconoscere la presenza di pericoli e ridurre o gestire i rischi associati.
Anche se la modellazione dei pericoli risulta essere uno studio abbastanza
elaborato e dispendioso in termini di tempo, e quindi di denaro, risulta essere
- 65 -
efficiente poiché rende la programmazione del software efficace già al primo
sviluppo, basti pensare solo al fatto che risulta estremamente complicato
identificare tutti i potenziali pericoli in una sola volta; in più la redazione della
modellazione dei pericoli risulta un documento essenziale in fase di
aggiornamento o di ampliamento del software.
Il processo di modellazione dei pericoli può essere riassunto in sei fasi:
Figura 22. Processo di modellazione dei pericoli
Descriviamo in modo più preciso ogni fase.
1. Identificare i beni da proteggere: consiste nell’individuazione dei beni,
quindi dei files o dei dati di valore che devono essere protetti dai sistemi ostili.
2. Creare una panoramica dell'architettura dell’applicazione: consiste nello
sviluppo di diagrammi e tabelle semplici per documentare l'architettura
dell'applicazione, inclusi sottosistemi, confini delle zone protette e flusso dei
dati.
3. Scomporre l'applicazione: consiste nell’individuazione delle varie
interconnessioni con i sistemi ostili in cui si interfaccia l’applicazione, per
intercettare i vari punti vulnerabili del progetto.
4. Identificare i pericoli: consiste nell’individuazione dei pericoli che
potrebbero interessare l'applicazione.
5. Documentare i pericoli: consiste nella redazione di un modello che descriva i
vari pericoli a cui è vulnerabile l’applicazione.
6. Classificare i pericoli: consiste nella classificazione dei pericoli in modo da
stabilire le priorità e poter affrontare prima quelli più seri, ovvero quelli che
presentano i rischi maggiori. Il processo di classificazione valuta la probabilità
del pericolo a fronte dei danni che potrebbe provocare in caso di attacco. È
possibile che per alcuni pericoli sia preferibile non eseguire azioni correttive,
se si paragona il rischio con i costi necessari per ridurlo.
Iniziamo a redarre il modello dei pericoli.
I beni da proteggere sono essenzialmente due:
• credenziali di autenticazione immesse dai clienti e dai collaboratori;
• file sensibili depositati dai clienti e dai collaboratori.
- 66 -
L’architettura dell’applicazione può essere schematizzata come in figura:
Figura 23. Diagramma dell’architettura dell’applicazione
Analizzando l’applicazione si vede che essa risulta interconessa con sistemi ostili
in svariati punti.
Possiamo suddividere i possibili pericoli per l’applicazione suddividendoli in:
• pericoli a livello host;
• pericoli a livello applicazione.
I pericoli a livello host sono quelli che scaturiscono dalla configurazione del
server Microsoft.
Le vulnerabilità principali da considerare sono:
• mancato aggiornamento con patch di sicurezza recenti, produce un alto
rischio di esposizione a virus, cavalli di Troia, worms e attacchi IIS;
• utilizzo di porte, protocolli e servizi non necessari, accrescono la
superficie di attacco e consentono ad utenti malintenzionati di raccogliere
informazioni sull'ambiente e di sfruttarle a proprio vantaggio;
• possibilità di accesso anonimo non autenticato;
• utilizzo di password e criteri account inadeguati, consentono attacchi di
violazione delle password, spoofing dell'identità.
Questa tipologia di pericoli non verrà esaminata in quanto essendo lo spazio
fornito alla Phi.d'αlpha s.r.l. in hosting viene già gestito da tecnici specializzati e
competenti.
I pericoli a livello applicazione sono:
• utilizzo di una convalida dell'input inadeguata, che apre la strada ad
attacchi di script tra siti, SQL injection e di overflow del buffer;
• passaggio di credenziali o cookie di autenticazione su collegamenti di rete
non crittografati, che consente l'acquisizione di credenziali o il
dirottamento di sessione;
• utilizzo di criteri password e di account inadeguati, che consentono
l'accesso non autorizzato;
- 67 -
•
incapacità di proteggere gli aspetti di gestione della configurazione
dell'applicazione, incluse le interfacce di amministrazione;
• archiviazione di segreti di configurazione, come stringhe di connessione e
credenziali degli account di servizio, in formato non crittografato;
• utilizzo di account di processo e di servizio con privilegi eccessivi;
• utilizzo di tecniche di codifica dell'accesso ai dati non sicure, che
aumentano il pericolo associato agli attacchi di iniezione di comandi;
• utilizzo di un sistema di crittografia debole o personalizzato e impossibilità
di proteggere adeguatamente le chiavi di crittografia;
• protezione basata sull'integrità dei parametri passati dal browser, ad
esempio, i campi di modulo, le stringhe di query, i dati dei cookie, le
sessioni e le intestazioni http;
• utilizzo di una gestione delle eccezioni non sicura, che può aprire la strada
ad attacchi di tipo Denial of Service e alla divulgazione di dettagli di
livello sistema di grande utilità per i pirati informatici;
• controllo e registrazione inadeguati, che possono comportare pericoli di
ripudio.
A questo punto si è passato alla classificazione del rischio di ogni pericolo.
Il rischio può essere valutato come: rischio = probabilità ⋅ potenziale danno .
Procedendo con questa metodologia si è verificato che i rischi a più alto valore
sono:
• uso insicuro della crittografia;
• controlli di accesso insufficienti;
• iniezioni di comandi;
• gestione insicura delle sessioni;
• gestione inadeguata degli errori.
La fase di modellazione dei pericoli risulta conclusa, a questo punto si passa alla
fase di valutazione delle possibili contromisure per limitare al massimo le
vulnerabilità.
3.3 Analisi delle contromisure
In questo paragrafo verranno descritte le possibili contromisure effettuabili per
limitare l’effetto delle vulnerabilità a rischio più alto riscontrate nella fase di
modellazione dei pericoli.
- 68 -
3.3.1 Uso insicuro della crittografia
L’utilizzo della crittografia verrà applicato ai file sensibili che i clienti ed i
collaboratori trasmetteranno all’area riservata del portale web della Phi.d'αlpha
s.r.l..
Sono possibili due strategie di inserimento della fase di de-cifratura, può essere
implementata lato server o lato client.
Per implementazione lato server si intende che la de-cifratura viene eseguita da
una funzione ASP durante l’up-download del file come mostrato in figura:
Figura 24. Diagramma dell’architettura dell’applicazione con cifratura lato server
Per implementazione lato client si intende che la cifratura viene eseguita dagli
utilizzatori nel proprio computer per mezzo di un software, dopodichè verrà
eseguito l’upload del file già cifrato, mentre nella fase di download i file vengono
prelevati senza procedure ASP direttamente dall’area riservata e decifrati nel
proprio computer come mostrato in figura:
Figura 25. Diagramma dell’architettura dell’applicazione con cifratura lato client
L’implementazione scelta è stata quella lato client in quanto, anche se quella lato
server risulta essere più facile da eseguire per l’utilizzatore, in quanto si trova ad
- 69 -
inserire solo la chiave ed il resto viene eseguito tutto dall’applicazione web,
questo tipo di implementazione risulta inadeguata per due motivi, come prima
cosa produce un’alta occupazione delle risorse del server con conseguente
rallentamento, infatti essendo la fase di upload implementata in puro codice ASP
e non con applicazioni installate sul server, inserire la fase di de-cifratura in
questo punto provoca un grande tempo di trasmissione del file, come seconda
cosa la trasmissione vera e propria viene eseguita in chiaro prima di essere cifrata
dalla funzione ASP, quindi risulta vulnerabile ad attacchi di sniffing.
In conclusione è stato sviluppato un software in VB.NET per gestire la decifratura dei file, non si è utilizzato software come PGP in quanto risultano essere
troppo elaborati e di difficile comprensione per gli utilizzatori del portale.
A questo punto sorge il problema di scelta fra un algoritmo asimmetrico o uno
simmetrico.
Visto che la Phi.d'αlpha s.r.l. ha esplicitamente richiesto che i file trasmessi
potessero essere attribuiti al solo mittente e visto che l’utilizzo di procedure di
autenticazione tramite smart card è stato scartato, visti i tempi ridotti del tirocinio,
si è pensato di impiegare un algoritmo a chiave privata, nella fattispecie l’AES.
Poiché gli algoritmi a chiave privata producono la gestione di un elevato numero
di chiavi, si è pensato alla possibilità di sviluppo di un software steganografico
che nascondesse dentro una immagine bitmap la chiave segreta, è stato quindi
prodotto in VB.NET tale software.
Si è pensato alla steganografia, poiché così la trasmissione delle chiavi può
avvenire in modo sicuro anche tramite protocollo http ed è possibile per l’utente
l’abbinamento del file trasmesso con la relativa immagine con chiave nascosta.
3.3.2 Controlli di accesso insufficienti
Il portale deve gestire una fase di autenticazione degli utenti e proprio in questa
fase che si insediano il maggior numero di vulnerabilità.
La metodologia di autenticazione più utilizzata in ambito web si basa sull'invio
delle proprie credenziali username e password da browser al server in chiaro,
dopodichè, questo le confronterà con il database contenente le credenziali.
Se non si utilizza un tunneling SSL, ciò può divenire un problema in quanto
tramite un attacco di sniffing è possibile rintracciare le credenziali e
conseguentemente riuscire ad ottenere l'accesso al programma web, utilizzando,
appunto, le credenziali altrui così carpite effettuando un reply attack.
Visto che il progetto sarà implementato su protocollo http si è pensato di cifrare la
password con un algoritmo di hashing nella fattispecie MD5.
Come per la fase di crittografia, l’implementazione della funzione di hash può
essere eseguita lato server e lato client.
Per implementazione lato server, si intende che la funzione di hash viene eseguita
da uno script ASP durante la fase di autenticazione come mostrato in figura:
- 70 -
Figura 26. Diagramma dell’architettura dell’applicazione con hash lato server
Per implementazione lato client si intende che la funzione di hash viene eseguita
in fase di invio da uno script lato client, ad esempio utilizzando Java Script, come
mostrato in figura:
Figura 27. Diagramma dell’architettura dell’applicazione con hash lato client
L’implementazione scelta è stata quella lato server in quanto, la gestione della
funzione di hash lato client poteva produrre errori dovuti al blocco da parte del
browser dello script Java Script ed il rischio di sniffing risultava essere molto
limitato poiché, essendo il numero di utenti esiguo ed il loro accesso casuale,
risultava molto difficile una possibile intercettazione di tali credenziali.
Questo tipo di procedura di autenticazione risulta comunque vulnerabile ad
attacchi di brute forcing, quindi si è predisposto l’inserimento di una password
non intelligibile, per evitare attacchi a dizionario, e di minimo 8 caratteri
alfanumerici.
Un'altra vulnerabilità, di basso rischio, è dovuta alla funzione di hash, infatti sono
possibili delle collisioni sulle password, ma per questo non è possibile fare nulla,
se non utilizzare funzioni di hash robuste.
- 71 -
3.3.3 Iniezioni di comandi
Un altro punto focale da analizzare, sempre dovuto all’immissione delle
credenziali di autenticazione, risulta essere quello di possibili attacchi dovuti ad
iniezioni di comandi.
Essendo il dialogo fra database e server gestito da codice SQL ci si troverà di
fronte alla gestione di possibili attacchi di SQL injection.
Per ovviare a questa vulnerabilità si è pensato di inserire una funzione di
validazione dei dati che sostituisca i caratteri “sospetti” con caratteri non nocivi in
modo da sventare l’attacco.
3.3.4 Gestione insicura delle sessioni
Per quanto riguarda la gestione delle sessioni create per tenere traccia degli utenti
autenticati nell’area riservata la soluzione ottimale sarebbe quella di utilizzare il
protocollo https, ma visto che non è possibile, si sono usati degli accorgimenti che
ne riducono le vulnerabilità, come ad esempio il fatto che i dati di sessione
vengono inviati esclusivamente tramite POST e mai con il metodo GET poiché
quest’ultimo risulta visibile nell’url.
Per evitare che le pagine dell’area riservata fossero richiamate ed accessibili in
modo automatico attraverso l’inserimento dell’url o tramite ricerca su motore di
ricerca si è implementata una funzione di verifica tramite le variabile di sessioni
che se fornisce esito negativo, quindi l’utente non è loggato, lo redirige sulla
pagina di login.
Per quanto riguarda la fase di logout si è prestata molta attenzione al fatto di
possibilità di raggiungere le pagine dell’area riservata per mezzo del bottone
indietro del browser, per ovviare a questa vulnerabilità si è sviluppata una
funzione che valuta l’expires della pagina attraverso una procedura condizionale.
3.3.5 Gestione inadeguata degli errori
Le ultime vulnerabilità prese in esame sono state quelle dovute alla gestione
superficiale degli errori.
La gestione corretta degli error fa si che un errore dell’applicazione web, non sia
fonte di informazioni sulla struttura interna del software ad eventuali attacchi.
Basti notare che anche il semplice File Not Found piuttosto di un Access Denied
può essere un’informazione utile per un utente malintenzionato.
Un altro esempio sono gli stack trace che generati dalla Virtual Machine
forniscono spezzoni di codice a chi richiede la pagina al cui interno risiede un
errore di programmazione.
Per eliminare questa tipologia di vulnerabilità è stata effettuata una revisione
completa del codice sorgente ed è stata effettuata una gestione accurata delle
eccezioni in modo tale che restituiscano messaggi chiari per l’utente e non
compromettenti per l’applicazione web.
- 72 -
3.4 Implementazione del software lato client
Per lo sviluppo del software lato client è stato utilizzato come linguaggio di
programmazione il Visual Basic .NET, e come piattaforma IDE il Microsoft
Visual Basic 2005 Express Edition.
Si è scelto di utilizzare questa versione del compilatore poiché risulta essere
totalmente gratuita e scaricabile dal sito Microsoft.
Anche se presenta alcune limitazioni, come ad esempio la modalità di debug delle
applicazioni solo in locale e la bassa estendibilità all’aggiunta di strumenti esterni
al menù e all’uso di controlli di terze parti, risulta essere più che sufficiente per lo
sviluppo del software relativo alla gestione delle policy di sicurezza richieste.
Altro punto a favore, è che a differenza delle versioni Standard e Professional,
risulta essere molto compatto, circa 40 MB, e la Microsoft non ha imposto nessun
vincolo sulla creazione di software commerciale.
I software che verranno sviluppati sono due:
• software per la gestione della crittografia;
• software per la gestione della steganografia.
3.4.1 Software per la gestione della crittografia
Per lo sviluppo del software di crittografia si è utilizzata la classe appartenente al
namespace System.Security.Cryptography in cui il Framework mette a
disposizione del programmatore un insieme di classi dedicate a quasi ogni tipo di
algoritmo di cifratura, sia per funzioni di hashing sia per algoritmi simmetrici sia
asimmetrici.
Come detto in precedenza si è scelto di utilizzare l’algoritmo di cifratura AES
poiché fornisce un elevata robustezza.
Il software, tralasciando la gestione degli errori e delle eccezioni, può essere
schematizzato attraverso due schemi a blocchi, uno per la fase di cifratura l’altro
per la fase di decifratura:
Figura 28. Schema a blocchi delle funzioni di de-cifratura
- 73 -
La lettura e scrittura del file avvengono come strem binari poichè si è voluto
creare un’applicazione che gestisse qualsiasi tipo di file, se si fosse voluto ad
esempio gestire solo file di testo si sarebbe potuto utilizzare una codifica come ad
esempio la UTF-8.
Le funzioni più importanti di questo programma sono quella di cifratura e quella
di decifratura.
Su entrambe le funzione devono essere inizializzati i valori di alcune variabili
indispensabili per il funzionamento della classe che implementa l’AES.
Come prima cosa è necessario definire:
• BlockSize: dimensione del blocco;
• IV: vettore di inizializzazione.
La BlockSize è l'unità minima da crittografare e gli viene assegnato il valore di 16
byte.
Il vettore di inizializzazione ha un significato particolare che deve essere spiegato.
L’algoritmo AES per crittografare usa la chiave segreta ed il risultato della
codifica dei byte precedenti, quindi è chiaro che prima dei primi 8 byte non ci sarà
nulla, quindi è necessario fornire una base di partenza all’algoritmo e questa è
proprio il vettore di inizializzazione. Anche il vettore di inizializzazione ha la
dimensione di 16 byte.
A questo punto è necessario fornire la chiave segreta con la sua relativa
dimensione.
La chiave segreta viene data dall’utilizzatore del software attraverso la
compilazione di una TextBox, quindi assumerà il tipo stringa.
Essendo un valore immesso, deve prima essere validato, per fare ciò è stata creata
una funzione apposita che attraverso un’espressione regolare controlla che siano
immessi solo caratteri alfanumerici (alfabetici minuscolo, alfabetici maiuscolo,
numeri) e che essi siano in numero sufficiente rispetto alla dimensione della
chiave scelta, infatti è stata implementa la possibilità di far scegliere
all’utilizzatore la lunghezza della chiave fra 128 bit (16 caratteri) e 256 bit (32
caratteri).
Il fatto di aver limitato il numero delle possibili chiavi risulta un indebolimento
alla robustezza dell’algoritmo, infatti si è passati dalla possibilità di inserire 256
caratteri a quella di inserirne 62, nella fattispecie per le chiave a 128 bit si passa
da un valore di 2128 ≅ 3, 4 ⋅1038 ad un valore di 6216 ≅ 4,8 ⋅1028 mentre per le
chiavi a 256 bit si passa da un valore di 2256 ≅ 1, 2 ⋅1077 ad un valore di
6232 ≅ 2, 3 ⋅1057 .
Questa scelta è stata effettuata poiché risulta più semplice per l’utilizzatore
inserire una stringa di caratteri alfanumerici piuttosto che una sequenza di codice
binario o esadecimale qualsivoglia.
Una volta impostate queste proprietà della classe è possibile effettuare la decifratura utilizzando i metodi :
• CreateEncryptor().TransformFinalBlock( , ,);
• CreateDecryptor().TransformFinalBlock( , ,);
- 74 -
dove la funzione TransformFinalBlock accetta come parametri:
• inputBuffer: è l’input sul quale eseguire l'operazione;
• inputOffset: è l’offset nella matrice di byte dal quale iniziare a utilizzare i
dati;
• inputCount: è il numero di byte nella matrice di byte da utilizzare come
dati;
e restituisce l’array di byte contenente il file de-cifrato.
Come richiesto dalla Phi.d'αlpha s.r.l. si è cercato di sviluppare il software in
modo tale che fosse il più friendly possibile.
Il software si presenta come una sola finestra in cui è possibile effettuare tutte le
operazioni.
Figura 29. Finestra del software per la gestione della crittografia
Per rendere il più semplice possibile l’utilizzo del software è stata gestita
l’immissione del file da de-cifrare per mezzo di un’operazione di Drag&Drop,
infatti per ottenere il path del file basta trascinarlo nella TextBox denominata
“Path”.
A questo punto l’utilizzatore sceglierà la lunghezza della chiave scegliendo fra 16
e 32 caratteri ed inserirà la chiave nella TextBox denominata “Chiave” infine
sceglierà se effettuare la cifratura o la decifratura premendo i bottoni in basso a
destra ed in basso a sinistra. Il file cifrato avrà come estensione .cry mentre il file
decifrato ritornerà ad avere l’estensione originale.
I files prodotti dal software verranno posizionati nella stessa directory del file che
lo ha generato.
Per evitare difficoltà dovute ad errori dell’utilizzatore sono state gestite tutte le
possibili eccezioni con il relativo messaggio di spiegazione sull’errore commesso,
sono state quindi gestiti errori dovuti a path non validi, a chiavi segrete non
valide, etc.
3.4.2 Software per la gestione della steganografia
Per ottenere una trasmissione della chiave maggiormente sicura si è pensato di
inviarla in un file steganografato.
- 75 -
Per rendere il file meno vulnerabile ad un possibile attacco, invece di utilizzare un
software in commercio ne è stato sviluppato uno apposito, con un algoritmo
ottimizzato.
La tecnica steganografica applicata è di tipo sostitutivo e vengono utilizzati come
file contenitori, immagini Bitmap.
Ipotizzando una distribuzione equiprobabile fra gli zero e gli uno del file e quelli
del messaggio, andando a modificare i bits meno significativi del file contenitore
si produrrebbe una variazione del 50% dei byte che devono contenere il
messaggio segreto. Per diminuire questa probabilità si è pensato, che essendo il
messaggio relativamente corto in quanto la chiave può essere di 16 o 32 caratteri,
è possibile utilizzare 64 byte per ogni carattere poiché i caratteri alfanumerici
sono 62, richiedendo file contenitori di minimo 3 kB per chiavi da 16 caratteri e 6
kB per quelle da 32 caratteri. I 64 byte possono essere immaginati, pensando alla
struttura di un file Bitmap, come una matrice 8 ⋅ 8 come in figura:
Figura 30. Matrice contenente la codifica dei caratteri della chiave
dove solo il riquadro nero identifica il carattere.
Essendo i riquadri bianchi molto più numerosi di quelli neri si è pensato di
associare a loro una sequenza di bits meno probabile. In particolare i riquadri neri
sono stati rappresentati con una sequenza di soli zero mentre quelli bianchi con
qualsiasi altra sequenza purché sia presente almeno un uno.
1
La probabilità composta di avere n bits zero consecutivi è n , quindi la
2
1
probabilità di avere tutte le altre parole sarà 1 − n .
2
Immaginando di utilizzare questo procedimento su di un file contenitore con
distribuzione equiprobabile di zero ed uno si vedrà che aumentando il numero di
bits costituenti i riquadri il numero di bits da sostituire tenderà a diminuire.
- 76 -
Ad esempio, per un blocco di 1024 byte si avrà che:
N. di bits costituenti il riquadro
1
2
3
4
5
6
N. di bits da modificare nel file contenitore
512
264
144
88
64
56
Tabella 10. Esempio di bits da modificare nel file contenitore in base ai bit costituenti il riquadro
Uno dei casi peggiori che si può avere, si presenta quando si usa come file
contenitore un’immagine completamente bianca.
Si è per esempio utilizzata un’immagine 11 ⋅ 32 di 1056 byte ed è stato modificato
sempre il primo riquadro dei 64.
In questo caso anche un semplice attacco visuale fa notare l’esistenza di una
anomalia nell’immagine ed andando a scomporla nei canali RGB è addirittura
possibile identificare una certa sequenzialità su bits:
Figura 31. Analisi visiva fra un immagine e la sua relativa steganografata
Utilizzando un attacco statistico, l’anomalia risulta evidente, in quanto
esaminando l’immagine convertita in cifre esadecimali, si nota subito
l’improbabilità di un rumore strutturato come quello in figura.
- 77 -
Figura 32. Analisi statistica fra un immagine e la sua relativa steganografata
Utilizzando invece immagini con variazioni di colore molto frequenti il risultato è
molto apprezzabile, in quanto ad un attacco visivo risulta essere indistinguibile,
mentre ad un attacco statistico, utilizzando sempre immagini diverse si rende
difficoltosa l’analisi.
Per giustificare quanto detto verrà fornito un esempio con immagine cover con
alta varianza nella frequenza di colore.
Figura 33a. Immagine originale
Figura 33b. Immagine steganografata
L’immagine ha una dimensione di 1600 ⋅1200 di 5760054 byte.
Per la steganografia dell’immagine sono stati utilizzati i seguenti parametri:
• chiave segreta: 534b44a19bf18d20b71ecc4eb77c572f
• numero i bit per byte: 2
• shift del cifrario a scorrimento: 23
ottenendo una variazione di 532 bit su 523 byte, cioè una media di 1,02 bit per
byte.
- 78 -
Esaminando l’immagine convertita in cifre esadecimali si vede come l’immagine
steganografata abbia una piccola variazione sulle componenti RGB del colore
quasi sempre nell’ordine dell’unità.
Figura 34. Frammento di codice esadecimale dell’immagine e della sua relativa steganografata
Per rendere più sicuro l’algoritmo, i codici che costituiscono la chiave possono
essere cifrati per mezzo di un cifrario a scorrimento.
Il software, tralasciando la gestione degli errori e delle eccezioni, può essere
schematizzato attraverso due schemi a blocchi, uno per la fase di inserimento
della chiave e l’altro per la fase di estrapolazione:
Figura 35. Schema a blocchi delle funzioni di iniezione ed estrapolazione della chiave
Il software si presenta come una sola finestra in cui è possibile effettuare tutte le
operazioni.
Figura 36. Finestra del software per la gestione della steganografia
- 79 -
Come per il software per la crittografia, l’immissione del file è stata gestita per
mezzo di un’operazione di Drag&Drop.
Anche in questo caso l’utilizzatore può scegliere la lunghezza della chiave
scegliendo fra 16 e 32 caratteri ed inserirla nella TextBox denominata “Chiave”.
L’utilizzatore può anche scegliere il numero di bit da modificare per ogni byte
dell’immagine contenitore, in quanto come descritto aumentando tale numero, in
linea teorica si diminuisce la variazione sull’immagine steganografata. Tale
numero è stato settato di default a 3 in quanto si è verificato che è un valore
accettabile per qualsiasi tipo di combinazione immagine contenitore - chiave.
Per effettuare l’iniezione della chiave o il prelevamento della chiave, l’utilizzatore
sceglierà premendo i bottoni “Nascondi la chiave” e “Preleva la chiave”.
Il file Bitmap steganografato verrà posizionato nella stessa directory del file che lo
ha generato.
Per evitare difficoltà dovute ad errori dell’utilizzatore sono state gestite tutte le
possibili eccezioni con il relativo messaggio di spiegazione sull’errore commesso,
sono state quindi gestiti errori dovuti a path non validi, è stato quindi gestito
l’input forzato di soli file Bitmap di dimensioni minime opportune, a chiavi
segrete non valide, etc.
Nella sezione di iniezione è stato implementato anche un campo denominato
“Utilizzo bit”, dove viene data una stima dell’efficienza dell’algoritmo in base alla
immagine cover ed alla chiave utilizzata.
Un utilizzatore attento può pensare di fare alcuni tentativi modificando la cifratura
a scorrimento, il numero di bit da modificare per ogni byte dell’immagine
contenitore, ed eventualmente l’immagine cover stessa per ottenere il risultato
migliore possibile.
Per migliorare l’algoritmo si potrebbe pensare di codificare i riquadri neri
seguendo una sequenza pseudo-random ed utilizzando un algoritmo di cifratura
più efficiente.
3.5 Implementazione dell’applicazione web
Il software lato server è stato sviluppato utilizzando come linguaggi di
programmazione: Visual Basic Script, Java Script, ASP ed il linguaggio di markup HTML.
Visto che il portale sarà eseguito su di un server Microsoft si è installato sul
computer preposto allo sviluppo del progetto l’IIS (Internet Information Service)
per poter collaudare in remoto le pagine sviluppate.
Essenzialmente l’applicazione web è costituita da due parti.
La prima è costituita da un fase di autenticazione per filtrare gli utenti preposti
all’ingresso nell’area riservata della Phi.d'αlpha s.r.l. ed una connessa fase di
logout in cui gli utenti possono uscire dall’area riservata in modo sicuro.
- 80 -
La seconda parte è costituita da una sezione in cui gli utenti possono effettuare
l’upload dei file che desiderano condividere con annessa una sezione in cui è
possibile eseguire il download di tutti i file inseriti.
3.5.1 Login e logout degli utenti
Per sviluppare la fase di login, cioè quella in cui gli utenti vengono autenticati, si
è proceduto inizialmente alla creazione di un database Microsoft Access dove
potessero essere contenute tutte le credenziali degli utenti.
Come prima cosa si è creato un nuovo database a cui è stato dato il nome
“user.mdb” ed è stata creata una nuova tabella dal nome “Utenti” con i seguenti
campi:
• Id;
• Username;
• Password.
La tabella in visualizzazione struttura risulta costituita come in figura:
Figura 37. Visualizzazione struttura della tabella “Utenti”
A questo punto è stata costruita una pagina in cui fosse possibile per l’utente
inserire le proprie credenziali.
Si è così implementata una form rientrante in cui tramite il metodo POST
vengono validate le credenziali.
La form è costituita da un campo UserName e da un campo Password.
Figura 38. Form per il login
L’UserName viene inviato in chiaro mentre la Password viene cifrata per mezzo
di una funzione di hash, nella fattispecie utilizzando l’algoritmo MD5.
Non essendo disponibile una tale funzione nel linguaggio ASP, si è proceduto
all’inserimento della stessa utilizzandone una implementata da Phil Fresle e
prelevata dal sito www.frez.co.uk. Tale funzione è stata sviluppata, come
illustrato dall’autore, utilizzando le specifiche fornite dalla RSA Laboratories e
- 81 -
descritte nel documento RFC1321 ed è stata programmata in linguaggio ASP e
Visual Basic Script.
La funzione chiamata “MD5” accetta come input una stringa e restituisce una
stringa.
Le credenziali, immesse nella form, prima di essere confrontate con quelle
contenute nel database vengono validate per scongiurare possibili attacchi di
iniezione di comandi.
Avendo usato come linguaggio, per generare le query, l’SQL si è creata una
funzione ad-hoc atta a filtrare possibili attacchi di SQL injection.
La funzione chiamata “FiltraSQL” accetta come input una stringa e restituisce una
stringa.
Tale funzione non fa altro che verificare se la stringa immessa nella form contiene
caratteri preposti ad attacchi di SQL injection e se ne trova essi vengono sostituiti
con caratteri non nocivi.
Risulta essenziale scongiurare questo tipo di attacco perché è impiegabile anche
da hacker poco espserti in quanto basta ad esempio inserire come UserName il
nome dell’amministratore del servizio (ad esempio “root”) e come password il
codice: “ ' or '0' = '0 ” per ottenere l’acceso all’area riservata poiché la query
utilizzata per il confronto delle credenziali avrà il seguente codice:
select * from Utenti
where
UserName = 'root' and
Password = ' ' or '0 ' = '0 '
Siccome il carattere ' viene interpretato dal linguaggio ASP come il carattere di
fine stringa la where sarà sempre verificata.
Una volta effettuati i controlli sui dati immessi, è possibile effettuare la
validazione andando a compiere il confronto fra le credenziali immesse nella form
e quelle contenute nel database, se il confronto da un esito positivo allora vengono
create due sessioni chiamate “Log” e “Username” dove alla prima viene assegnato
il valore True e alla seconda viene assegnato l’UserName dell’utente; se invece il
confronto da un esito negativo viene assegnata alla sessione “Log” il valore False.
Se il confronto è positivo l’utente viene indirizzato all’area ad accesso riservato,
mentre se il confronto risulta essere negativo l’utente viene reindirizzato di nuovo
alla pagina di login a cui viene aggiunto un messaggio per comunicargli che i dati
immessi non sono validi.
Oltre ai controlli descritti vengono eseguite anche tutte le procedure atte a
garantire eccezioni ed errori, come ad esempio la mancata compilazione di un
campo della form, in modo da rendere il più semplice possibile la verifica da parte
dell’utilizzatore dell’errore da lui commesso.
Per garantire che le pagine web dell’area riservata siano accessibili solo dagli
utenti autorizzati oppure non siano generate in modo automatico, sia
dall’immissione dell’url o da risultati di ricerche ottenute dai motori di ricerca, in
ogni pagina viene controllato se l’utente che tenta di accedere è regolarmente
- 82 -
loggato, viene quindi effettuato un controllo sulle due variabili si sessione “Log” e
“Username”. Se l’utente non risulta autorizzato viene reindirizzato alla pagina di
login.
La fase di logout viene eseguita tramite due procedure:
• Session.Contents.RemoveAll();
• Session.Abandon.
Con la prima procedura vengono cancellate tutte le variabili di sessione, cioè
vengono svuotate e annullate, quindi non esisteranno più nel corso della
navigazione dell’utete, mentre con la seconda procedura si cancellano tutte quante
le variabili di sessione attive nell’istante in cui il comando viene inoltrato.
Una volta eseguito il logout non dovrebbe più essere possibile ritornare all’area
riservata invece, se non viene preso un adeguato accorgimento, tramite l’utilizzo
del bottone “Indietro” del browser è possibile.
Per evitare questa anomalia, si è sviluppata una funzione, che come prima cosa fa
in modo tale che le pagine non rimangano nella cache del browser, e poi tramite
una procedura condizionale valuta se la pagina viene visitata tramite un accesso
dall’area riservata o tramite un accesso successivo alla fase del logout, nel primo
caso consente l’accesso, mentre nel secondo caso redirige l’utilizzatore alla
pagina di login.
Per concludere si vuole spiegare perché si è scelto di utilizzare le sessioni.
Le sessioni provocano, se in numero elevato, un notevole appesantimento di
lavoro sul server rallentandolo di conseguenza, infatti queste variabili lavorano
completamente sul Server-Side.
Per ovviare a questo inconveniente si potrebbe pensare di utilizzare delle variabili
Client-Side, come ad esempio i cookies.
Non si è scelto di utilizzare i cookies, poiché essi potrebbero in alcuni casi essere
stati disabilitati dagli utenti e questo porterebbe ad un non funzionamento
dell’interfaccia di autenticazione, mentre le sessioni si appoggiano a dei cookies
speciali generati dal server e sono quindi sempre attive.
Come ultima ragione che ha portato alla scelta delle sessioni c’è quella relativa al
fatto che esse sono in numero bassissimo e quindi non provocano un lavoro
stressante per il server.
3.5.2 Upload e download dei files
La Phi.d'αlpha s.r.l., nelle specifiche fornite, ha richiesto un’area in cui fosse
possibile inserire e prelevare del materiale informatizzato tramite operazioni di
criptazione.
Le procedure di criptazione sono state ottenute, come descritto precedentemente,
attraverso un software lato client, quindi rimane da progettare un’applicazione
web in grado di gestire l’upload ed il download dei files.
Nel linguaggio ASP non esiste una funzione predisposta ad effettuare l’upload dei
files, quindi normalmente per implementare tale funzionalità ci si deve servire di
componenti esterni che vengono eseguiti sul server. Purtroppo però questi
- 83 -
componenti, oltre che ad avere un costo elevato, necessitano di un'installazione da
parte della società di hosting, cosa che non sempre viene effettuata per motivi di
sicurezza.
Un'altra ragione per cui non si è scelto di utilizzare queste tecnologie è che esse
non sono modificabili, poiché raramente sono open source, quindi spesso non
sono ottimizzate per le specifiche di chi le vuole utilizzare.
Visto che il protocollo http supporta l'upload ed anche il Web Server di Microsoft
IIS, si è pensato di sviluppare un’applicazione web in grado di implementare
l’upload dei files attraverso puro codice ASP.
Come prima cosa deve essere creata una pagina in grado di recuperare i dati e
spedirli. Per fare questo ci si è serviti di una form.
Figura 39. Form per l’upload
Analizzando la documentazione ufficiale della Microsoft si nota che l'unico
metodo per accedere al contenuto del file uploadato è richiamare il metodo
RequestBinary:
bytecount = Request.TotalBytes bytArray = Request.BinaryRead(bytecount)
dove bytecount è una variabile long che restituisce la lunghezza della richiesta,
mentre bytArray è un array che contiene i byte della richiesta.
In pratica il metodo BinaryRead legge un certo numero di byte direttamente dal
corpo della richiesta http inviato dal client come parte del metodo POST.
Dovendo leggere l'intero file bisognerà conteggiare quanti byte sono stati spediti e
memorizzarli in una variabile che sarà quindi il file da uploadare.
Putroppo il linguaggio Visual Basic Script non dispone di funzioni in grado di
convertire, in modo automatico, tutto un Array da byte a char (string), quindi si
dovrebbe costruire un ciclo su ogni elemento dell'array per creare una stringa di
caratteri in questo modo:
For lngLoop = 0 To UBound(bytArray) - 1
strByteToString = strByteToString + Chr(bytArray(lngLoop))
Next
Questo ciclo rallenta molto il processo di uploading, ed in alcuni casi si possono
verificare dei timeout che ne bloccano addirittura l’esecuzione.
Per evitare questo si può pensare di utilizzare la libreria ADODB che attraverso il
metodo "AppendChunk" dell'oggetto Field, permette di processare i dati come un
field di tipo long binary, in modo da restituire una stringa.
- 84 -
Utilizzando la libreria ADODB il ciclo precedente viene sostituito dal seguente
codice:
Set rstTemp = Server.CreateObject("ADODB.Recordset")
rstTemp.Fields.Append "bytArray", adLongVarChar, lenb(bytArray)
rstTemp.Open
rstTemp.AddNew
rstTemp.Fields("bytArray").AppendChunk bytArray
rstTemp.Update
strByteToString = rstTemp("bytArray")
che fa si che nella variabile stringa strByteToString sia contenuta la richiesta
serializzata.
A questo punto la richiesta è manipolabile con i metodi e le funzioni generalmente
utilizzate, con Visual Basic Script, quali Mid e InStr.
Un esempio di richiesta serializzata è il seguente:
-----------------------------7d1193202027a
Content-Disposition: form-data;
name="uploadFile";
filename="C:\Esempio.cry"
Content-Type: text/plain
·"Eê [1] &möüy|Ã"óoÊYE?lÄïV?$c [¿~åÿ1êòbÃ
ƒÃ>^"*-|D¡ïfÃŒ|é÷"Eê [1] &möüy|Ã"óoÊYE?lÄÃd
Figura 40. Frammento di richiesta serializzata
in cui:
• 7d1193202027a: è il codice identificativo del file spedito;
• Content-Disposition: indica la provenienza del file, in questo caso una
form;
• name: contiene il nome del campo form, in questo caso “uploadFile”;
• filename: contiene il percorso ed il nome del file spedito, in questo caso
“C:\Esempio.cry”;
• Content-Type: contiene la tipologia del file spedito, in questo caso
text/plain;
ed il resto è il contenuto del file che viene chiuso attraverso un tag apposito.
Il codice identificativo si ripete per ogni richiesta serializzata, può quindi essere
utilizzato per effettuare un ciclo.
In ogni ciclo si recuperano: nome dell'input, tramite la stringa: "name" ed il suo
relativo contenuto. Quando il campo è di tipo file, nella richiesta serializzata si
troverà anche l'attributo "filename" con il percorso da cui è stato prelevato il file.
A questo punto bisogna recuperare il contenuto del file dalla richiesta stessa.
Per fare ciò si è utilizzata una classe scritta da Simone Medas con licenza BSDlike prelevata dal sito www.aspitalia.com.
- 85 -
Tale classe chiamata “clsInput” ha come membri:
• name: variabile stringa che identifica il nome assegnato all'input;
• isFile: variabile booleana, vale "true" se è un file;
• size: variabile numerica, contiene la lunghezza del file contenuto;
• fileName: variabile stringa che contiene il nome del file uploadato;
• filePath: variabile stringa che contiene il percorso completo dal quale è
stato uploadato il file;
e due metodi:
• saveFile(): salva il file dove è in esecuzione lo script
• saveFileAs(destinationPath, newFileName): permette di specificare sia
il percorso di destinazione (nel server) che un eventuale ed opzionale
nome da assegnare al file.
Il parser si occupa di creare una collezione di clsInput utilizzando l'oggetto
"Scripting.Dictionary", dove l'oggetto in questione è "inputs".
Bisogna infine specificare che questa classe, è utilizzabile solo nella versione 5.0
di Visual Basic Script, quindi con IIS5 o IE 5.x o con l'installazione della
VBScript Virtual Mchine 5.0.
Ora si sono gestite tutte le eccezioni, cioè quella dovuta alla mancata scelta di un
file e quella dovuta alla scelta di un file il cui nome è già presente nell’area
riservata.
Per quanto riguarda la prima si è fatto in modo che sia visualizzato un messaggio
che esplichi l’avvenuta eccezione all’utilizzatore, mentre per la seconda, in
accordo con la Phi.d'αlpha s.r.l., si è fatto in modo tale che l’utilizzatore non possa
effettuare sovrascrzione dei files.
Quando l’utente sceglie il file da inviare e preme il bottone invia, viene mandato
al server la richiesta, a questo punto tramite l’utilizzo dell’oggetto
FileSystemObject si fa una scansione di tutti i file contenuti nell’area riservata e
se uno dei nome dei file risulta essere uguale a quello che cerca di mandare
l’utente, viene bloccato l’upload e generato un messaggio di errore nel quale viene
detto che esiste già un file con quel nome e che non è possibile sovrascriverlo, e
che se si vuole comunque mandarlo bisogna cambiargli il nome.
Per quanto riguarda la pagina in cui è possibile effettuare il download dei files
condivisi, essa viene generata in modo automatico attraverso uno script ASP.
Tramite l’oggetto FileSystemObject viene eseguita una scansione dell’area
riservata per catalogare tutti i files in essa contenuti, e viene creata una tabella in
cui vengono elencati:
• nome del file;
• tipo del file;
• dimensione del file.
Nel campo tipo del file è stato effettuato un controllo per vedere se il file ha
estensione .cry in modo da evidenziare che si tratta di un file crittografato
attraverso il software sviluppato.
I files contenuti nell’area riservata potranno a discrezione della Phi.d'αlpha s.r.l.
essere cancellati attraverso un accesso Ftp a tale cartella.
- 86 -
CONCLUSIONI E SVILUPPI FUTURI
Durante il tirocinio effettuato presso la Phi.d'αlpha s.r.l. si è cercato di
implementare un portale web sicuro ed allo stesso tempo estremamente friendly.
Il tema della sicurezza risulta essere al giorno d’oggi estremamente sentito per
tutte quelle aziende che si trovano a lavorare con dati riservati e sensibili, poiché
una loro trattazione in modo non corretta può provocare danni irreparabili sia per i
clienti, sia per l’azienda stessa che si potrebbe trovare a fronteggiare elevate
sanzioni pecuniarie o addirittura procedimenti di natura penale.
Visto ciò risulta estremamente difficile far collimare la semplicità con la
sicurezza.
Le procedure attuate per la realizzazione di questo progetto risultano essere
abbastanza sicure, ma non esenti da possibili attacchi.
Purtroppo sviluppare procedure per garantire policy di sicurezza più elevate
producono una diminuzione della semplicità di utilizzo del software e questo in
alcuni casi, può provocare danni ancora più irreparabili in quanto un utente “non
addetto ai lavori” si troverebbe ad utilizzare strumenti a lui incomprensibili e
quindi potenzialmente dannosi.
Nonostante ciò si può dire che le garanzie di sicurezza implementate risultano
essere sufficienti per la Phi.d'αlpha s.r.l., in quanto essendo un’azienda non molto
grande, si trova a prestare i propri servizi ad un numero ristretto di clienti ed a
collaborare con un altrettanto numero limitato di collaboratori, quindi ci si è potuti
limitare a trattare solo quelle vulnerabilità che sono di importanza notevolmente
rilevante.
Se si vuole, però analizzare dei possibili sviluppi futuri, il lavoro da fare risulta
essere ragguardevole.
Come prima cosa, sarebbe necessario implementare tutta la sezione dell’area
riservata del portale sotto protocollo https, in modo da garantire un livello più
elevato di sicurezza a possibili attacchi di sniffing.
Per quanto riguarda invece l’utilizzo della crittografia e della steganografia,
sarebbe necessario poter effettuare degli incontri, per poter istruire tutti i fruitori
di queste tecnologie spiegando come tali algoritmi se usati male, non garantiscono
policy di sicurezza elevate, basti pensare ad esempio all’uso scorretto delle chiavi
segrete.
Per quanto riguarda invece proprio il software prodotto, per quello realizzato per
implementare l’algoritmo di cifratura AES ci si può ritenere soddisfatti, mentre
per quello che riguarda il software che implementa la steganografia sarebbe
meglio apportare alcune modifiche all’algoritmo che realizza l’iniezione della
chiave nel file, in quanto, esso risulta segreto fintanto che un hacker non viene a
conoscenza dell’algoritmo stesso, e questo non rispetta il postulato di Kerckhoffs.
Per rendere l’algoritmo di steganografia veramente sicuro bisognerebbe utilizzare
una tecnica di memorizzazione dei vari frammenti della chiave pseudo-casuale e
che essa sia preventivamente cifrata.
- 87 -
L’applicazione web risulta essere estremamente friendly e quindi di facile utilizzo
anche a tutti quegli utenti non esperti del settore informatico, in quanto richiede
solo l’immissione delle credenziali di autenticazione, fornite dalla Phi.d'αlpha
s.r.l. e quindi l’utilizzatore non deve compilare tutti quelle form preposte
all’accettazione o al cambiamento delle credenziali, che spesso scoraggiano quella
tipologia di utenti poco esperti.
Un ultima opinione si può esprimere sulla modalità di cancellazione dei files dal
server che la Phi.d'αlpha s.r.l. compie.
Essa non fornisce nessuna garanzia di sicurezza in quanto la cancellazione
“normale” di un file non ne realizza l’effettiva eliminazione dalla memoria, quindi
sarebbe indicato realizzare un software che riuscisse, per esempio attraverso
sovrascrizioni multiple delle locazioni di memoria che contenevano il file, ad
eliminare in modo definitivo il file.
In conclusione si può dire che la realizzazione di questo progetto è stata molto
interessante, poiché oltre a fornire diversi punti di studio su argomenti
estremamente degni di attenzione come la crittografia e la steganografia, ha
fornito una fondamentale esperienza sulla vita aziendale e sulle correlate esigenze
pratiche che risultano molto spesso distanti da quelle di natura teorica.
- 88 -
APPENDICE
In questa sezione verrà inserito il codice sorgente del progetto realizzato
suddividendolo in:
• codice VB.NET del software di crittografia;
• codice VB.NET del software di steganografia;
• codice ASP del software web.
- 89 -
Codice VB.NET del software di crittografia
Option Explicit On
Imports System.Security.Cryptography
Imports System.IO
Imports System.Text
Imports System.Text.RegularExpressions
Public Class frmMain
'dichiaro le variabili pubbliche
Public bytIV() As Byte = {123, 245, 166, 166, 135, 73, 13, 39, 255, 91, 45, 78, 14, 211, 22, 62}
Public strPath As String 'contiene il Path del file
Public abytFile As Byte() 'contiene il file in byte
Public blnFlag As Boolean 'contiene il flag per l'inserimento del nome
Public strEstensioneFile As String 'contiene l'estensione del file
Public intDimensioneChiave As Integer 'contiene la dimensione della chiave
#Region "Drag&Drop"
'restituisce il Path del file trascinato in strPath
Private Sub txtPath_DragDrop(ByVal sender As Object, _
ByVal e As System.Windows.Forms.DragEventArgs) Handles
txtPath.DragDrop
If (e.Data.GetDataPresent(DataFormats.FileDrop)) Then
e.Effect = DragDropEffects.Copy
Else
e.Effect = DragDropEffects.None
End If
End Sub
Private Sub txtPath_DragEnter(ByVal sender As Object, _
ByVal e As System.Windows.Forms.DragEventArgs) Handles
txtPath.DragEnter
Dim sPathName As String()
sPathName = e.Data.GetData(DataFormats.FileDrop)
txtPath.Text = sPathName(0)
strPath = sPathName(0)
txtChiavescelta.Text = ""
End Sub
#End Region
#Region "Funzioni per Lettura e Scrittura"
Private Function LeggiFile(ByVal vstrPathName As String) As Byte()
'leggo il file usando BinaryReader in modo da ottenere un'array di byte
Dim objFileL As New FileStream(vstrPathName, FileMode.OpenOrCreate, FileAccess.Read)
Dim objFileLBR As New BinaryReader(objFileL)
abytFile = objFileLBR.ReadBytes(objFileL.Length)
objFileL.Close()
objFileLBR.Close()
Return abytFile
End Function
- 90 -
Private Sub ScriviFile(ByVal vstrPathName As String, ByVal vabytFileS As Byte())
'sfruttando la classe Path ottengo: directory e nome del file
Dim strDirFile As String = Path.GetDirectoryName(vstrPathName)
Dim strNomeFile As String = Path.GetFileNameWithoutExtension(vstrPathName)
'in base al tipo di operazione: cripto o decripto modifico l'estensione del file
Dim strEstFile As String
If blnFlag = 0 Then
strEstFile = ".cry"
Else
strEstFile = "." & strEstensioneFile
End If
'se il file esiste già aggiungo al nome un trattino
If File.Exists(strDirFile & "\" & strNomeFile & strEstFile) Then
strNomeFile &= "_"
End If
Dim objFileS As New FileStream(strDirFile & "\" & strNomeFile & strEstFile, FileMode.Create, _
FileAccess.Write)
Dim objFileSBW As New BinaryWriter(objFileS)
objFileSBW.Write(vabytFileS)
objFileS.Close()
objFileSBW.Close()
End Sub
#End Region
Public Function Cripta(ByVal vstrIV As Byte(), ByVal vstrChiave As String, _
ByVal vabytFileC As Byte()) As Byte()
'array di byte che contiene il file criptato
Dim abytFileC As Byte()
'inizializzo la classe RijndaelManaged
Dim objAES As RijndaelManaged = New RijndaelManaged
'dimensione della chiave: 128 bit = 16 byte, 256 bit = 32 byte
objAES.KeySize = intDimensioneChiave
'dimensione del blocco
objAES.BlockSize = 128
'carico il Vettore di Inizializzazione
objAES.IV = bytIV
'carico la chiave trasformandola da string a array di byte
objAES.Key = Encoding.Default.GetBytes(vstrChiave)
'cripto l'array di byte che contiene il file
abytFileC = objAES.CreateEncryptor().TransformFinalBlock(abytFile, 0, abytFile.Length)
Return abytFileC
End Function
Public Function Decripta(ByVal vstrChiave As String, ByVal vabytFileD As Byte()) As Byte()
'array di byte che contiene il file decriptato
Dim abytFileD As Byte()
'inizializzo la classe RijndaelManaged
Dim objAES As RijndaelManaged = New RijndaelManaged
'dimensione della chiave: 128 bit = 16 byte, 256 bit = 32 byte
objAES.KeySize = intDimensioneChiave
'dimensione del blocco
objAES.BlockSize = 128
'carico il Vettore di Inizializzazione
objAES.IV = bytIV
'carico la chiave trasformandola da string a array di byte
objAES.Key = Encoding.Default.GetBytes(vstrChiave)
Try
- 91 -
'decripto l'array di byte che contiene il file
abytFileD = objAES.CreateDecryptor().TransformFinalBlock(abytFile, 0, abytFile.Length)
Return abytFileD
'gestisco gli errori
Catch ex As Exception
abytFile = Nothing
Return abytFile
End Try
End Function
Public Function VerificaChiave(ByVal vstrChiave As String) As Boolean
'verifico la correttezza della chiave impostando che sia alfanumerica e di lunghezza giusta
If vstrChiave = "" Then
MsgBox("Non è stata inserita la chiave", MsgBoxStyle.Exclamation)
Return False
ElseIf Regex.IsMatch(vstrChiave, "[^a-zA-Z0-9]") Then
'se è sbagliata avverto l'utente
MsgBox("La chiave non è valida: può contenere solo caratteri alfanumerici",
MsgBoxStyle.Exclamation)
Return False
ElseIf vstrChiave.Length < intDimensioneChiave / 8 Then
'se è sbagliata avverto l'utente
MsgBox("La chiave non è valida:" & _
" deve essere lunga: " & intDimensioneChiave / 8 & " caratteri", MsgBoxStyle.Exclamation)
Return False
Else
Return True
End If
End Function
Public Sub AggiungiEst()
'ridimensiono l'array contenente il file in modo da contenere i 3 caratteri dell'estensione in fondo
Dim intLunghFile As Integer = abytFile.Length
ReDim Preserve abytFile(intLunghFile + 2)
'prendo l'estensione del file e lo rendo di 3 caratteri togliendo il punto
Dim strEstensioneFile As String = System.IO.Path.GetExtension(strPath)
strEstensioneFile = Strings.Right(strEstensioneFile, 3)
'trasformo la stringa contenente l'estensione del file in un array di byte
Dim abytEstensioneFile As Byte()
abytEstensioneFile = Encoding.Default.GetBytes(strEstensioneFile)
'carico negli ultimi 3 posti dell'array contenente il file l'estensione del file
Dim i As Integer
For i = 0 To 2
abytFile(intLunghFile + i) = abytEstensioneFile(i)
Next
End Sub
Public Sub RimuoviEst()
'ridimensiono l'array contenente il file in modo da eliminare i 3 caratteri dell'estensione in fondo
Dim intLunghFile As Integer = abytFile.Length
ReDim Preserve abytFile(intLunghFile - 4)
End Sub
- 92 -
Private Sub cmdCripta_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles cmdCripta.Click
'metto il cursore a forma di clessidra
Me.Cursor = Cursors.WaitCursor
'setto il Flag a 0 per dire che sto Criptando
blnFlag = 0
txtChiavescelta.Text = ""
Try
'leggo il file
Call LeggiFile(strPath)
'verifico la correttezza della chiave
If VerificaChiave(txtChiave.Text) = True Then
'aggiungo l'estensione al contenuto del file
Call AggiungiEst()
'cripto il file
abytFile = Cripta(bytIV, txtChiave.Text, abytFile)
'scrivo il file
Call ScriviFile(strPath, abytFile)
txtChiavescelta.Text = txtChiave.Text
'inizializzo
Call init()
Else
txtChiave.Text = ""
txtChiave.Select()
End If
Catch ex As Exception
If strPath = "" Then
MsgBox("Non è stato scelto nessun file", MsgBoxStyle.Exclamation)
Else
MsgBox("Non è possibile aprire il file", MsgBoxStyle.Exclamation)
strPath = ""
End If
txtPath.Text = ""
txtPath.Select()
End Try
'metto il cursore di default
Me.Cursor = Cursors.Default
End Sub
Private Sub cmdDecripta_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles cmdDecripta.Click
'metto il cursore a forma di clessidra
Me.Cursor = Cursors.WaitCursor
'setto il Flag ad 1 per dire che sto Decriptando
blnFlag = 1
txtChiavescelta.Text = ""
Try
'leggo il file
Call LeggiFile(strPath)
If VerificaChiave(txtChiave.Text) = True Then
'decripto il file
abytFile = Decripta(txtChiave.Text, abytFile)
'gestisco l'errore dovuto alla funzione decripta se la chiave è errata
If abytFile IsNot Nothing Then
'leggo l'estensione dall'array contenente il file decriptato
'che serve per inserirla nella funzione per scriverlo
Dim intLunghFile As Integer = abytFile.Length - 1
Dim abytEstensioneFile(2) As Byte
Dim i As Integer
- 93 -
For i = 0 To 2
abytEstensioneFile(2 - i) = abytFile(intLunghFile - i)
Next
strEstensioneFile = Encoding.Default.GetString(abytEstensioneFile)
'rimuovo l'estensione dal contenuto del file
Call RimuoviEst()
'scrivo il file
Call ScriviFile(strPath, abytFile)
'inizializzo
Call init()
Else
MsgBox("Non è possibile decriptare il file", MsgBoxStyle.Exclamation)
'inizializzo
Call init()
End If
Else
txtChiave.Text = ""
txtChiave.Select()
End If
Catch ex As Exception
If strPath = "" Then
MsgBox("Non è stato scelto nessun file", MsgBoxStyle.Exclamation)
Else
MsgBox("Non è possibile aprire il file", MsgBoxStyle.Exclamation)
strPath = ""
End If
txtPath.Text = ""
txtPath.Select()
End Try
'metto il cursore di default
Me.Cursor = Cursors.Default
End Sub
Private Sub init()
'inizializzo le variabili pubbliche
abytFile = Nothing
strPath = ""
txtPath.Text = ""
txtChiave.Text = ""
blnFlag = 0
End Sub
Private Sub frmMain_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
‘inizializzo
Call init()
'inizializzo la dimensione della chiave a 256 bit
rbt256bit.Checked = True
intDimensioneChiave = 256
txtChiave.MaxLength = 32
rbt128bit.Checked = False
txtPath.Select()
End Sub
- 94 -
Private Sub rbt128bit_CheckedChanged(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles
rbt128bit.CheckedChanged
'gestisco le opzioni per la lunghezza della chiave
If rbt128bit.Checked = True Then
intDimensioneChiave = 128
txtChiave.MaxLength = 16
rbt256bit.Checked = False
End If
End Sub
Private Sub rbt256bit_CheckedChanged(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles
rbt256bit.CheckedChanged
'gestisco le opzioni per la lunghezza della chiave
If rbt256bit.Checked = True Then
intDimensioneChiave = 256
txtChiave.MaxLength = 32
rbt128bit.Checked = False
End If
End Sub
End Class
- 95 -
Codice VB.NET del software di steganografia
Option Explicit On
Imports System.IO
Imports System.Text
Imports System.Text.RegularExpressions
Public Class frmMain
Public strPath As String 'contiene il Path del file
Public abytFile As Byte() 'contiene il file in byte
Public intDimensioneChiave As Integer 'contiene la dimensione della chiave
#Region "Drag&Drop"
Private Sub txtPath_DragDrop(ByVal sender As Object, _
ByVal e As System.Windows.Forms.DragEventArgs) Handles txtPath.DragDrop
If (e.Data.GetDataPresent(DataFormats.FileDrop)) Then
e.Effect = DragDropEffects.Copy
Else
e.Effect = DragDropEffects.None
End If
End Su
Private Sub txtPath_DragEnter(ByVal sender As Object, _
ByVal e As System.Windows.Forms.DragEventArgs) Handles txtPath.DragEnter
Dim sPathName As String()
sPathName = e.Data.GetData(DataFormats.FileDrop)
txtPath.Text = sPathName(0)
strPath = sPathName(0)
lblBitByteModificati.Text = "Utilizzo bit: "
txtRecuperochiave.Text = ""
End Sub
Private Sub txtPath_DragLeave(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles txtPath.DragLeave
txtPath.Text = strPath
'se il file non è una Bitmap inizializzo
If VerificaFile(strPath) = True Then
Call Init()
End If
End Sub
Public Function VerificaFile(ByVal vstrPathName As String) As Boolean
'verifico che l'estensione del file sia BMP
If System.IO.Path.GetExtension(vstrPathName) <> ".bmp" Then
MsgBox("Il file selezionato non è un'immagine Bitmap", MsgBoxStyle.Exclamation)
Return True
End If
End Function
#End Region
- 96 -
#Region "Funzioni per Lettura e Scrittura"
Public Function LeggiFile(ByVal vstrPathName As String) As Byte()
'leggo il file usando BinaryReader in modo da ottenere un'array di byte
Dim objFileL As New FileStream(vstrPathName, FileMode.OpenOrCreate, FileAccess.Read)
Dim objFileLBR As New BinaryReader(objFileL)
abytFile = objFileLBR.ReadBytes(objFileL.Length)
objFileL.Close()
objFileLBR.Close()
Return abytFile
End Function
Private Sub ScriviFile(ByVal vstrPathName As String, ByVal vabytFileS As Byte())
'sfruttando la classe Path ottengo: directory e nome del file
Dim strDirFile As String = Path.GetDirectoryName(vstrPathName)
Dim strNomeFile As String = Path.GetFileNameWithoutExtension(vstrPathName)
'se il file esiste già aggiungo al nome un trattino
If File.Exists(strDirFile & "\" & strNomeFile & ".bmp") Then
strNomeFile &= "_"
Else
strNomeFile &= ""
End If
Dim objFileS As New FileStream(strDirFile & "\" & strNomeFile & _
".bmp", FileMode.Create, FileAccess.Write)
Dim objFileSBW As New BinaryWriter(objFileS)
objFileSBW.Write(vabytFileS)
objFileS.Close()
objFileSBW.Close()
End Sub
#End Region
Public Sub Init()
txtChiave.Text = ""
lblBitByteModificati.Text = "Utilizzo bit: "
txtPath.Text = ""
strPath = ""
txtRecuperochiave.Text = ""
End Sub
Private Sub cmdStego_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles cmdStego.Click
'verifico la correttezza della chiave
If Regex.IsMatch(txtChiave.Text, "[^0-9a-zA-Z]") Then
'se è sbagliata avverto l'utente
MsgBox("La chiave non è valida: può contenere solo caratteri alfanumerici",
MsgBoxStyle.Exclamation)
txtChiave.Text = ""
txtChiave.Select()
Exit Sub
End If
'metto il cursore a forma di clessidra
Me.Cursor = Cursors.WaitCursor
Try
Dim a As Integer
Dim b As Integer
Dim aintCar(62) As Integer
- 97 -
Dim aintCarShift(62) As Integer
'popolo aintCaratteri con le posizione dei pixel neri
For a = 0 To 62
aintCar(a) = a
Next
'shifto la aintCaratteri in base allo Shift richiesto dall'utente come usando un cifrario a scorrimento
For a = 0 To 62
If (a + txtCarShift.Text) <= 62 Then
aintCarShift(a + txtCarShift.Text) = aintCar(a)
End If
Next
For b = 0 To txtCarShift.Text - 1
aintCarShift(b) = aintCar(63 - txtCarShift.Text + b)
Next
'prendo la chiave dell'utente e vado ad inserire su aintNumPixCar il numero
'equivalente alla posizione dei caratteri della chiave
'contiene il pixel nero dei caratteri della chiave
Dim aintNumPixCar(intDimensioneChiave - 1) As Integer
Dim aintPosPixCar(intDimensioneChiave - 1) As Integer
For a = 0 To intDimensioneChiave - 1
Select Case txtChiave.Text.Substring(a, 1) 'scorro un carattere alla volta la chiave
Case Is = "0"
aintNumPixCar(a) = 0
Case Is = "1"
aintNumPixCar(a) = 1
Case Is = "2"
aintNumPixCar(a) = 2
Case Is = "3"
aintNumPixCar(a) = 3
Case Is = "4"
aintNumPixCar(a) = 4
Case Is = "5"
aintNumPixCar(a) = 5
Case Is = "6"
aintNumPixCar(a) = 6
Case Is = "7"
aintNumPixCar(a) = 7
Case Is = "8"
aintNumPixCar(a) = 8
Case Is = "9"
aintNumPixCar(a) = 9
Case Is = "a"
aintNumPixCar(a) = 10
Case Is = "b"
aintNumPixCar(a) = 11
Case Is = "c"
aintNumPixCar(a) = 12
Case Is = "d"
aintNumPixCar(a) = 13
Case Is = "e"
aintNumPixCar(a) = 14
Case Is = "f"
aintNumPixCar(a) = 15
Case Is = "g"
aintNumPixCar(a) = 16
Case Is = "h"
aintNumPixCar(a) = 17
Case Is = "i"
aintNumPixCar(a) = 18
Case Is = "j"
- 98 -
aintNumPixCar(a) = 19
Case Is = "k"
aintNumPixCar(a) = 20
Case Is = "l"
aintNumPixCar(a) = 21
Case Is = "m"
aintNumPixCar(a) = 22
Case Is = "n"
aintNumPixCar(a) = 23
Case Is = "o"
aintNumPixCar(a) = 24
Case Is = "p"
aintNumPixCar(a) = 25
Case Is = "q"
aintNumPixCar(a) = 26
Case Is = "r"
aintNumPixCar(a) = 27
Case Is = "s"
aintNumPixCar(a) = 28
Case Is = "t"
aintNumPixCar(a) = 29
Case Is = "u"
aintNumPixCar(a) = 30
Case Is = "v"
aintNumPixCar(a) = 31
Case Is = "w"
aintNumPixCar(a) = 32
Case Is = "x"
aintNumPixCar(a) = 33
Case Is = "y"
aintNumPixCar(a) = 34
Case Is = "z"
aintNumPixCar(a) = 35
Case Is = "A"
aintNumPixCar(a) = 36
Case Is = "B"
aintNumPixCar(a) = 37
Case Is = "C"
aintNumPixCar(a) = 38
Case Is = "D"
aintNumPixCar(a) = 39
Case Is = "E"
aintNumPixCar(a) = 40
Case Is = "F"
aintNumPixCar(a) = 41
Case Is = "G"
aintNumPixCar(a) = 42
Case Is = "H"
aintNumPixCar(a) = 43
Case Is = "I"
aintNumPixCar(a) = 44
Case Is = "J"
aintNumPixCar(a) = 45
Case Is = "K"
aintNumPixCar(a) = 46
Case Is = "L"
aintNumPixCar(a) = 47
Case Is = "M"
aintNumPixCar(a) = 48
Case Is = "N"
- 99 -
aintNumPixCar(a) = 49
Case Is = "O"
aintNumPixCar(a) = 50
Case Is = "P"
aintNumPixCar(a) = 51
Case Is = "Q"
aintNumPixCar(a) = 52
Case Is = "R"
aintNumPixCar(a) = 53
Case Is = "S"
aintNumPixCar(a) = 54
Case Is = "T"
aintNumPixCar(a) = 55
Case Is = "U"
aintNumPixCar(a) = 56
Case Is = "V"
aintNumPixCar(a) = 57
Case Is = "W"
aintNumPixCar(a) = 58
Case Is = "X"
aintNumPixCar(a) = 59
Case Is = "Y"
aintNumPixCar(a) = 60
Case Is = "Z"
aintNumPixCar(a) = 61
Case Is = "_"
aintNumPixCar(a) = 62
End Select
aintPosPixCar(a) = aintCarShift(aintNumPixCar(a))
Next
‘leggo il file
Call LeggiFile(strPath)
'valuto se il file è troppo piccolo per contenere la chiave
If abytFile.Length > (intDimensioneChiave * 64 + 54) Then
'contiene il numero di bit da utilizzare per la modifica
Dim intNumBit As Integer = txtNumBit.Text - 1
Dim abytCella(63) As Byte 'contiene la matrice di un carattere
Dim intPix As Integer 'contiene il byte da elaborare
'contatore per il ciclo del numero di caratteri della chiave
Dim intContDimChiave As Integer
'contatore per il ciclo del numero di pixel della matrice di codifica
Dim intContDimMatPix As Integer
'contatore per il ciclo del numero di bit da utilizzare
Dim intContNumBit As Integer
Dim intBitModificati As Integer = 0 'contiene il numero di bit modificati
Dim intByteModificati As Integer = 0 'contiene il numero di byte modificati
For intContDimChiave = 0 To intDimensioneChiave - 1
'vado a modificare la matrice in base alla chiave
For intContDimMatPix = 0 To 63
'carico la matrice di 64 pixel
abytCella(intContDimMatPix) = abytFile(54 + intContDimMatPix + _
(intContDimChiave * 64))
Dim resto As Integer
'verifico la condizione sul resto
resto = 0
intPix = abytCella(intContDimMatPix)
For intContNumBit = 0 To intNumBit
If CBool(intPix And (1 << intNumBit - intContNumBit)) = True Then
resto += 2 ^ (intNumBit - intContNumBit)
End If
- 100 -
Next
If intContDimMatPix = aintPosPixCar(intContDimChiave) Then
'pixel nero
'se resto=0 allora è già corretto
If resto > 0 Then
abytFile(54 + intContDimMatPix + (intContDimChiave * 64)) -= resto
'conto i byte modificati
intByteModificati += 1
'conto i bit cambiati
Dim intContBitModificati As Integer
Dim aintConfronto() As Integer = {128, 64, 32, 16, 8, 4, 2, 1}
For intContBitModificati = 0 To 7
If (resto And aintConfronto(intContBitModificati)) _
= aintConfronto(intContBitModificati) Then
intBitModificati += 1
End If
Next
End If
Else
'pixel bianco
'se resto>1 allora è già corretto
If resto = 0 Then
abytFile(54 + intContDimMatPix + (intContDimChiave * 64)) += 1
'conto i byte modificati
intByteModificati += 1
'conto i bit modificati
intBitModificati += 1
End If
End If
Next
Next
'scrivo il file
Call ScriviFile(strPath, abytFile)
'scrivo nella txtBox il numero di bit modificati in relazione ai byte modificati
Dim strMessaggio As String = Nothing
Select Case intBitModificati / intByteModificati
Case Is = 0
strMessaggio = " media 0 bit per byte"
Case Is = 1
strMessaggio = " media 1 bit per byte"
Case Is > 1
strMessaggio = " media " & _
Math.Round(intBitModificati / intByteModificati, 2) & " bit per byte"
End Select
lblBitByteModificati.Text = "Utilizzo bit: variati " & intBitModificati & _
" bit su " & intByteModificati & " byte:" & strMessaggio
Else
MsgBox("Il file .bmp non è abbastanza grande", MsgBoxStyle.Exclamation)
End If
txtChiave.Text = ""
txtPath.Text = ""
strPath = ""
txtPath.Select()
Catch ex As Exception
'verifico che Path<>""
If strPath = "" Then
MsgBox("Non è stato scelto nessun file", MsgBoxStyle.Exclamation)
txtPath.Select()
'End If
'verifico la correttezza della chiave
- 101 -
ElseIf txtChiave.Text = "" Then
MsgBox("Non è stata inserita la chiave", MsgBoxStyle.Exclamation)
txtChiave.Select()
ElseIf txtChiave.Text.Length < intDimensioneChiave Then
'se è sbagliata avverto l'utente
MsgBox("La chiave non è valida:" & _
" deve essere lunga: " & intDimensioneChiave & " caratteri", MsgBoxStyle.Exclamation)
txtChiave.Text = ""
txtChiave.Select()
End If
End Try
'metto il cursore di default
Me.Cursor = Cursors.Default
End Sub
Private Sub cmdDeStego_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles cmdDeStego.Click
txtRecuperochiave.Text = ""
'metto il cursore a forma di clessidra
Me.Cursor = Cursors.WaitCursor
Try
Call LeggiFile(strPath)
'contiene l'offset dei caratteri nella matrice 8x8
Dim aintPosPixCar(intDimensioneChiave - 1) As Integer
'contiene il numero di bit da utilizzare per la modifica
Dim intNumBit As Integer = txtNumBit.Text - 1
Dim abytCella(63) As Byte 'contiene la matrice di un carattere
'contatore per il ciclo del numero di caratteri della chiave
Dim intContDimChiave As Integer
'contatore per il ciclo del numero di pixel della matrice di codifica
Dim intContDimMatPix As Integer
'contatore per il ciclo del numero di bit da utilizzare
Dim intContNumBit As Integer
For intContDimChiave = 0 To intDimensioneChiave - 1
'vado a modificare la matrice in base alla chiave
For intContDimMatPix = 0 To 63
'carico la matrice di 64 pixel
abytCella(intContDimMatPix) = abytFile(54 + intContDimMatPix + (intContDimChiave * 64))
Dim resto As Integer
'verifico la condizione sul resto
resto = 0
For intContNumBit = 0 To intNumBit
If CBool(abytCella(intContDimMatPix) And (1 << intNumBit - intContNumBit)) = True Then
resto += 2 ^ (intNumBit - intContNumBit)
End If
Next
'pixel nero
If resto = 0 Then
aintPosPixCar(intContDimChiave) = intContDimMatPix
End If
Next
Next
Dim astrConfronto() As String = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9" _
, "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p" _
, "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" _
, "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P" _
, "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "_"}
Dim a As Integer
- 102 -
'prendo i caratteri shiftati corrisponendi alla chiave e li metto nella txtChiave
For a = 0 To intDimensioneChiave - 1
If (aintPosPixCar(a) + txtCarShift.Text) <= 62 Then
txtRecuperochiave.Text &= astrConfronto(aintPosPixCar(a) + txtCarShift.Text)
Else
txtRecuperochiave.Text &= astrConfronto(aintPosPixCar(a) + txtCarShift.Text - 63)
End If
Next
Catch ex As Exception
If strPath = "" Then
MsgBox("Non è stato scelto nessun file", MsgBoxStyle.Exclamation)
End If
End Try
'metto il cursore di default
Me.Cursor = Cursors.Default
strPath = ""
txtPath.Text = ""
txtPath.Select()
End Sub
Private Sub frmMain_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
'inizializzo la dimensione della chiave a 256 bit
rbt256bit.Checked = True
intDimensioneChiave = 32
txtChiave.MaxLength = 32
rbt128bit.Checked = False
'inizializza il numero dei bit e lo shift
txtNumBit.Text = 3
txtCarShift.Text = 50
End Sub
Private Sub rbt128bit_CheckedChanged(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles rbt128bit.CheckedChanged
'gestisco le opzioni per la lunghezza della chiave
If rbt128bit.Checked = True Then
intDimensioneChiave = 16
txtChiave.MaxLength = 16
rbt256bit.Checked = False
End If
End Sub
Private Sub rbt256bit_CheckedChanged(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles rbt256bit.CheckedChanged
'gestisco le opzioni per la lunghezza della chiave
If rbt256bit.Checked = True Then
intDimensioneChiave = 32
txtChiave.MaxLength = 32
rbt128bit.Checked = False
End If
End Sub
End Class
- 103 -
Codice ASP del software web
Script per la funzione di hash MD5 - Autore: Phil Fresle
<%
Private Const BITS_TO_A_BYTE=8
Private Const BYTES_TO_A_WORD=4
Private Const BITS_TO_A_WORD=32
Private m_lOnBits(30)
Private m_l2Power(30)
m_lOnBits(0)=CLng(1)
m_lOnBits(1)=CLng(3)
m_lOnBits(2)=CLng(7)
m_lOnBits(3)=CLng(15)
m_lOnBits(4)=CLng(31)
m_lOnBits(5)=CLng(63)
m_lOnBits(6)=CLng(127)
m_lOnBits(7)=CLng(255)
m_lOnBits(8)=CLng(511)
m_lOnBits(9)=CLng(1023)
m_lOnBits(10)=CLng(2047)
m_lOnBits(11)=CLng(4095)
m_lOnBits(12)=CLng(8191)
m_lOnBits(13)=CLng(16383)
m_lOnBits(14)=CLng(32767)
m_lOnBits(15)=CLng(65535)
m_lOnBits(16)=CLng(131071)
m_lOnBits(17)=CLng(262143)
m_lOnBits(18)=CLng(524287)
m_lOnBits(19)=CLng(1048575)
m_lOnBits(20)=CLng(2097151)
m_lOnBits(21)=CLng(4194303)
m_lOnBits(22)=CLng(8388607)
m_lOnBits(23)=CLng(16777215)
m_lOnBits(24)=CLng(33554431)
m_lOnBits(25)=CLng(67108863)
m_lOnBits(26)=CLng(134217727)
m_lOnBits(27)=CLng(268435455)
m_lOnBits(28)=CLng(536870911)
m_lOnBits(29)=CLng(1073741823)
m_lOnBits(30)=CLng(2147483647)
m_l2Power(0)=CLng(1)
m_l2Power(1)=CLng(2)
m_l2Power(2)=CLng(4)
m_l2Power(3)=CLng(8)
m_l2Power(4)=CLng(16)
m_l2Power(5)=CLng(32)
m_l2Power(6)=CLng(64)
m_l2Power(7)=CLng(128)
m_l2Power(8)=CLng(256)
m_l2Power(9)=CLng(512)
m_l2Power(10)=CLng(1024)
m_l2Power(11)=CLng(2048)
m_l2Power(12)=CLng(4096)
m_l2Power(13)=CLng(8192)
m_l2Power(14)=CLng(16384)
m_l2Power(15)=CLng(32768)
m_l2Power(16)=CLng(65536)
m_l2Power(17)=CLng(131072)
- 104 -
m_l2Power(18)=CLng(262144)
m_l2Power(19)=CLng(524288)
m_l2Power(20)=CLng(1048576)
m_l2Power(21)=CLng(2097152)
m_l2Power(22)=CLng(4194304)
m_l2Power(23)=CLng(8388608)
m_l2Power(24)=CLng(16777216)
m_l2Power(25)=CLng(33554432)
m_l2Power(26)=CLng(67108864)
m_l2Power(27)=CLng(134217728)
m_l2Power(28)=CLng(268435456)
m_l2Power(29)=CLng(536870912)
m_l2Power(30)=CLng(1073741824)
Private Function LShift(lValue,iShiftBits)
If iShiftBits=0 Then
LShift=lValue
Exit Function
ElseIf iShiftBits=31 Then
If lValue And 1 Then
LShift=&H80000000
Else
LShift=0
End If
Exit Function
ElseIf iShiftBits<0 Or iShiftBits>31 Then
Err.Raise 6
End If
If (lValue And m_l2Power(31-iShiftBits)) Then
LShift=((lValue And m_lOnBits(31-(iShiftBits+1)))*m_l2Power(iShiftBits)) Or &H80000000
Else
LShift=((lValue And m_lOnBits(31-iShiftBits))*m_l2Power(iShiftBits))
End If
End Function
Private Function RShift(lValue,iShiftBits)
If iShiftBits=0 Then
RShift=lValue
Exit Function
ElseIf iShiftBits=31 Then
If lValue And &H80000000 Then
RShift=1
Else
RShift=0
End If
Exit Function
ElseIf iShiftBits<0 Or iShiftBits>31 Then
Err.Raise 6
End If
RShift=(lValue And &H7FFFFFFE)\m_l2Power(iShiftBits)
If (lValue And &H80000000) Then
RShift=(RShift Or (&H40000000\m_l2Power(iShiftBits-1)))
End If
End Function
Private Function RotateLeft(lValue,iShiftBits)
RotateLeft=LShift(lValue,iShiftBits) Or RShift(lValue,(32-iShiftBits))
End Function
- 105 -
Private Function AddUnsigned(lX,lY)
Dim lX4
Dim lY4
Dim lX8
Dim lY8
Dim lResult
lX8=lX And &H80000000
lY8=lY And &H80000000
lX4=lX And &H40000000
lY4=lY And &H40000000
lResult=(lX And &H3FFFFFFF)+(lY And &H3FFFFFFF)
If lX4 And lY4 Then
lResult=lResult Xor &H80000000 Xor lX8 Xor lY8
ElseIf lX4 Or lY4 Then
If lResult And &H40000000 Then
lResult=lResult Xor &HC0000000 Xor lX8 Xor lY8
Else
lResult=lResult Xor &H40000000 Xor lX8 Xor lY8
End If
Else
lResult=lResult Xor lX8 Xor lY8
End If
AddUnsigned=lResult
End Function
Private Function F(x,y,z)
F=(x And y) Or ((Not x) And z)
End Function
Private Function G(x,y,z)
G=(x And z) Or (y And (Not z))
End Function
Private Function H(x,y,z)
H=(x Xor y Xor z)
End Function
Private Function I(x,y,z)
I=(y Xor (x Or (Not z)))
End Function
Private Sub FF(a,b,c,d,x,s,ac)
a=AddUnsigned(a,AddUnsigned(AddUnsigned(F(b,c,d),x),ac))
a=RotateLeft(a,s)
a=AddUnsigned(a,b)
End Sub
Private Sub GG(a,b,c,d,x,s,ac)
a=AddUnsigned(a,AddUnsigned(AddUnsigned(G(b,c,d),x),ac))
a=RotateLeft(a,s)
a=AddUnsigned(a,b)
End Sub
Private Sub HH(a,b,c,d,x,s,ac)
a=AddUnsigned(a,AddUnsigned(AddUnsigned(H(b,c,d),x),ac))
a=RotateLeft(a,s)
a=AddUnsigned(a,b)
End Sub
- 106 -
Private Sub II(a,b,c,d,x,s,ac)
a=AddUnsigned(a,AddUnsigned(AddUnsigned(I(b,c,d),x),ac))
a=RotateLeft(a,s)
a=AddUnsigned(a,b)
End Sub
Private Function ConvertToWordArray(sMessage)
Dim lMessageLength
Dim lNumberOfWords
Dim lWordArray()
Dim lBytePosition
Dim lByteCount
Dim lWordCount
Dim lByteValue ' need these variables to handle byte value and input argument type
Dim lMessageType
Const MODULUS_BITS=512
Const CONGRUENT_BITS=448
lMessageType=Vartype(sMessage)
Select Case lMessageType ' strings or Variant Byte Arrays: nothing else!
Case 8 : lMessageLength=Len(sMessage)
Case 8209 : lMessageLength=LenB(sMessage)
Case Else Err.Raise -1,"MD5","Unknown Type passed to MD5 function"
End Select
lNumberOfWords=(((lMessageLength+((MODULUS_BITSCONGRUENT_BITS)\BITS_TO_A_BYTE))\(MODULUS_BITS\BITS_TO_A_BYTE))+1)* _
(MODULUS_BITS\BITS_TO_A_WORD)
ReDim lWordArray(lNumberOfWords-1)
lBytePosition=0
lByteCount=0
Do Until lByteCount >=lMessageLength
lWordCount=lByteCount\BYTES_TO_A_WORD
lBytePosition=(lByteCount Mod BYTES_TO_A_WORD)*BITS_TO_A_BYTE
Select Case lMessageType ' get the next byte value
Case 8 : lByteValue = Asc (Mid (sMessage,lByteCount+1,1))
Case 8209 : lByteValue = AscB(MidB(sMessage,lByteCount+1,1))
End Select
lWordArray(lWordCount)=lWordArray(lWordCount) Or LShift(lByteValue,lBytePosition)
lByteCount=lByteCount+1
Loop
lWordCount=lByteCount\BYTES_TO_A_WORD
lBytePosition=(lByteCount Mod BYTES_TO_A_WORD)*BITS_TO_A_BYTE
lWordArray(lWordCount)=lWordArray(lWordCount) Or LShift(&H80,lBytePosition)
lWordArray(lNumberOfWords-2)=LShift(lMessageLength,3)
lWordArray(lNumberOfWords-1)=RShift(lMessageLength,29)
ConvertToWordArray=lWordArray
End Function
Private Function WordToHex(lValue)
Dim lByte
Dim lCount
For lCount=0 To 3
lByte=RShift(lValue,lCount*BITS_TO_A_BYTE) And m_lOnBits(BITS_TO_A_BYTE-1)
WordToHex=WordToHex & Right("0" & Hex(lByte),2)
Next
End Function
- 107 -
Public Function MD5(sMessage)
Dim x
Dim k
Dim AA
Dim BB
Dim CC
Dim DD
Dim a
Dim b
Dim c
Dim d
Const S11=7
Const S12=12
Const S13=17
Const S14=22
Const S21=5
Const S22=9
Const S23=14
Const S24=20
Const S31=4
Const S32=11
Const S33=16
Const S34=23
Const S41=6
Const S42=10
Const S43=15
Const S44=21
x=ConvertToWordArray(sMessage)
a=&H67452301
b=&HEFCDAB89
c=&H98BADCFE
d=&H10325476
For k=0 To UBound(x) Step 16
AA=a
BB=b
CC=c
DD=d
FF a,b,c,d,x(k+0),S11,&HD76AA478
FF d,a,b,c,x(k+1),S12,&HE8C7B756
FF c,d,a,b,x(k+2),S13,&H242070DB
FF b,c,d,a,x(k+3),S14,&HC1BDCEEE
FF a,b,c,d,x(k+4),S11,&HF57C0FAF
FF d,a,b,c,x(k+5),S12,&H4787C62A
FF c,d,a,b,x(k+6),S13,&HA8304613
FF b,c,d,a,x(k+7),S14,&HFD469501
FF a,b,c,d,x(k+8),S11,&H698098D8
FF d,a,b,c,x(k+9),S12,&H8B44F7AF
FF c,d,a,b,x(k+10),S13,&HFFFF5BB1
FF b,c,d,a,x(k+11),S14,&H895CD7BE
FF a,b,c,d,x(k+12),S11,&H6B901122
FF d,a,b,c,x(k+13),S12,&HFD987193
FF c,d,a,b,x(k+14),S13,&HA679438E
FF b,c,d,a,x(k+15),S14,&H49B40821
GG a,b,c,d,x(k+1),S21,&HF61E2562
GG d,a,b,c,x(k+6),S22,&HC040B340
GG c,d,a,b,x(k+11),S23,&H265E5A51
GG b,c,d,a,x(k+0),S24,&HE9B6C7AA
GG a,b,c,d,x(k+5),S21,&HD62F105D
GG d,a,b,c,x(k+10),S22,&H2441453
GG c,d,a,b,x(k+15),S23,&HD8A1E681
- 108 -
GG b,c,d,a,x(k+4),S24,&HE7D3FBC8
GG a,b,c,d,x(k+9),S21,&H21E1CDE6
GG d,a,b,c,x(k+14),S22,&HC33707D6
GG c,d,a,b,x(k+3),S23,&HF4D50D87
GG b,c,d,a,x(k+8),S24,&H455A14ED
GG a,b,c,d,x(k+13),S21,&HA9E3E905
GG d,a,b,c,x(k+2),S22,&HFCEFA3F8
GG c,d,a,b,x(k+7),S23,&H676F02D9
GG b,c,d,a,x(k+12),S24,&H8D2A4C8A
HH a,b,c,d,x(k+5),S31,&HFFFA3942
HH d,a,b,c,x(k+8),S32,&H8771F681
HH c,d,a,b,x(k+11),S33,&H6D9D6122
HH b,c,d,a,x(k+14),S34,&HFDE5380C
HH a,b,c,d,x(k+1),S31,&HA4BEEA44
HH d,a,b,c,x(k+4),S32,&H4BDECFA9
HH c,d,a,b,x(k+7),S33,&HF6BB4B60
HH b,c,d,a,x(k+10),S34,&HBEBFBC70
HH a,b,c,d,x(k+13),S31,&H289B7EC6
HH d,a,b,c,x(k+0),S32,&HEAA127FA
HH c,d,a,b,x(k+3),S33,&HD4EF3085
HH b,c,d,a,x(k+6),S34,&H4881D05
HH a,b,c,d,x(k+9),S31,&HD9D4D039
HH d,a,b,c,x(k+12),S32,&HE6DB99E5
HH c,d,a,b,x(k+15),S33,&H1FA27CF8
HH b,c,d,a,x(k+2),S34,&HC4AC5665
II a,b,c,d,x(k+0),S41,&HF4292244
II d,a,b,c,x(k+7),S42,&H432AFF97
II c,d,a,b,x(k+14),S43,&HAB9423A7
II b,c,d,a,x(k+5),S44,&HFC93A039
II a,b,c,d,x(k+12),S41,&H655B59C3
II d,a,b,c,x(k+3),S42,&H8F0CCC92
II c,d,a,b,x(k+10),S43,&HFFEFF47D
II b,c,d,a,x(k+1),S44,&H85845DD1
II a,b,c,d,x(k+8),S41,&H6FA87E4F
II d,a,b,c,x(k+15),S42,&HFE2CE6E0
II c,d,a,b,x(k+6),S43,&HA3014314
II b,c,d,a,x(k+13),S44,&H4E0811A1
II a,b,c,d,x(k+4),S41,&HF7537E82
II d,a,b,c,x(k+11),S42,&HBD3AF235
II c,d,a,b,x(k+2),S43,&H2AD7D2BB
II b,c,d,a,x(k+9),S44,&HEB86D391
a=AddUnsigned(a,AA)
b=AddUnsigned(b,BB)
c=AddUnsigned(c,CC)
d=AddUnsigned(d,DD)
Next
MD5=LCase(WordToHex(a) & WordToHex(b) & WordToHex(c) & WordToHex(d))
End Function
%>
- 109 -
Script per il login
<%
'funzione per prevenire attacchi di SQL injection
'al posto dei caratteri sensibili inserisco caratteri innoqui
Function FiltraSQL(strSQL)
strSQL = Replace(strSQL, "'", "''")
strSQL = Replace(strSQL, "%", "[%]")
strSQL = Replace(strSQL, "[", "[[]")
strSQL = Replace(strSQL, "]", "[]]")
strSQL = Replace(strSQL, "_", "[_]")
strSQL = Replace(strSQL, "#", "[#]")
FiltraSQL = strSQL
End function
'se è stato premuto il bottone Login
If Request.Form("Login")="Login" then
'recupero l'Username
Username = Request.Form("username")
'recupero la Password e ne faccio l'hash
Password = MD5(Request.Form("password"))
'verifico che i campi "Username" e "Password" non siano vuoti
If Username <> "" and Password <> "" then
'i dati sono corretti, posso iniziare il controllo sul database
'mi connetto al database
url_DB = "driver={Microsoft Access Driver (*.mdb)};dbq=" & server.mappath("db/user.mdb")
Set Conn = Server.CreateObject("ADODB.Connection")
conn.Open url_DB
Set RecSet = Server.CreateObject("ADODB.Recordset")
'preparo la query filtrata contro SQL injection
SQL = "SELECT * FROM Utenti where Username = '" & FiltraSQL(Username) &_
"' and Password = '" & FiltraSQL(Password) & "' "
'RecSet.Open SQL, Conn, adOpenStatic, adLockOptimistic
RecSet.Open SQL, Conn, adOpenStatic
'verifico se l'utente esiste
If Not RecSet.Eof then
'l'utente esiste allora imposto 2 sessioni: Log=True e Username=Username e indirizzo all’area riservata
Session("Log") = True
Session("Username") = Username
Response.Redirect "h_arearis.asp"
Else
'l'utente non esiste allora imposto Log=False
Session("Log") = False
End If
‘Chiudo la connessione al DB
RecSet.Close
Set RecSet = Nothing
Conn.Close
Set Conn = Nothing
‘verifico se l'utente è loggato
If Session("Log") = False then
‘i dati non sono correti: utente inesistente o username/password errati
msg="<p><h2><b>Accesso negato!</b></h2><p>L'UserName o la Password sono errati"
End If
Else
' campi "username" o "password" vuoti
msg="<p><h2><b>Accesso negato!</b></h2><p>I Campi UserName o Password sono vuoti"
End If
End If
%>
- 110 -
<!--form per il login-->
<center>
<%=msg%>
<form method="POST" action="">
<table border="0" cellspacing="0" cellpadding="0">
<tr><td width=75>UserName:</td><td><INPUT TYPE=Text NAME="username" size="12"></td></tr>
<tr><td width=75>Password:</td><td><INPUT TYPE=Password NAME="password" size="12"></td></tr>
</table>
<input type="submit" value="Login" name="Login">
</form>
<script>document.login.username.focus();</script>
</center>
<!--form per il login-->
- 111 -
Script da inserire su ogni pagina dell'area riservata
<%
'setto la pagina in modo che non sia accessibile dopo il logout tramite il tasto indietro del browser
'faccio in modo tale che il browser non memorizzi le pagine dell'area riservata nella cache
Response.Buffer = True
Response.ExpiresAbsolute = Now()-1
Response.Expires = 0
Response.AddHeader "pragma", "no-cache"
Response.AddHeader "cache-control", "no-store, must-revalidate, private"
Response.CacheControl = "private"
'la pagina non essendo nella cache quando viene premuto il tasto indietro del browser deve essere ricaricata
'se la lunghezza in caratteri della variabile Session("PrimaVisita") >0
‘allora l'utente non è la prima volta che visita la pagina
If len(Session("PrimaVisita"))>0 then
Session("PrimaVisita") = ""
Response.Redirect("h_login.asp")
Response.End
End If
%>
<%
'verifico se l'utente che vuole accedere è stato loggato, se non lo è lo reindirizzo alla pagina del login
If Session("Log") = False and Session("Username") = "" then
Response.Redirect "h_login.asp"
End If
%>
- 112 -
Classe per la gestione degli upload - Autore: Simone Medas
<SCRIPT LANGUAGE=vbscript RUNAT=Server>
Dim Inputs
'class to store data input
class clsInput
public name
public isFile
private pContent
public size
public fileName
public filePath
public property let content(newContent)
pContent = newContent
end property
public default property get content()
content = pContent
end property
'save the content into file with same filename as uploaded in current application path
public function saveFile()
saveFile = saveFileAs("", "")
end function
'save the content into file with given filename and path
public function saveFileAs(byVal destinationPath, byVal newFileName)
Dim withName
'if content is empty don't save it
if size = 0 then exit function
'append given path if any
if destinationPath <> "" then
withName = destinationPath
else
withName = Server.MapPath(".")
end if
'check if final slash exist, if don't, then do append it
if right(withName, 1) <> "\" then withName = withName & "\"
'append new filename if any
if newFileName <> "" then
withName = withName & newFileName
else
withName = withName & fileName
end if
on error resume next
Set fso = CreateObject("Scripting.FileSystemObject")
Set tf = fso.CreateTextFile(withName , True)
if Err.number = 0 then
tf.Write(pContent)
tf.Close
end if
if Err.number >0 then
saveFileAs = Err.Description
else
saveFileAs = ""
end if
end function
end class
- 113 -
Function UpLoad()
Dim bytArray
Dim bytecount
bytecount = Request.TotalBytes
if bytecount = 0 then
UpLoad = 0
exit function
end if
'continue only when bytecount>0
Set inputs = Server.CreateObject("Scripting.Dictionary")
bytArray = Request.BinaryRead(bytecount)
Dim objInput
Dim adLongVarChar
adLongVarChar = 201
Dim strByteToString
Dim lngLoop
Dim strIDInput
Dim lngStartPos
Dim lngFieldStartPos
Dim strInputHeader
Dim strContetType
Dim strInputName
Dim strFileName
Dim strFilePath
Dim strInputContent
Dim isFile
Dim rstTemp
'we using anrecordset object to quickly convert array of byte to string
Set rstTemp = Server.CreateObject("ADODB.Recordset")
rstTemp.Fields.Append "bytArray", adLongVarChar, lenb(bytArray)
rstTemp.Open
rstTemp.AddNew
rstTemp.Fields("bytArray").AppendChunk bytArray
rstTemp.Update
'we have getted the original string
strByteToString = rstTemp("bytArray")
Set rstTemp=Nothing
lngStartPos = 1
'get row separation
strIDInput = Mid(strByteToString, 1, InStr(1, strByteToString, vbCrLf) - 1)
'for each input field
While lngStartPos > 0
'resets all input variables
strInputHeader = ""
strContetType = ""
strInputContent = ""
strInputName = ""
strFileName = ""
strFilePath = ""
isFile = false
'skip row separation
lngStartPos = lngStartPos + Len(strIDInput) + 2
'gets current input header
strInputHeader = Mid(strByteToString, lngStartPos, InStr(lngStartPos, strByteToString, vbCrLf) + 2 lngStartPos)
'skip input header
lngStartPos = lngStartPos + Len(strInputHeader)
'gets content type if any
strContetType = Mid(strByteToString, lngStartPos, InStr(lngStartPos, strByteToString, vbCrLf) + 2 lngStartPos)
- 114 -
'skip content type
lngStartPos = lngStartPos + Len(strContetType)
If Len(strContetType) > 2 Then lngStartPos = lngStartPos + 2
'gets content input value
strInputContent = Mid(strByteToString, lngStartPos, InStr(lngStartPos, strByteToString, strIDInput) - 2 lngStartPos)
'skip content type
lngStartPos = lngStartPos + Len(strInputContent) + 2
'gets input header fields
'gets "name" field
lngFieldStartPos = InStr(1, strInputHeader, "; name=", vbTextCompare) + 8
strInputName = Mid(strInputHeader, lngFieldStartPos, InStr(lngFieldStartPos, strInputHeader, Chr(34)) lngFieldStartPos)
lngFieldStartPos = 0
'gets "filename" field if exists
lngFieldStartPos = InStr(1, strInputHeader, "; filename=", vbTextCompare)
If lngFieldStartPos > 0 Then
lngFieldStartPos = lngFieldStartPos + 12
strFilePath = Mid(strInputHeader, lngFieldStartPos, InStr(lngFieldStartPos, strInputHeader, Chr(34)) lngFieldStartPos)
if len(strFilePath)>0 then
strFileName = Mid(strFilePath, InStrRev(strFilePath, "\", Len(strFilePath)) + 1)
strFilePath = Mid(strFilePath, 1, InStrRev(strFilePath, strFileName, Len(strFilePath)) - 1)
end if
End If
lngFieldStartPos = 0
'from this point we have all data
If strFileName <> "" Then
isFile = True
else
isFile = False
end if
'create the input object with current values
Set objInput = new clsInput
objInput.name = strInputName
objInput.isFile = isFile
objInput.content = strInputContent
objInput.size = len(strInputContent)
objInput.fileName = strFileName
objInput.filePath = strFilePath
'append just created input object to "inputs" collection
Set inputs(strInputName) = objInput
Set objInput = Nothing
'go to next input value
lngStartPos = InStr(lngStartPos, strByteToString, strIDInput)
'check if input separator is the last
If Mid(strByteToString, lngStartPos + Len(strIDInput) + 1, 1) = "-" Then lngStartPos = 0
Wend
bytArray = ""
UpLoad = bytecount
End Function
</SCRIPT>
- 115 -
Script per la gestione degli upload
<%
'setto la variabile come dimensione del file
bytecount = UpLoad()
'se viene premuto il tasto Invia il file avrà una dimensione maggiore di 0
If bytecount > 0 then
'controllo se il file già esiste
fileOverwrite = False
'creo gli oggetti necessari alla gestione dei file
Set fso = Server.CreateObject("Scripting.FileSystemObject")
file = Server.MapPath("./") & "/filear/" & inputs("uploadFile").fileName
If fso.FileExists(file) then
'imposto la variabile a True, la utilizzerò dopo per bloccare l'upload
fileOverwrite = true
Response.Write "<p>Il file " & inputs("uploadFile").fileName &_
" eiste! Modificare il nome del file per effettuarne l'upload<p>"
End If
'Distruggo gli oggetti creati e libero le risorse
Set fso = nothing
Set file = nothing
'se la stringa immessa nel form è effettivamente un file
‘e non si sta effettuando un overwrite allora eseguo l'upload
If inputs("uploadFile").isFile = True and fileOverwrite = False then
'salvo il file nella directory definita
retErr = inputs("uploadFile").saveFileAs(Server.MapPath("./") & "/filear/", "")
%>
<p>Il file <% =inputs("uploadFile").fileName %> è stato inviato correttamente<p>
<%
End If
%>
<%
'se non è stato scelto nessun file
If inputs("uploadFile").fileName="" then
Response.Write "<p>Non è stato scelto nessun file<p>"
End If
%>
<!--form per upload-->
<form action="" method="post" encType="multipart/form-data" name="Upload">
<INPUT name="uploadFile" type="file"><br>
<INPUT type="submit" value="Invia" name="Invia">
<script>document.Upload.Invia.focus();</script>
</form>
<!--form per upload-->
<%
Else
'rigenerò il form di immissione del file poichè essendo una form "rientrante"
‘la gestione delle eccezoni mi fa ritornare alla pagina stessa
%>
<!--form per upload-->
<form action="" method="post" encType="multipart/form-data" name="Upload">
<INPUT name="uploadFile" type="file"><br>
<INPUT type="submit" value="Invia" name="Invia">
<script>document.Upload.Invia.focus();</script>
- 116 -
</form>
<!--form per upload-->
<%
End If
%>
- 117 -
Script per la pagina di visualizzazione e download dei file
<p>I file disponibili sono:<p>
<%
'creo gli oggetti necessari alla gestione dei file
Set objFso = Server.createObject("Scripting.FileSystemObject")
Set objFolder = objFso.GetFolder(Server.MapPath("./") & "/filear/")
Set objFiles = objFolder.Files
'scorro tutti i file nella cartella selezionata
For Each strFile in objFiles
%>
<table border="0" width="700">
<tr>
<!--nome del file--->
<td width="300"><a href="filear/<% =strFile.Name %>"><% =strFile.Name %> </a></td>
<!--tipo del file--->
<td width="300">
<%
'verifico se l'estensione del file è cry e specifico che si tratta di un file cifrato
If Right(strFile.Name,3)= "cry" then
Response.Write "File crittografato"
Else
Response.Write strFile.type
End If
%>
</td>
<!--dimensione del file--->
<td width="100" align="right">
<%
'gestisco le dimensioni dei file in modo da farle visualizzare come multipli di byte
If strFile.Size<1024 then
Response.Write(strFile.Size) & "byte"
ElseIf strFile.Size<1048576 then
Response.Write(Round((strFile.Size/1024),2)) & "KB"
Else
Response.Write(Round((strFile.Size/1048576),2)) & "MB"
End If
%>
</td>
</tr>
<%
Next
'Distruggo gli oggetti creati e libero le risorse
Set objFso = Nothing
Set objFolder = Nothing
Set objFiles = Nothing
%>
</table>
- 118 -
Script per il logout
<%
'cancello il contenuto di ogni variabile Sessione
Session.Contents.RemoveAll()
'elimino ogni Sessione aperta
Session.Abandon
%>
- 119 -
BIBLIOGRAFIA
Kris Jamsa (2002) “Hacker Proof, Sicurezza in rete Seconda Edizione”, McGrawHill
D.L. 30 giugno 2003, n. 196 “Codice in materia di protezione dei dati personali”
Gazzetta Ufficiale n. 174 del 29 luglio 2003 – Supplemento Ordinario n. 123
D.P.R. 10 novembre 1997, n. 153 “Regolamento recante criteri e modalità per la
formazione e la trasmissione con strumenti informatici e telematici, a norma
dell’articolo 15, comma 2, della legge 15 marzo 1997, n. 59
Gazzetta Ufficiale 13 marzo 1998, Serie Generale, n. 60
Dizionario Treccani
http://www.treccani.it
Philippe Oechslin “Making a Faster Cryptanalytic Time-Memory Trade-Off”
http://lasecwww.epfl.ch/pub/lasec/doc/Oech03.pdf
RSA Laboratories “Public-Key Cryptography Standards (PKCS)”
http://www.rsa.com/rsalabs/node.asp?id=2124
Specifiche tecniche sul formato dei file .bmp e .wav
http://www.wotsit.org/
Specifiche sui protocolli http e https
www.w3.org/Protocols
Vulnerabilità delle applicazioni web
http://www.owasp.org/
- 120 -