CASTIGLIONI MARCO POZZETTI MIRKO TREVISAN MATTEO LA SICUREZZA INFORMATICA ANNO SCOLASTICO 2001/2002 CLASSE 5IB Sommario SOMMARIO Introduzione III Capitolo 1 La storia 1.1 La nascita dei calcolatori 1.1.1 I computer e la seconda guerra mondiale 1.1.2 I computer nel dopoguerra 1.1.3 I computer moderni 1.2 I computer nella seconda guerra mondiale 1 1 2 3 4 Capitolo 2 Il presente 2.1 Le comunicazioni in Internet 2.2 Il protocollo IP 2.2.1 Il preambolo IP 2.2.2 Struttura dell’indirizzo IP 2.3 Il protocollo TCP 2.3.1 Il preambolo TCP 2.3.2 Gestione delle connessioni TCP 2.4 Le porte 2.4.1 Esempi di porte 2.5 I socket 2.6 Esempi 2.6.1 Tracert 2.6.2 Netstat 7 8 8 10 11 12 13 15 16 17 17 18 18 Capitolo 3 La crittografia 3.1 La storia 3.1.1 Crittografia antica 3.1.2 Crittografia fino al XVIII secolo 3.1.3 Crittografia moderna 3.2 Principali cifrari 3.2.1 Cifrari a sostituzione 3.2.2 Cifrario affine 3.2.3 Cifrario Playfair 3.2.4 Stream cypher 3.2.5 Cifrario di Vernam 3.3 La sicurezza perfetta 3.4 Gli algoritmi 3.4.1 Il DES 3.4.2 L’ RSA 3.5 Macchine cifranti 3.5.1 Enigma 3.5.2 La bomba di Turing 3.6 Crittoanalisi 3.6.1 Crittoanalisi statistica 3.6.2 Crittoanalisi lineare 3.6.3 Crittoanalisi differenziale 3.6.4 Crittoanalisi su polialfabetici 3.6.5 Brute force 3.7 Curiosità e considerazioni 19 21 23 25 28 28 28 30 31 32 33 35 35 45 46 46 52 57 57 58 60 60 61 62 I Sommario Capitolo 4 Esempi pratici 4.1 L’uso di Winsock 4.1.1 Struttura dell’applicazione 4.1.2 Implementazione dell’applicazione 4.2 Il DES 4.2.1 La classe CDes 4.3 Scambio di messaggi crittati 4.3.1 Struttura dell’applicazione 4.3.2 Implementazione dell’applicazione 4.4 L’ analisi di un testo 4.4.1 Struttura dell’applicazione 4.4.2 Implementazione dell’applicazione 4.5 I socket in Linux 4.5.1 Implementazione dell’applicazione 4.6 PGP 64 64 66 68 68 75 76 76 78 78 81 88 88 90 Conclusioni 101 Appendice A 105 Appendice B 109 Appendice C 114 Appendice D 120 Appendice E 121 Appendice F 123 Glossario 171 Bibliografia 176 II Introduzione INTRODUZIONE L’ argomento trattato nell’ area di progetto, la sicurezza informatica, è entrato in auge in seguito alla capillare di diffusione dei PC e di Internet. Con essi sono nati i primi seri problemi di sicurezza sia per i privati e, soprattutto, per le grandi aziende. Nell’area di progetto si è cercato di analizzare questo problema prendendo in esame sia la parte teorica che quella pratica. In particolare l’attenzione è stata focalizzata su i due grandi temi chiave della sicurezza : gli attacchi via socket e la crittografia. Infatti sono questi i due temi che ad oggi determinano o meno la sicurezza di un sistema. Il primo, cioè i socket, riguarda la trasmissione delle informazioni, il secondo, la crittografia, riguarda la sicurezza intrinseca di esse. La trattazione di questi argomenti nella parte pratica ha permesso di realizzare una piccola applicazione che è in grado, tramite l’uso congiunto di socket e crittografia, di inviare messaggi cifrati tra due stazioni. Inoltre è stata realizzata una piccola applicazione che permette di crittare i messaggi attraverso algoritmi “storici” come la scacchiera di Polibio o il cifrario di Cesare. Come ultimo esempio pratico è stato analizzato l’uso di PGP. In pratica è stato costruito un piccolo manuale, contenente le istruzioni più importanti, per usare il programma di crittazione più diffuso al mondo. La seconda parte dell’area di progetto si basa sulle conseguenze che l’azione congiunta di informatica e crittografia hanno portato nella storia. In particolare si analizzeranno le tecniche usate nella seconda guerra mondiale per cifrare le informazioni, come la macchina Enigma e quelle per decifrarle, come la Bomba di Turing. In particolare lo sviluppo della crittografia è stato affrontato fin dai primi algoritmi (codice Atbash) fino ad arrivare ai giorni nostri. III La storia Capitolo 1 La storia 1.1 1.2 1.1 La nascita dei calcolatori 1.1.1 I computer e la seconda guerra mondiale 1.1.2 I computer nel dopoguerra 1.1.3 I computer moderni I computer nella seconda guerra mondiale La nascita dei calcolatori La parola computer deriva dal latino “computare” che significa “fare di conto”. Questo strumento è nato per facilitare il calcolo di funzioni matematiche complesse. Già nel 1642 il matematico Blaise Pascal inventò e costruì la prima calcolatrice macchina con riporto automatico con otto cifre. Questa macchina servì solo a dimostrare che si potevano eseguire calcoli matematici anche con macchine e non solo con la mente, mentre il vero e proprio computer nasce solo nel XX secolo. Sempre in questi anni nasce la scienza dell’informatica, che studia l’elaborazione dei dati e il trattamento automatico delle informazioni. 1.1.1 I computer e la seconda guerra mondiale Il secondo conflitto mondiale fu la rampa di lancio dei primi computer, che furono ideati sia dalla parte alleata sia dalla parte tedesca. I tedeschi furono i primi a costruire un macchina che fu in grado di generare un codice crittato, che era incomprensibile per gli alleati. Questo codice, creato dai tedeschi per comunicare strategie di guerra e messaggi, fu incomprensibile per gli alleati per tutta la prima parte del conflitto. Churchill incaricò il matematico inglese Turing, che fu l’ideatore della prima macchina, che era in grado di leggere le informazioni da un nastro e di copiarle su un altro, di dirigere il centro di studi sulla comunicazione. Turing formò un gruppo di lavoro per decifrare i codici crittati, formato da circa settemila persone, sia militari sia personale civile (si andava da matematici, ad archeologi, a crittografici, ad enigmisti, a giocatori d’azzardo e a tante altre persone). Ma solo un esperto di centralini telefonici ideò il primo calcolatore elettromeccanico, che era in grado di trovare in pochi minuti i codici nazisti: questa macchina prese il nome di Colossus. 1 La storia Questo calcolatore cambiò letteralmente le sorti della guerra, infatti, gli alleati erano in grado di prevedere le mosse dei tedeschi e la marina italiana ne fece le spese, venendo sconfitta nel 1941 a Capo Matapan. Alla fine della seconda guerra mondiale Churchill ordinò di smantellare tutti gli esemplari di Colossus. 1.1.2 I computer nel dopoguerra Gli anni del dopoguerra furono fondamentali per la nascita di calcolatori più veloci, anche se questi calcolatori “moderni” erano molto grossi, pesanti e lenti rispetto a quelli che usiamo ora. Il primo calcolatore elettromeccanico funzionava automaticamente con programmi registrati (che sono gli “antenati” dei primi software). Il nome di questo calcolatore era Harvard Mark 1 e fu realizzato nei laboratori dell’IBM, in collaborazione con l’università di Harvard. Con questo calcolatore è nato anche il termine “bug”, che viene utilizzato dagli specialisti per definire un errore. Il calcolatore Bessie che eseguiva operazioni matematiche come la somma di numeri a 23 cifre in tre decimi di secondo e una moltiplicazione in 6 secondi, venne impiegato dalla marina militare statunitense per studi sulla balistica e progettazione di navi. Inoltre venne anche usato dalla commissione dell’energia per ricerche sulla disintegrazione dell’atomo. Un altro calcolatore realizzato nel 1946, destinato solamente ad un uso militare, chiamato Eniac, costò la bellezza di mezzo milione di dollari di allora. Questo calcolatore serviva per il calcolo delle traiettorie dei proiettili. Esso riusciva a realizzare una tabella balistica in 30 minuti contro le 20 ore impiegate da un uomo. Questo calcolatore fu tenuto in funzione solo per nove anni, dopo di che non fu più utilizzato poiché aveva un alto costo di manutenzione. Esso va ricordato anche per un altro fatto: durante la sua creazione lo scienziato John Tykey creò il termine “bit”, contrazione delle parole “Binary DigiT”. Esso rappresenta la più piccola unità di informazione, che specifica due stati: 1 (acceso) e 0 (spento), che codificano i dati all’interno di un computer. Una striscia di otto bit forma un “byte”, che oggi viene utilizzato per rappresentare un carattere o un singolo numero. Nel 1947 fu inventato il transistor, il quale rivoluzionò completamente il mondo del computer. Questi dispositivi erano molto più piccoli (qualche millimetro) rispetto alle valvole (diversi centimetri), erano molto più resistenti e consumavano molta meno elettricità. Fino al 1950 i computer non avevano memoria e quindi le informazioni non potevano essere salvate. Tra il 1950 e il 2 La storia 1955 i calcolatori vennero dotati di memorie, ma la capacità di memorizzazione era solo di un bit alla volta. Queste memorie “interne” erano molto ingombranti e siccome i computer avevano già grandi dimensioni, si decise di abbandonarle, puntando su memorie ausiliarie o esterne, come nastri e dischi magnetici. Negli anni successivi si costruirono calcolatori sempre più piccoli, arrivando nel 1957 alle dimensioni di un frigorifero. Questo calcolatore era accessibile solamente all’esercito. Ma l’era dei computer domestici era lontana, poiché il costo era elevato e le dimensioni non certo adatte per una casa. Ma la vera rivoluzione avvenne nel 1958, grazie all’ingegnere americano Kilby che inventò i circuiti integrati. 1.1.3 I computer moderni Gli integrati rivoluzionarono il mondo del computer: con questa invenzione i calcolatori potevano avere delle dimensioni molto ridotte rispetto ai loro predecessori. Questa invenzione nel campo informatico prese il nome di chip. I computer ebbero una diffusione maggiore: essi non solo potevano essere acquistati dai militari, ma anche da industrie. Erano molto veloci, grazie a questi circuiti miniaturizzati, ma il loro costo era molto elevato e ancora accessibile a pochi. Questi computer erano prodotti soprattutto in America, ma nel 1965 anche l’Italia scese in campo, grazie all’ Olivetti, che costruì un calcolatore chiamato “Programma 101”, che ebbe grande successo, soprattutto oltreoceano. Questo calcolatore fu il primo ad avere memorizzato al suo interno un programma ed un supporto magnetico, dal quale avrà origine il “floppy disk”. Nel 1968 l’industria americana prese il sopravvento, infatti, in questo anno nacque l’Intel, che fu ed è tuttora, l’azienda leader nella costruzione di processori e chip di memoria. Nel 1970 costruì la prima RAM adottata da tutti i calcolatori al posto delle vecchie memorie a nuclei magnetici. Nel 1971 venne costruita la prima cpu che da allora, costituisce il cuore del calcolatore. Essa era in grado di tenere memorizzati i dati, fino a che non veniva a mancare la corrente. Per realizzare il computer come lo conosciamo oggi, mancava ancora un componente, infatti, il vero problema era memorizzare i dati all’interno del calcolatore, senza perderli una volta tolta la corrente. Questo problema venne superato grazie al primo “hard disk”, costruito dall’IBM, che 3 La storia permetteva di immagazzinare i dati anche in mancanza di corrente. La data più importante nella storia dei computer e dell’informatica fu il 1975, anno in cui, grazie a due studenti universitari, William “Bill” Gates e Paul Allen, nacque la Microsoft, prima azienda specializzata nell’elaborazione di linguaggi per computer. A questa azienda si opposero altri due giovani, Stephen Jobs e Stephen Wozniak, che nel salotto della loro casa, costruirono Apple I e diedero vita nel 1976 alla Apple azienda, tuttora in competizione con Microsoft. Nel 1977, Jobs e Wozniak, costruirono Apple II, che era solo dotato di una tastiera, di un alimentatore e di prese per il collegamento con le periferiche, già presenti sul mercato. Nel 1981 l’IBM, che allora era la maggiore produttrice di computer, investì sulla produzione dei “Personal Computer” grazie anche all’aiuto della Microsoft, la quale ideò e fornì il primo sistema operativo : l’ MS-DOS, che è tuttora utilizzato. In questi quarant’ anni il computer si è evoluto rapidamente, passando dall’essere lento e ingombrante ad avere dimensioni che siamo abituati a vedere tutti i giorni e a velocità che sono in costante aumento. Nel futuro i computer saranno sempre più piccoli e più veloci e faranno sempre più parte della nostra vita quotidiana. 1.2 I computer nella Seconda Guerra Mondiale Dopo l’ascesa al potere di Hitler, verificatasi in Germania a partire del 1933, e la costruzione del suo regime dittatoriale, il nazismo portò prima l’Europa e poi il mondo intero in un nuovo e spaventoso conflitto mondiale. La guerra iniziò il 1° settembre del 1939 con l’attacco della Germania alla Polonia che venne conquistata i poche settimane . Il 3 settembre la Francia e l’Inghilterra dichiararono guerra alla Germania. Mentre sul fronte francese non si verificarono inizialmente combattimenti, la Russia attaccò e conquistò la Finlandia, la Germania per stringere l’Inghilterra in una morsa attaccò e conquistò la Danimarca e la Norvegia. Sulla linea di confine tra Francia e Germania i francesi costruirono una linea difensiva (Linea Maginot), con trincee e cannoni, che serviva come difesa in caso di attacco, ma la Germania attaccò, passando per il Belgio, il 10 maggio del 1940, e dopo poco più di un mese i tedeschi conquistarono gran parte della Francia. Il 10 giugno del 1940 entrò in guerra a fianco dei nazisti l’Italia. Con questo intervento militare si verificherà la conquista italiana di territori in Africa (Somalia, Sudan) e della Grecia, mentre perdette l’Etiopia; inoltre subì gravi sconfitte navali a Punta Stilo e a Capo Matapan nel 1941, derivanti dalla 4 La storia superiorità della marina inglese, ottenuta grazie al radar. La battaglia di Capo Matapan fu persa a causa dell’intercettazione inglesi delle trasmissione crittate tra Italiani e tedeschi, grazie al primo computer COLOSSUS. Per l’Asse (Germania, Italia, Giappone) fino alla fine del 1941 la guerra portò importanti vittorie, che rafforzarono il loro potere e permisero la conquista di nuovi territori e, come conseguenza, l’allargamento dei propri confini. I tedeschi evitarono che i paesi alleati ricevessero gli aiuti dagli Stati Uniti; questi ultimi si dichiararono neutrali nel 1939 insieme al Giappone. Ma gli USA, in realtà, fornivano aiuti ai paesi che non avevano al potere dei regimi totalitari filo fascisti. I tedeschi cercarono di evitare che gli aiuti statunitensi raggiungessero l’Europa, usando i sottomarini (U-boat), che aspettavano le navi al largo dell’Atlantico e le affondavano. I sottomarini tedeschi, riuscivano a comunicare tra di loro e con gli alti comandi dell’esercito tramite l’invio di messaggi. Questi ultimi per non essere intercettati e capiti dagli Alleati erano crittati con la macchina ENIGMA. Per la prima parte della guerra le potenze dell’Asse riuscirono a comunicare con sicurezza senza che gli Alleati riuscissero a intercettare e a comprendere i messaggi mandati. Con l’attacco della Germania alla Russia, che iniziò nel giugno del 1941, cominciò il declino delle potenze dell’asse. Dopo aver riportato vittorie schiaccianti in pochi mesi, l’immenso esercito arrivò alle porte di Mosca e Stalingrado. Ma con l’inizio dell’inverno la macchina bellica si inceppò, fermò la sua marcia verso la conquista dell’intero territorio e cominciò una guerra di posizione,. L’esercito russo si riorganizzò e sferrò la controffensiva, mentre quello tedesco arretrò per circa 200 chilometri. Come conseguenza Hitler ordinò la resistenza a oltranza e nel giugno del 1942 dispose di radere al suolo Stalingrado, ma l’esercito non riuscì nell’impresa; questo fu l’inizio della fine per le potenze dell’Asse. Inoltre gli Alleati riuscirono a rompere il codice crittato che permetteva ai tedeschi di comunicare segretamente, così da permettere agli alleati di conoscere in anticipo le mosse del nemico. Questa rottura del codice fu effettuata da un gruppo di persone aiutate da un computer chiamato COLOSSUS. Questo gruppo fu incaricato da Churchill sotto la supervisione di Alan Turing. Anche sul fronte del Pacifico cominciarono a verificarsi le prime sconfitte del Giappone da parte degli americani. Come già stato detto, sia i giapponesi che gli americani, si dichiararono neutrali nel 1939, ma dopo l’attacco nipponico a Pearl Harbor, avvenuto il 7 dicembre 1941, gli USA decideranno di entrare in guerra. Nel Pacifico la forza americana era gravemente indebolita, poiché l’attacco a Pearl Harbor riportò gravi perdite di uomini e mezzi, rendendo le forze giapponesi superiori. Per avere il predominio nel Pacifico e l’annientamento 5 La storia della flotta americana, i giapponesi dovettero organizzare un nuovo attacco. L’intelligence navale degli Stati Uniti aveva subito un grave smacco nell’attacco alle Hawaii, ma si misero al lavoro per cercare d’intercettare e decrittare il messaggi nipponici; fu formato così un gruppo composto per la maggior parte d’analisti. In 6 mesi di lavoro furono in grado di decrittare il codice. Da questo momento, gli americani poterono sapere in anticipo le mosse del nemico, ma non dove sarebbe avvenuto l'attacco. Il luogo scelto dai giapponesi furono le isole Midway, che fu scoperto casualmente in un messaggio cifrato. Il 4 giugno del 1942 iniziarono le prime schermaglie: sia i giapponesi che gli americani persero un numero uguale di navi, ma il contrattacco portato dagli americani fu schiacciante e vennero distrutte la maggior parte delle portaerei giapponesi, mentre le forze aeree vennero decimate. Dopo la schiacciante vittoria, le forze nel Pacifico tornarono in parità. Da questo momento la macchina industriale americana cominciò a produrre navi e mezzi per combattere il Giappone. A patire dal 1943 i giapponesi persero la maggior parte dei territori, gli americani si avvicinarono pericolosamente alle coste del giappone. Nel 1944 cominciarono i bombardamenti su Tokyo. Ma la vera forza nipponico era basata sull’esercito di terra. Allora Truman decise di sganciare due bombe atomiche sul Giappone per mettere fine al conflitto. Ne 1943 gli alleati sbarcarono in Italia e Mussolini venne arrestato e imprigionato. Si istituì il governo di Badoglio. Il 5 maggio del 1944 gli alleati conquistarono Roma. Gli alleati e l’Unione Sovietica decisero di aprire un nuovo fronte di guerra: il luogo scelto fu la Normandia. La sbarco riuscì con successo e sia l’esercito alleato, sia i sovietici marciarono inarrestabili verso la Germania e Berlino. Il 7 maggio i tedeschi firmano la capitolazione. 6 Il presente Capitolo 2 Il presente 2.1 2.2 2.3 2.4 2.5 2.6 2.1 Le comunicazioni in Internet Il protocollo IP 2.2.1 Il preambolo IP 2.2.2 Struttura dell’indirizzo IP Il protocollo TCP 2.3.1 Il preambolo TCP 2.3.2 Gestione delle connessioni TCP Le porte 2.4.1 Esempi di porte I socket Esempi 2.6.1 Tracert 2.6.2 Netstat Le comunicazioni in Internet La maggior parte delle applicazioni che comunicano via rete (Internet o LAN) utilizzano gli stessi principi. Vi è una stazione cliente (client) che richiede un servizio ad una stazione servente (server). Quest’ ultima rimane in ascolto fino a che il cliente non richiede un servizio. A questo punto la stazione servente può decidere o meno di esaudire la richiesta. In caso affermativo le due stazioni cominciano a scambiarsi informazioni, il canale di comunicazione è bidirezionale, ovvero entrambe le stazioni possono inviare informazioni. Quando le due stazioni hanno terminato di comunicare la comunicazione verrà abbattuta. Quella appena fatta è una descrizione semplificata del protocollo TCP/IP (Transfer Control Protocol/Internet Protocol), il principale protocollo di comunicazione usato in Internet. La sua principale funzione è quella di fornire un flusso affidabile di dati tra due stazioni e permettere l’identificazione di esse tramite un indirizzo. Il TCP/IP nasce durante gli anni ’70, congiuntamente con la versione 3.4 di UNIX. Il progetto fu elaborato dall’università californiana di Berkeley. Il suo sviluppo è stato reso necessario dalla nascita delle prime reti a commutazione di pacchetto, avvenuta durante gli anni ’60. La prima di esse fu ARPANet, nata da uno studio finanziato dall’agenzia americana DARPA (Defense Advanced Research Project Agency) e svolto dall’ARPA (Advanced Research Project Agency). 7 Il presente Durante gli anni ’80 con la fusione tra ARPANet e NSFNET (National Science Foundation NETwork) nasce la rete mondiale Internet, la quale verrà aperta al pubblico da 1992. 2.2 Il protocollo IP Il protocollo IP (Internet Protocol) appartiene al livello 3° (livello di rete) del sistema a strati OSI (Open System Interconnection, standard internazionale per l’organizzazione di reti locali) e consente l’implementazione di una rete a commutazione di pacchetto che può utilizzare qualunque DLC (Data Link Control). Esso spedisce le informazioni divise in pacchetti, e ognuno di essi percorre diversi percorsi attraverso la rete. Quindi non si garantisce che il primo pacchetto inviato sia anche il primo arrivato al ricevitore. Per compensare questo difetto si utilizza il protocollo TCP che appartiene al 4° livello OSI (livello di trasporto) che garantisce l’ordine dei pacchetti arrivati al terminale attraverso l’IP e assicura l’affidabilità del protocollo. Ogni interfaccia su una rete TCP/IP riceve un identificatore univoco chiamato indirizzo IP. Ad ogni periferica della rete verrà assegnato un indirizzo IP. Ogni computer possedente un indirizzo IP e capace di comunicare via TCP/IP viene chiamato host. Esso possiede almeno una scheda di rete o un modem. Di conseguenza, se un host possiede più schede di rete, possiederà anche più indirizzi IP. Gli indirizzi IP sono formati da due parti : un ID di rete e un ID dell'host. L'ID dell'host identifica un singolo host che si trova su un segmento di rete. L'host può comunicare direttamente solo con altri host che si trovano sullo stesso segmento di rete, infatti, i segmenti, sono divisioni logiche di una rete in univoci ID numerici chiamati subnet. L'host deve usare, per comunicare con gli host di una diversa subnet, un router che comunica con entrambe le subnet. Il successo dell’IP è dovuto alla flessibilità, la quale permette di connettere reti basate su tecnologie eterogenee. 2.2.1 Versione Il preambolo IP 8 16 IHL Tipo di servizio Identificazione Tempo di vita 24 32 Lunghezza del pacchetto DF MF Offset di frammentazione del pacchetto Checksum Protocollo Indirizzo sorgente Indirizzo destinazione Options (lunghezza variabile) 8 Il presente Version Descrive la versione del protocollo utilizzato dal datagram IPv4. La lunghezza è di 4 bit. IHL Siccome la lunghezza dell'header non è constante in questo campo è contenuta la lunghezza dell'header in parole di 32 bit il valore minimo è 5 (nessuna opzione header = 20 byte) il massimo è 15 byte (header uguale a 60 byte). La lunghezza del campo è di 4 bit. Tipo di servizio Consente agli host di comunicare alla rete il tipo di servizio desiderato in base ai parametri: ritardo, capacità di trasmissione affidabilità. La lunghezza è di 8 bit. Lunghezza del pacchetto Riguarda l'intero pacchetto la massima lunghezza è di 65.536 byte pari a 16 bit. Identificazione È necessario per permettere all'host di destinazione di determinare a quale datagram appartiene un frammento appena arrivato.Tutti i frammenti di un datagram contengono lo stesso numero di identificazione. La lunghezza è di 16 bit. Offset di frammentazione del pacchetto Indica in quale posizione del datagram corrente si trova questo frammento, tutti i frammenti tranne l'ultimo devono essere multipli di 8 byte, il campo è di 13 bit , avrò quindi un massimo di 8192 frammenti (8192 x 8 = 65536 byte al massimo(IP packet). Tempo di vita È un contatore utilizzato per limitare il tempo di vita dei pacchetti sulla rete. Quando il contatore raggiunge lo 0 il pacchetto viene scartato e viene inviato alla destinazione un messaggio di avvertimento. Lunghezza pari a 8 bit. Protocollo Campo che indica il protocollo che viene usato al livello trasporto (TCP, UDP e altri) la numerazione dei protocolli è globale ed è descritta nel RFC 1700. La lunghezza è di 16 bit. Indirizzo sorgente e destinazione Sono rispettivamente gli indirizzi del mittente e del destinatario del pacchetto composti da 32 bit ognuno. Checksum Verifica solamente il preambolo IP. E’ utilizzato per verificare gli errori generati dai router. L'algoritmo consiste nel sommare tutte le parole di 16 bit che arrivano usando 9 Il presente l'aritmetica di complemento a 1 e quindi prendendo il complemento a 1 del risultato. Il risultato finale deve essere 0. Da notare che l'algoritmo deve essere cambiato ad ogni salto perchè c'è almeno un campo che cambia il TTL (time to live). La seconda struttura illustra le opzioni che si possono aggiungere a un pacchetto IP. Quelle più usate sono descritte di seguito. Security Descrive il grado di segretezza delle informazioni, in teoria un router militare dovrebbe utilizzare questo campo per richiedere di non attraversare paesi considerati a rischio. Strict source routing Fornisce il percorso completo da seguire. Loose source routing Richiede che il pacchetto attraversi una lista di router specificati nell'ordine specificato ma e' possibile che passi attraverso altri router lungo il percorso. Record route Forza i router lungo il cammino ad aggiungere il loro indirizzo IP al campo opzione. Timestamp È simile all'opzione record route a parte il fatto che oltre a registare l'indirizzo a 32 bit ogni router regista un timestamp di 32 bit (motivi diagnostici). 2.2.2 Struttura dell’indirizzo IP L’indirizzo IP è composto da 4 byte (1 byte = 0 Æ 255 decimale o 0 Æ ff esadecimale) che identificano in modo univoco un computer, quindi a ogni terminale corrisponde un solo indirizzo IP. Esempio 123.1.82.109 In una rete locale (LAN, Local Area Network) l’indirizzo IP è statico. Il primo indirizzo è 192.168.0.1, gli altri indirizzi crescono in modo sequenziale. Diversamente in Internet (WAN, World Area Network) l’indirizzo IP è dinamico, quindi ad ogni nuova connessione si avrà un nuovo IP. Questo avviene per diversi motivi: • primo, il totale degli indirizzi che si possono creare con 32bit è 4.294.967.296, quindi non è possibile applicare ad ogni utente un IP fisso poiché gli indirizzi disponibili non sarebbero sufficienti; • secondo, un IP statico faciliterebbe il compito ai pirati informatici 10 Il presente Poiché esistono “solo” 4,3 miliardi di indirizzi IP gli sviluppatori hanno deciso di suddividerli in 5 diverse classi, dalla A alla E. Ognuna di esse ha un funzionamento diverso dalle altre. Per identificarle il 1° byte dell’IP ha dei valori diversi : Classe Configurazione binaria del 1° byte Indirizzo Struttura Classe A Classe B Classe C Classe D Classe E 0xxxxxxx 10xxxxxx 110xxxxx 1110xxxx 11110xxx 0-127.x.x.x 127-191.0-255.x.x 192-223.0-255.0-255.x 224-239.x.x.x 240-255.x.x.x Net_Add 1°byte Net_Add 1°, 2° byte Net_Add 1°, 2°, 3° byte Flat Usi futuri Naturalmente le varie classi hanno funzionalità diverse. Le classi A, B, C hanno scopi commerciali ossia sono usate da società o da privati per connettersi a Internet, mentre la classe D è usata per impieghi speciali mentre la classe E è riservata per usi futuri. Le 3 classi per usi quotidiani hanno delle differenze sostanziali, poiché hanno tutte un diverso numero di host e un diverso numero di reti : Classe Numero di reti Numero di host Classe A Classe B Classe C 126 16.384 2.097.152 16.777.214 65.534 254 Si può notare che la classe A ha un elevato numero di host, ma un basso numero di reti. Al contrario la classe C può avere pochi host, ma un elevato numero di reti. Classe Indirizzo IP ID di rete ID dell'host Classe A Classe B Classe C 10.1.1.10 172.16.1.10 192.168.1.10 10 172.16.00 192.168.1 1.01.10 1.10 10 La scelta della classe dipende dalla rete che si vuole effettuare. 2.3 Il protocollo TCP Il protocollo TCP fa parte del 4° livello dello standard OSI. Il suo compito è quello di rendere affidabile il protocollo IP, fornendo una verifica sulla consegna dei dati. TCP garantisce una consegna corretta per mezzo della ricevuta positiva con ritrasmissione (PAR, Positive Acknowledgment with Retransmission) e assembla nel corretto ordine i datagrammi IP in cui è stato frazionato il messaggio, all’arrivo di esso al ricevente. 11 Il presente Il TCP è diviso in 4 livelli fondamentali : 7 4 3 1–2 Applicazione Trasporto (TCP) Internet (IP) Host - rete Livello di Trasporto In questo particolare caso il livello di trasporto è solamente il TCP, ma in generale potrebbe essere anche l’UDP. Il TCP è un protocollo orientato alla connessione affidabile, ossia assegna ai livelli superiori l’affidabilità che invece manca al livello inferiore, ovvero all’IP. Il protocollo TCP ha il compito di dividere il messaggio entrante e passarlo al livello IP. Il datagramma di lunghezza massima è di 65496 (65536 – 20 per il preambolo TCP – 20 per il preambolo dell’IP). Livello Internet Il livello Internet è il fulcro, insieme al TCP, dell’architettura. L’indirizzo permette di inserire un pacchetto in una qualsiasi rete( può essere una LAN, una MAN o Internet). I pacchetti inviati possono arrivare in ordine diverso rispetto a come sono partiti. Lo scopo del livello Internet è consegnare i pacchetti IP al luogo di destinazione. 2.3.1 Preambolo TCP 8 Source port TCP H.L. URG ACK PSH 16 Sequence number Acknowledgement Number RST SYN FIN Checksum 24 Destination port 32 Window size Urgent pointer Options (lunghezza variabile) Data (lunghezza variabile) Sorgente e destinazione Rispettivamente porta sorgente e porta destinazione identificano gli estremi locali di una connessione, ogni host deve decidere come allocare le proprie porte successive alla 256. Il punto di accesso del livello trasporto sarà quindi identificato dall'indirizzo espresso nel seguente formato ADDRESS IP : PORTA La lunghezza di ambedue i campi è di 16 bit. Numero di sequenza Un numero di sequenza viene assegnato ad ogni pacchetto durante la connessione tra 2 host, il campo è composto da 32 bit. 12 Il presente Numero Ack È uguale a 1 per indicare che il numero di ack è valido, se ack = 0 il segmento non contiene ack e il campo numero di ack viene ignorato. PSH Indica dati di tipo push, in questo modo si richiede al mittente di consegnare i dati dell'applicazione al momento dell'arrivo, evitando che siano salvati in un buffer di attesa. Lunghezza 1 bit. RST Viene utilizzato per reinizializzare una connessione che è diventata instabile a causa del guasto di un host o per qualche altro motivo. Inoltre viene anche utilizzato per rifiutare l'apertura di una connessione. Lunghezza 1 bit. SYN Viene utilizzato per creare una connessione. La richiesta di connessione è caratterizzata da SYN=1 ACK=0. La risposta sara' SYN=1 ACK=1. Lunghezza 1 bit. FIN Viene utilizzato per chiudere una connessione. Specifica che il mittente non ha altri dati da spedire, tuttavia dopo aver chiuso una connessione, un processo può continuare a ricevere dati indefinitamente. Lunghezza 1 bit. Window Il controllo di flusso TCP è gestito utilizzando un protocollo sliding window a dimensione variabile. Il campo window specifica quanti byte possono essere spediti a partire dal byte confermato. Lunghezza 16 bit. Checksum Per garantire l'affidabilità è presente anche un campo checksum, che verifica il preambolo i dati e lo pseudopreambolo. Quando viene eseguito il calcolo, il campo checksum viene posto uguale a 0, e il campo dati viene completato con un 0 se la lunghezza è un numero dispari. L'algoritmo di checksum somma tutte le parole di 16 bit in complemento a 1 e quindi prende il complemento a 1 della somma. Come conseguenza quando il ricevente esegue il calcolo sull'intero segmento (compreso il checksum) il risultato deve essere 0. 2.3.2 Gestione delle connessioni TCP In TCP, per creare una connessione viene usato il protocollo three-way handshake che consiste, come indicato dal nome, in tre passi principali : 13 Il presente 1. 2. 3. il client spedisce un pacchetto TCP avente il flag SYN impostato, il flag ACK non impostato e con un valore X del sequence number; il server risponde con entrambi i flag SYN e ACK impostati, con il sequence number con un valore Y e acknowledgment number con valore X+1; il client risponde con il flag ACK impostato, con il Sequence number con valore X+1 e acknowldgement number con valore Y+1. SYN=1 ACK=0 SEQ-NUM=X CLIENT --------------------------------------> SERVER SYN=1 ACK=1 SEQ-NUM=Y ACK-NUM=X+1 CLIENT <-------------------------------------- SERVER ACK=1 SEQ-NUM=X+1 ACK-NUM=Y+1 CLIENT --------------------------------------> SERVER Dopo che la connessione è stata inizializzata si può procedere al trasferimento dei dati. In seguito verrà indicato con pacchetto SYN il primo dei tre, con SYN/ACK il secondo e con ACK il terzo. Gestione Sequence number e Acknowledgement number in una connessione Il TCP realizza una connessione affidabile, è in grado cioè, di recuperare pacchetti persi, duplicati e fuori ordine. Tutto questo è possibile grazie all'assegnamento di un numero di sequenza (sequence number) ad ogni byte trasmesso e alla richiesta di conferma dei dati ricevuti dal destinatario (acknowledgement number). All'interno di un pacchetto il sequence number indica il numero di sequenza del primo byte di dati contenuto, mentre l'Acknowledgement number indica il numero del prossimo byte atteso e conferma la ricezione fino al byte indicato meno 1. Prendiamo in esame il seguente esempio per capire meglio. SEQ-NUM=1000 ACK-NUM=5000 DATI=100 byte 1) A -----------------------------------------> B SEQ-NUM=5000 ACK-NUM=1100 DATI=250 byte 2) A <----------------------------------------- B SEQ-NUM=1100 ACK-NUM=5250 DATI=150 byte 3) A -----------------------------------------> B SEQ-NUM=5250 ACK-NUM=1250 DATI=0 byte 4) A <----------------------------------------- B 14 Il presente Nel caso 1) A spedisce a B 100 byte il cui primo byte ha come numero di sequenza 1000. Inoltre conferma la ricezione dei byte ricevuti in precedenza fino al 4999 ed indica che si aspetta che il prossimo byte trasmesso sia quello con numero di sequenza 5000. Nel caso 2) B spedisce ad A 250 byte il cui primo byte ha come numero di sequenza 5000. Inoltre conferma la ricezione dei byte ricevuti in precedenza fino al 1099 ed indica che si aspetta che il prossimo byte trasmesso sia quello con numero di sequenza 1100. Nel caso 3) A spedisce a B 150 byte il cui primo byte ha come numero di sequenza 1100. Inoltre conferma la ricezione dei byte ricevuti in precedenza fino al 5249 ed indica che si aspetta che il prossimo byte trasmesso sia quello con numero di sequenza 5250. Nel caso 4) B non ha dati da spedire, si limita solo a confermare i dati ricevuti. Questo pacchetto non verrà confermato in quanto non contiene dati. Chiusura di una connessione Sebbene le connessioni TCP siano full duplex, per comprendere la chiusura di una connessione è meglio pensarle come una coppia di connessioni simplex. Ogni connessione simplex viene chiusa indipendentemente dall'altra. Per chiudere una connessione entrambe le parti possono spedire un pacchetto TCP contenente il flag FIN impostato a uno per indicare che non ci sono più dati da spedire. Quando viene confermata la ricezione del flag FIN quella connessione viene spenta. Quando entrambe le direzioni vengono chiuse la connessione viene rilasciata. Quindi normalmente occorrono 4 passaggi per chiudere una connessione. 2.4 Le porte Quando un host si collega ad un server, i due computer trasmettono continuamente i propri dati attraverso delle porte. Ogni porta ha un numero associato e compie un servizio specifico. Il servizio è compiuto da un programma, chiamato demone che esegue i comandi necessari per compiere il servizio richiesto. Le porte sono suddivise in 2 categorie : • Da 0 a 255 • Da 255 a 65535 Le prime sono dette well – known port poiché i loro servizi sono noti e precisati, mentre le altre porte non hanno tutte un servizio preciso e in alcuni casi sono addirittura dei doppioni delle porte conosciute. 15 Il presente Ad esempio la porta 80 svolge il servizio http, ma anche la porta 8080 svolge la stessa occupazione. Quando ci si collega ad una rete tra cui anche Internet, come detto in precedenza, due terminali si scambiano informazioni attraverso le porte, ma non tutte vengono usate nello stesso collegamento. Esse si possono trovare in 4 stati: • Ascolto • Comunicazione • Chiusura • Attesa Quando una porta è chiusa, per un hacker è impossibile tentare di entrarci, quindi ogni tentativo di intrusione fallirà. 2.4.1 E s e m p i di porte Legenda Porta C/S Poss. att. Note : indica la porta utilizzata : se il servizio descritto è dalla parte del server (S), oppure dal lato client (C). : indica le possibilità di attacco alla porta. : varie ed eventuali, come ad esempio possibilità di attacco ai servizi presenti su quella porta, presenza di back door, ecc… PORTA C/S POSS. ATT. NOTE ICMP (0) // Sezione relativa alla manutenzione del protocollo TCP/IP FTP (21) S Ricezione di pacchetti anomali per mandare in crash lo stack TCP/IP // Telnet (23) S // // SMTP (25) S // DNS (53) S Bug di Sendmail (UNIX) // TFTP (69) S // // Finger (79) S Disabilitare il Finger o montare una versione aggiornata WEB (80) S Può essere usato per un “denial of service” attack CGI/BIN attacks POP3 (110) S TCP (119) S Possibile lettura file in posta // NetBios (137) Proxy (1080) S // C/S // // // Utilizzare sempre la versione aggiornata del server WEB // // E’ necessario disattivare NetBios. Oppure installare WinNuke95 Chi cerca una connessione sulla 1080 vuole mandare in giro pacchetti a nome vostro, alcuni ISP mettono a disposizione un server proxy per velocizzare le 16 Il presente 5001 C/S // IRC (6667) S // 12345 / 12346 C/S // UDP (31337) C/S // 2.5 comunicazioni. L’effetto collaterale è che tutti i pacchetti in uscita hanno l’indirizzo IP del proxy server. Porta destinazione degli attacchi di Socket de Trois // Porte del server NetBus, si possono ricevere scan alla ricerca di un dato programma E’ la porta standard del server di Back Orifice I socket I socket sono i principali oggetti utilizzati dalle applicazioni per eseguire la maggior parte delle comunicazioni di rete. Sono stati inizialmente utilizzati per UNIX alla Università di California di Berkeley e sono stati progettati in modo che le comunicazioni di rete fra applicazioni potessero avvenire nello stesso modo in cui quelle stesse applicazioni leggevano e scrivevano i file. Da allora vi è stato un progresso anche per quanto riguarda i socket ma il funzionamento di base è rimasto immutato. La creazione di una connessione via socket richiede due informazioni principali : • bisogna sapere il nome del server; • bisogna conoscere la porta su cui il server è in ascolto. Esempio 85.125.255.12 : 80 Indirizzo IP Porta È possibile riassumere i socket come l’unione dell’indirizzo IP più la porta. È importante dire che solo un’applicazione può essere in ascolto in una determinata porta e su un determinato computer. Anche se su un computer vi possono essere più applicazioni che ascoltano più richieste di connessione su un singolo computer, ognuna di esse deve essere in ascolto su una porta differente. 2.6 Esempi Il sistema operativo MS – DOS mette a disposizione due programmi, Netstat e Tracert. Ambedue i programmi servono per controllare parametri relativi alle connessioni, quali le porte e i pacchetti TCP/IP. 17 Il presente 2.6.1 Netsat La funzione Netstat permette di vedere tutte le porte aperte del proprio host durante una connessione TCP/IP. Esso, per ogni porta locale, specifica a quale indirizzo remoto è connessa e quale porta il remoto sta utilizzando, inoltre specifica per ogni connessione il protocollo (TCP, UDP) e lo stato della porta. Sintassi Protocollo 2.6.2 netstat –sn Indirizzo host Indirizzo server Stato socket Tracert La funzione Tracert permette, specificando un sito, di tenere traccia del percorso che il pacchetto compie per arrivare dal provider al server in cui è ospitato il sito. Sintassi Numero passaggi tracert (nome sito) Tempo passato nel nodo Indirizzo del sito 18 La crittografia Capitolo 3 La crittografia 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.1 La storia 3.1.1 Crittografia antica 3.1.2 Crittografia fino al XVIII secolo 3.1.3 Crittografia moderna Principali cifrari 3.2.1 Cifrari a sostituzione 3.2.2 Cifrario affine 3.2.3 Cifrario Playfair 3.2.4 Stream cypher 3.2.5 Cifrario di Vernam La sicurezza perfetta Gli algoritmi 3.4.1 Il DES 3.4.2 L’ RSA Macchine cifranti 3.5.1 Enigma 3.5.2 La bomba di Turing Crittoanalisi 3.6.1 Crittoanalisi statistica 3.6.2 Crittoanalisi lineare 3.6.3 Crittoanalisi differenziale 3.6.4 Crittoanalisi su polialfabetici 3.6.5 Brute force Curiosità e considerazioni La storia Per migliaia di anni re, regine e generali hanno avuto il bisogno di comunicazioni efficienti per governare i loro paesi e comandare i loro eserciti. Nel contempo, essi compresero quali conseguenze avrebbe avuto la caduta dei loro messaggi in mano ostili : informazioni preziose sarebbero state a disposizione delle nazioni rivali e degli eserciti nemici. Fu il pericolo dell' intercettazione da parte degli avversari a promuovere lo sviluppo di codici, tecniche di alterazione del messaggio destinate a renderlo comprensibile solo alle persone autorizzate. Una delle prime tecniche di comunicazione segrete, basata sull'occultamento del messaggio, si chiama steganografia, dalle parole greche steganós, che significa coperto, e gráphein, che significa scrivere. Negli anni sono state impiegate in tutto il mondo innumerevoli forme di steganografia. Uno dei metodi più bizzarri per trasmettere le informazioni segrete era utilizzato nell'antica Persia e viene 19 La crittografia raccontato da Erodoto. Esso consisteva nel rapare i capelli di uno schiavo e nel scrivergli il messaggio sulla testa. Lo schiavo si recava poi dal destinatario del messaggio dopo che gli erano ricresciuti i capelli e il messaggio era recuperato rapandoglieli nuovamente. Nell'antica Cina si dipingeva il messaggio su striscioline di seta finissima, che venivano appallottolate e coperte di cera. Le palline erano quindi inghiottite dal messaggero. Nel XVI secolo lo scienziato italiano Giambattista Della Porta spiegò come comunicare tramite un uovo sodo, preparando un inchiostro con 30 grammi di allume in mezzo litro d'aceto, e usandolo per scrivere sul guscio. La soluzione penetra nel guscio, che è poroso, senza lasciar traccia, e tinge l'albume solidificato; quest'ultimo potrà essere letto sbucciando l'uovo. La longevità della steganografia dimostra che essa garantisce una certa sicurezza, ma il suo punto debole è evidente : se il latore del messaggio è attentamente perquisito, è probabile che il messaggio sia scoperto; in tal caso, il nemico può farne l'uso che crede. In altre parole, la segretezza è perduta nel momento stesso dell'intercettazione. In tal caso è inevitabile che molti messaggi siano trovati. Perciò in parallelo con lo sviluppo della steganografia si assisté all'evoluzione della crittografia, dal greco kryptós, che significa nascosto. La crittografia non mira a nascondere il messaggio in sé, ma il suo significato. Per rendere incomprensibile un testo, lo si altera per mezzo di un procedimento concordato a suo tempo dal mittente e dal destinatario. Questi può quindi invertire il procedimento, e ricavare il messaggio originale. Il vantaggio della crittografia è che anche se il nemico intercetta il messaggio, esso risulta incomprensibile e quindi inutilizzabile. Infatti il nemico, non conoscendo il procedimento di alterazione, dovrebbe trovare difficile, se non impossibile, ricostruire il significato. Non tutte le società antiche svilupparono forme di crittografia. La Cina, per esempio, l'unica civiltà antica ad usare una scrittura ideografica, non ne ha mai viste. Le ragioni, a detta degli storici, sono legate alla natura prevalentemente orale delle comunicazioni. In India, invece, forme di crittografia furono concretamente praticate. In diversi testi sacri sono presenti riferimenti a forme di scritture segrete. Nell'Artha-Sastra, un testo classico sugli affari di stato, si sottolinea l'importanza delle scritture segrete nei servizi di spionaggio. Esempi di scritture segrete sono presenti anche nel Latila-Vistara, un libro che esalta le virtù di Budda. Anche nelle scritture cuneiforme sviluppate in Mesopotamia sono stati ritrovati esempi di crittografia. Sia presso gli Assiri che i Babilonesi, le due grosse civiltà sorte sulle sponde del Tigri, è stata rinvenuta l'usanza di sostituire le parti terminali delle parole con elementi corti e stereotipati detti colofoni. In Iraq, nel periodo finale delle scritture cuneiformi, è presente per la prima volta la sostituzione di nomi con numeri. 20 La crittografia Anche se la steganografia e la crittografia sono discipline indipendenti, possono essere impiegate per alterare e occultare il medesimo testo, garantendo un livello di sicurezza molto più alto. Per esempio, il « microdot », cioè la riduzione di uno scritto alle dimensioni di un punto, è una forma di steganografia che ebbe largo impiego durante la seconda guerra mondiale. Tramite un procedimento fotografico, gli agenti tedeschi in America latina trasformavano una pagina scritta, precedentemente crittografata, in una macchia con un diametro inferiore al millimetro, che poteva essere nascosta nel puntino di una « i » in una comunicazione banale. Il primo microdot fu scoperto dall' FBI nel 1941 grazie a una soffiata. 3.1.1 Crittografia antica Le più antiche notizie sicure sono probabilmente quelle sulla scitala lacedemonica , data da Plutarco come in uso dai tempi di Licurgo (IX sec a.C.) ma più sicuramente usata ai tempi di Lisandro(verso il 400 a.C.). Consisteva in un bastone su cui si avvolgeva ad elica un nastro di cuoio; sul nastro si scriveva per colonne parallele all'asse del bastone, lettera per lettera, il testo segreto. Tolto il nastro dal bastone, il testo vi risultava trasposto in modo regolare ma sufficiente per evitare la comprensione senza un secondo bastone uguale al primo. Figura 3.1 : Scitala lacedemonica Tra il 390 e il 360 a.C. venne compilato da Enea il tattico, generale della lega arcadica, il primo trattato di cifrari il cui XXI capitolo tratta appunto di messaggi segreti. In questo viene descritto un disco sulla zona esterna del quale erano contenuti 24 fori, ciascuno dei quali era contrassegnato da una lettera disposte in ordine alfabetico. Un filo, partendo da un foro centrale, Figura 3.2 : Disco di Enea si avvolgeva passando per i fori delle successive lettere del testo. Il destinatario del messaggio svolgeva il filo dal disco segnando le lettere da esso indicate. Il testo si doveva poi leggere a rovescio. Nei testi sacri, in particolare nel Vecchio Testamento, si possono ritrovare tre principali scritture segrete : l’ Atbash, l’ Albam e l’ Atbah. Il primo codice cifrato, l’ Atbash, è stato ideato dal popolo ebraico. Esso consisteva nel capovolgere l’alfabeto, di conseguenza la prima lettera diventava l’ultima e l’ultima la prima e così per tutte le altre lettere dell’alfabeto. Usando l’ attuale alfabeto ordinario, l’ Atbash può essere riassunto con la seguente tabella di cifratura : 21 La crittografia L'Albam richiede che l'alfabeto venga diviso in due parti e che ogni lettera venga sostituita con la corrispondente dell'altra metà. Infine, l'Atbah, richiede che la sostituzione soddisfi una relazione di tipo numerico. Le prime nove lettere dell'alfabeto vengono sostituite in modo tale che la somma della lettera da sostituire e della lettera sostituente risulti uguale a dieci. Per le restanti lettere dell'alfabeto deve valere una regola simile con somma pari a 28 in decimale. a b c d e f g h i j k l mn o p q r s t u v w x y z z y x w v u t s r q p o n ml k j i h g f e d c b a Lo storico greco Polibio (200 ca. -118 a.C.), nelle sue Storie (Libro X) descrive un interessante metodo di cifratura. L'idea è quella di cifrare una lettera con una coppia di numeri compresi tra 1 e 5, in base ad una matrice 5x5, contenente le lettere dell'alfabeto. Ogni lettera viene rappresentata da due numeri, guardando la riga e la colonna in cui essa si trova. Per esempio, a=11 e r=42.Inoltre, Polibio, suggeriva di mandare tanti messaggeri quanti erano i caratteri del messaggio. Questi portavano nella mano sinistra un numero di torce pari all'indice di riga e nella mano destra un numero pari all'indice di colonna. In effetti più che di un codice segreto, si tratta di un sistema di telecomunicazione, di fatto un telegrafo ottico. Telegrafi a torce esistevano da molti secoli ed erano stati descritti da Enea il tattico intorno al 350 a.C., ma erano basati su un limitato elenco di messaggi possibili; quello di Polibio si basa invece sulla scomposizione del messaggio nelle singole lettere ed è quindi in grado di trasmettere qualsiasi messaggio. # 1 2 3 4 5 1 A F KQ P V 2 B G L R W 3 C H M S X 4 D I N T Y 5 E J O U Z Svetonio nella Vita dei dodici Cesari, un'opera del II secolo d.C., racconta che Giulio Cesare usava per le sue corrispondenze riservate un codice di sostituzione molto semplice, nel quale ogni lettera del testo veniva sostituita dalla lettera che la segue di tre posti nell'alfabeto ( Restano quelle a Cicerone,così come quelle ai familiari sugli affari domestici, nelle quali, se doveva fare delle comunicazioni segrete, le scriveva in codice, cioè con l'ordine delle lettere così disposto che nessuna parola potesse essere ricostruita: se qualcuno avesse voluto capire il senso e decifrare, avrebbe dovuto cambiare la quarta lettera degli elementi, cioè D per A e così via per le rimanenti. ). a b c d e f g h i j k l mn o p q r s t u v w x y z d e f g h i j k l mn o p q r s t u v w x y z a b c 22 La crittografia Ad esempio la lettera A è sostituita dalla D, la B dalla E e così via fino alle ultime lettere che sono cifrate con le prime come nella tabella che segue (che fa riferimento all'odierno alfabeto internazionale). 3.1.2 La crittografia fino al XVIII secolo Un sistema usato dall'Arcivescovo di Napoli, Pietro di Grazia, tra il 1363 e il 1365, é quello in cui le lettere sono cifrate con numeri o simboli speciali. La corrispondenza tra lettere e simboli o numeri per la sostituzione è fissata da una tabella. Dagli inizi del XIV secolo, per depistare i tentativi di analisi statistica delle frequenze, si iniziano ad usare più segni per cifrare le vocali, dato che queste sono molto ricorrenti in un testo. Successivamente tale tecnica viene estesa anche alle consonanti più ricorrenti. Inoltre alcune parole, utilizzate frequentemente, (Papa, et, con, quo, etc.) sono sostituite con un solo simbolo. Un primo esempio di questa cifratura fu la lettera di Michele Steno scritta nel 1411. Figura 3.3 : Lettera di Michele Steno Leon Battista Alberti, nel suo Trattato, ha proposto un disco composto di due cerchi concentrici di rame. Uno esterno fisso di diametro maggiore sul quale sono riportate le lettere dell'alfabeto in chiaro e uno interno mobile per le lettere dell'alfabeto cifrante. Il disco esterno è composto di 24 caselle contenenti 20 lettere maiuscole in ordine lessicografico, escluse H, J, K, W, Y, al posto delle quali ci sono i numeri 1, 2, 3, 4. Il disco interno riporta le 24 lettere minuscole in maniera disordinata (la u e la v sono collassate) ed un simbolo speciale &. 23 La crittografia Fissata una lettera maiuscola come chiave, ad esempio B, si deve spostare il disco mobile interno in modo da far corrispondere la B con un simbolo particolare del disco interno(&). Si stabilisce in tal modo un'associazione tra le lettere dell'alfabeto in chiaro e quello dell'alfabeto cifrante. Può anche essere utilizzata una chiave diversa per ogni parola del testo in chiaro. Le lettere che di volta in volta corrispondono ai numeri 1 2 3 4 non vengono usate per la cifratura. Tutte le lettere del messaggio da cifrare sono cambiate in base all'associazione tra le lettere maiuscole e quelle minuscole. Tale disco non ottenne Figura 3.4 : Disco successo anche per la d e c i s i o n e d e l l ' A l b e r t i d i dell’Alberti tenerlo segreto (il suo trattato fu pubblicato solo un secolo più tardi a Venezia insieme ad altri suoi "opuscoli morali" e passò quasi inosservato). Il bresciano Giovan Battista Bellaso pubblicò tra il 1553 e il 1564 tre opere di crittologia contenenti alcuni cifrari polialfabetici di notevole interesse. L'idea su cui si basa il principale cifrario proposto dal Bellaso è quella di ricavare cinque alfabeti da una parola segreta convenuta. Le lettere dell' alfabeto vengono scritte in una tabella composta da due righe. In particolare quelle della parola segreta sono inserite nelle prime colonne intercalate sulle due righe e le rimanenti lettere dell'alfabeto vengono scritte di seguito. In questo modo si è ottenuto il primo alfabeto derivato. A partire da questo ricaviamo il secondo spostando circolarmente verso destra la seconda riga di una posizione. Applicando lo stesso procedimento al secondo alfabeto, si ricava il terzo alfabeto derivato e così via fino ad ottenerne cinque, ognuno dei quali sarà identificato da un gruppo di quattro lettere. Facendo riferimento sempre al primo alfabeto, le lettere della prima e della sesta colonna identificano il primo alfabeto derivato, quelle della seconda e della settima colonna identificano il secondo alfabeto derivato. In generale le quattro lettere che identificano l' i-esimo alfabeto sono quelle dell' iesima e della (i + 5)-esima colonna. A questo punto si deve convenire una frase segreta; le lettere di quest’ ultima servono a selezionare l' alfabeto da usare. In particolare, presa l' i-esima lettera della parola segreta, si controlla quale dei cinque identificativi degli alfabeti la contiene. Si determina così l'alfabeto da usare per l' i-esima parola del testo in chiaro. Se il numero di lettere della frase segreta è minore del numero di parole del testo da cifrare, la frase segreta viene riapplicata ciclicamente per la selezione degli alfabeti. La cifratura si 24 La crittografia effettua sostituendo la lettera del testo in chiaro con la lettera che si trova sulla stessa colonna nell'alfabeto predeterminato. Blaise de Vigenére pubblicò nel 1586 un trattato di cifrari nel quale proponeva tra gli altri un codice che ebbe grande fortuna e che è ricordato con il suo nome. Si tratta del più semplice codice di sostituzione polialfabetica, e proprio per la sua semplicità ha goduto per secoli di una grossa fama. La forza del cifrario di Vigenére sta nell'utilizzare non uno ma 26 alfabeti cifranti per cifrare un solo messaggio. Il metodo si può considerare una generalizzazione del codice di Cesare; invece di spostare sempre dello stesso numero di posti la lettera da cifrare, questa viene spostata di un numero di posti variabile, determinato dalle lettere della parola chiave, da concordarsi tra mittente e destinatario. La parola è detta chiave o verme, per il motivo che, essendo in genere molto più corta del messaggio, deve essere ripetuta molte volte. Di seguito viene riportata il cifrario utilizzato nei codici di Vigénère. 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 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 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 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 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 3.1.3 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 La crittografia moderna Il cifrario di Jefferson prende il nome dal suo inventore Thomas Jefferson (1743-1826), uno degli autori della Dichiarazione d'Indipendenza e Presidente degli USA nel 1801-1804. Jefferson non lo mise mai in uso e il suo cifrario fu dimenticato fino al 1922, quando fu riscoperto e utilizzato, fino agli anni '50, dall'esercito statunitense. E nel 1890 Etienne Bazeries un 25 La crittografia crittologo francese propose l' "La chiffre endecifrable", un cifrario del tutto equivalente a quello di Jefferson. Il codice di Jefferson è un metodo di cifratura meccanico basato su un cilindro di circa 15 cm di lunghezza e 4 cm di larghezza. Il cilindro è costituito da 36 dischi, imperniati su di un asse, in grado di ruotare liberamente. Ogni disco riporta le 26 lettere dell'alfabeto sul bordo esterno, in un ordine differente Figura 3.5 : Cifrario di Jefferson l'uno rispetto all' altro. Inoltre i dischi possono volta per volta essere inseriti sull'asse in un ordine differente per ogni cifratura, previo accordo tra mittente e destinatario. La cifratura di un messaggio avviene nel seguente modo : il messaggio viene prima di tutto diviso in blocchi di 36 caratteri. Per ogni blocco, i dischi della macchina vengono ruotati in modo tale da far comparire allineati su una riga i caratteri del blocco. Una volta effettuata tale operazione, si sceglie a caso un'altra riga, e si considera la corrispondente sequenza di 36 lettere come il messaggio cifrato. Il ricevente, che possiede un cilindro identico a quello del trasmittente, non deve far altro che ruotare i dischi in modo tale da far comparire il cifrato allineato su una riga. Compiuta questa operazione, deve analizzare le restanti righe. Una sola di queste è una frase di senso compiuto rappresentante il messaggio in chiaro. Una variante è quella di fissare a priori la riga su cui sarà possibile trovare il messaggio in chiaro. Il cilindro di Jefferson è il primo esempio di una serie di macchine cifranti basate su cilindri e dischi ruotanti intorno ad un asse, la più celebre di tutte è la cosiddetta Macchina Enigma usata dai Tedeschi nella Seconda Guerra Mondiale. Il Playfair cipher fu inventato dal noto fisico Sir Charles Wheatstone (1802-1875), ma il nome di Playfair deriva da colui che ha divulgato nelle alte sfere governative questo metodo di cifratura. Lyon Playfair, barone di St.Andrews, mostrò per la prima volta questo sistema nel 1854 durante una cena organizzata da Lord Granville alla presenza di Lord Palmerton (1784-1865) allora ministro degli Esteri. La speranza di Playfair era quella di far utilizzare il Cipher durante la guerra di Crimea ma il sistema fu effettivamente utilizzato dall'esercito britannico solamente a partire dalla guerra Boera. Il Cipher è ritenuto essere il primo metodo di cifratura a bigrammi (coppie di caratteri). Si usa una matrice di 25 lettere che viene riempita nelle prime caselle con la parola chiave, abolendo le eventuali lettere ripetute, ed è completata con le rimanenti lettere nel loro ordine alfabetico. Si omette la W che, se necessario, potrà essere cifrata come una doppia V. 26 La crittografia Il testo in chiaro deve essere diviso in bigrammi di due lettere consecutive. Le due lettere si cercano sul quadrato e si sostituiscono con altre secondo le seguenti regole: se le due lettere chiare si trovano su una stessa riga, si prendono le due lettere che le seguono a destra; se una delle due lettere chiare si trova sulla quinta colonna a destra, si prenderà la prima lettera a sinistra della stessa riga. Se le due lettere chiare sono sulla stessa colonna, si prendono le due lettere sottostanti; se una lettera è nell'ultima riga, si prenderà la lettera che sta nella prima riga della stessa colonna; se le due lettere sono in colonne e righe diverse, si prendono le due che costituiscono un rettangolo con esse, cominciando da quella che si trova nella stessa riga della prima lettera del bigramma in chiaro; qualora il bigramma chiaro presenti due lettere uguali si cercherà di eliminare questo raddoppio, oppure di romperlo inserendo una lettera rara (k, w, x, y). Dopo che la Gran Bretagna dichiarò guerra alla Germania il 3 settembre 1939, le operazioni di decifrazione Britanniche furono spostate da Londra a Bletchley Park. Tra il 4 settembre 1939 e l'estate del 1944, Alan Turing (1912-1954) (uno dei più famosi matematici di questo secolo, fra i fondatori dell'informatica teorica) alloggiò al Crown Inn, a Shenley Brook End, un villaggio vicino Bletchley. Il lavoro eseguito da Alan Turing e dai suoi colleghi a Bletchley Park poté essere completamente apprezzato solo molti anni dopo, quando cadde il segreto militare sulle tecniche di crittoanalisi durante la guerra. Quasi tutte le comunicazioni tedesche venivano cifrate con una macchina chiamata Enigma. Questa macchina è una nobile rappresentante dei cifrari a rotore, utilizzati fino all'introduzione di cifrari elettronici e microelettronici che hanno sconvolto e trasformato il mondo della crittografia. Per "rompere" Enigma (alcuni dettagli della soluzione sono tenuti segreti fino ad oggi) Turing, per conto del governo inglese, si servì di gigantesche macchine chiamate appunto Colossi, che possono considerarsi i precursori dei moderni calcolatori elettronici. Turing è autore di ricerche estremamente importanti sul concetto logico-matematico di calcolabilità : lo strumento che egli ha proposto per affrontare il problema è noto oggi col nome di macchina di Turing. Una delle prime macchine di cifratura a rotori è stata costruita dal californiano Edward Hebern, che la brevettò nel 1921. Autentici gioielli della crittografia meccanica sono le macchine costruite da Boris Hangelin; nel 1927 egli aveva rilevato una ditta che produceva materiale crittografico e che ancora oggi è prospera e fiorente, anche se ormai i rotori sono entrati nei musei della scienza. Per rendersi conto di quanto i tempi siano cambiati basterà ricordare che l' Enigma aveva un grande inconveniente: era sprovvisto di stampante. I risultati apparivano illuminati su una tastiera apposita, lettera dopo lettera, e una persona doveva provvedere a trascriverli a mano su un foglio di carta. Una 27 La crittografia stampante elettro-meccanica avrebbe appesantito troppo il congegno e lo avrebbe reso poco maneggevole. In un epoca di supercomputer e macchine potentissime il codice Navajo è un monumento alla più potente e sofisticata macchina che esista al mondo : la mente umana. Nel tentativo di ottenere delle comunicazioni vocali "sicure" l'esercito USA, prima della seconda guerra mondiale ha sperimentato l'uso della lingua degli indiani Choctaws per criptare le comunicazioni vocali, lingua che era già di per se "criptata". Dopo l'entrata in guerra degli USA, nel 1941, lo studio di questo tipo di "crittografia" venne esteso e si sperimentarono i linguaggi di Commanches, Choctaws, Kiowas, Winnebagos, Seminoles, Navajos, Hopis e Cherokees. Successivamente la Marina USA ha proseguito il lavoro dell'esercito codificando, espandendo e perfezionando il metodo, usando esclusivamente il linguaggio Navajos. Usati con successo su molti fronti i "NAC" (Native American Codetalkers) non hanno mai visto "infranto" il loro "codice". 3.2 Principali cifrari Di seguito verranno analizzati i principali cifrari utilizzati nella storia. 3.2.1 Cifrari a sostituzione In questi sistemi di cifratura, ogni simbolo del testo in chiaro viene trasformato in un simbolo dell'alfabeto del testo cifrato. I segni di punteggiatura e gli spazi non vengono cifrati, in modo tale che il testo diventa un'unica stringa di caratteri alfabetici. Questi cifrari si dividono in due categorie: monoalfabetici e polialfabetici. Nei monoalfabetici, ogni carattere, una volta sostituito con un altro carattere, conserverà tale sostituzione durante tutta la fase di cifratura; per esempio, se la parola “bacca” sarà cifrata in “efggf”, allora la lettera 'a' sarà sempre cifrata con la 'f ', la 'c' con la 'g' e così via. Nei sistemi polialfabetici, invece, lo stesso carattere può essere cifrato con più caratteri. Un esempio di cifrario a sostituzione monoalfabetica è quello di Cesare. 3.2.2 Cifrario affine In questo cifrario la chiave é una coppia di interi in Z26 K = (a,b) con a,b ∈ Z26 Dato un messaggio x da cifrare, la funzione di cifratura é del tipo ek (x) = (ax + b) mod 26 28 La crittografia Queste funzioni sono dette funzioni affini, da cui il nome del cifrario. Una funzione di cifratura deve essere iniettiva; se così non fosse il ricevente non potrebbe decifrare il messaggio in modo univoco. Pertanto la chiave (a, b) deve essere scelta in modo che l'equazione y = (ax + b) mod 26 abbia un'unica soluzione. Supponendo di scegliere come chiave la coppia a = 2 e b = 0 e che il messaggio cifrato sia y = 0; allora la funzione di cifratura sarà ek (x) = 2x e quindi per decifrare il messaggio l'equazione da risolvere sarà 2x = 0 mod 26 Le soluzioni sono x = 0 e x = 13, quindi due messaggi in chiaro distinti corrispondono allo stesso messaggio cifrato. Di conseguenza la scelta a = 2 non è ammissibile perché si vuole che la congruenza ax = 0 mod 26 (1) abbia un'unica soluzione per x. Sia d = gcd(a,26). Allora la congruenza (1) ha almeno due distinte soluzioni in Z26, cioè x = 0 e x = 26/d. Per avere un'unica soluzione deve essere gcd(a,26) = 1, cioè a deve essere primo con 26. Tale condizione è necessaria e sufficiente affinché ek(x) risulti iniettiva. Teorema ax=y mod 26 ha un’unica soluzione per ogni y se e solo se gcd (a, 26) = 1. Dimostrazione Supponendo che ax = y mod 26 abbia un'unica soluzione per ogni y e supponendo per assurdo che gcd(a, 26) = d >1. Risolvendo l'equazione per y = 0 si giunge ad un assurdo; infatti ax = 0 mod 26 ha due soluzioni distinte in Z26 : x = 0 e x = 26/d . Quindi è stato provato che esiste un y per cui ax = y mod 26 non ammette soluzione unica. Sia gcd(a, 26) = 1, siano x1 e x2 soluzioni distinte di ax = y mod 26 quindi ax1 = ax2 mod 26 da cui a(x1 - x2 ) = 0 mod 26 quindi 26 | a( x1 - x2 ) dato che gcd(a,26) = 1 si ha 26 | ( x1 - x2 ) quindi x1 = x2 mod 26 così x1 e x2 sono la stessa soluzione. Si calcoli la funzione di decifratura d applicata ad un messaggio cifrato y. Siccome y = ax + b mod 26 si ha che y -b = ax mod 26 da cui 29 La crittografia a-1 (y-b) mod 26 = x quindi d(y) = a-1 (y - b) mod 26. Il numero di possibili chiavi per il cifrato affine è dato dal numero di coppie (a,b), tali che b può assumere qualsiasi dei 26 possibili valori mentre a solo i valori tra 0 e 25 primi con 26. Quindi il numero dei possibili valori che a può assumere è dato dalla cardinalità di Z*26, che può essere determinata tramite la funzione di Eulero: f(26) = (13-1) (2-1) = 12 Pertanto il numero di possibili chiavi è 26x12 , troppo basso per scoraggiare una ricerca esaustiva. 3.2.3 Cifrario Playfair Questo sistema fa uso di una matrice 5 x 5, che rappresenta la chiave, in cui ci sono 25 lettere distinte dell'alfabeto disposte in ordine arbitrario. L'unica lettera non presente è la Q, in quanto è la lettera che è quasi sempre seguita dalla U e quindi facilmente riconoscibile. Ogni lettera individua ed è individuata dal suo numero di riga e dal suo numero di colonna. Il testo in chiaro deve essere di lunghezza pari, dovrà essere diviso in coppie di caratteri e ciascuna coppia deve avere caratteri distinti. Nel caso in cui il testo sia di lunghezza dispari si aggiunge un carattere fittizio che non alteri il senso del messaggio, per ottenere la parità. Analogo stratagemma si utilizza se una delle coppie ha i due caratteri uguali: si inserisce come secondo carattere uno che non altera la comprensione del testo. Con queste caratteristiche ogni coppia di caratteri rientra sicuramente in uno fra questi tre casi : 1. le due lettere della coppia si trovano sulla stessa riga; 2. le due lettere si trovano sulla stessa colonna; 3. le due lettere non si trovano né sulla stessa riga né sulla stessa colonna. La cifratura è eseguita su una coppia di lettere per volta. Ogni coppia del testo in chiaro rientra in uno dei tre casi precedenti, ciascuno dei quali va trattato in modo differente: 1. le lettere della coppia del testo in chiaro vanno cifrate con le lettere che le seguono sulla stessa riga (con la convenzione “circolare” che l'ultima lettera della riga sia seguita dalla prima). Per esempio per la coppia WI si ha HS, WH diventa HI, ecc…; 2. le lettere della coppia del testo in chiaro vanno cifrate con le lettere immediatamente sottostanti 30 La crittografia (sempre con la convezione “circolare”) ; ad esempio IG diventa BO e VB diventa IG; 3. in questo caso, che è il più frequente, le due lettere individuano sulla matrice un “rettangolo” di cui due vertici rappresentano la coppia di caratteri del messaggio in chiaro e gli altri due i corrispondenti caratteri del messaggio cifrato. La convezione che si utilizza nella cifratura è che la prima lettera del testo risultante é quella che si trova sulla stessa riga della prima lettera della coppia in chiaro. Per esempio, NC diventa PA, mentre CN diventa AP. W Y E M T 3.2.4 H A F N U I B G O V S C J P X K D L R Z Stream cypher Nei crittosistemi studiati fino ad ora successivi elementi del testo in chiaro sono cifrati mediante la stessa chiave k, cioè la stringa cifrata y è ottenuta nel modo seguente: y = y1 y2 …. = ek (x1 ) ek (x2 ) …. Crittosistemi di questo tipo sono spesso definiti “cifrari a blocchi”. Un approccio alternativo consiste nell'utilizzare gli “stream cipher”. L'idea di base consiste nel generare una sequenza, detta “keystream” z = z1 z2 ....... e nell'utilizzarla per cifrare la stringa x = x1 x2 …… del testo in chiaro nel modo seguente ossia dove zi = fi ( k, x1 , …. , x i -1 ) L’elemento zi della sequenza è utilizzato per cifrare xi, yi = ezi(xi) Pertanto per cifrare la stringa x1 x2 ….. bisogna calcolare z1, y1, z2, y2 ….. Analogamente per decifrare la stringa y1 y2 …..bisogna calcolare z1, x1, z2, x2 ...... Per esempio se P = C = K = Z26 le funzioni di cifratura e decifratura possono essere le seguenti: yi = xi + zi mod 26 xi = yi - zi mod 26 Gli stream cipher sono spesso definiti in termini binari, cioè P = C = K = Z2. In tal caso le funzioni di cifratura e decifratura possono essere le seguenti: yi = xi + zi mod 2 31 La crittografia xi = yi - zi mod 2 Se associamo a "0" il valore booleano "falso", ed a "1" il valore booleano "vero" allora l'addizione modulo 2 corrisponde allo XOR, pertanto la cifratura e la decifratura possono essere implementate molto efficientemente in hardware. Un metodo per generare la sequenza keystream a partire da m valori k1 , . . . . , km consiste nel fissare i valori per z1, .…., zm come z i = k i per ogni i = 1,……, m, e nel calcolare i valori successivi in base ad una relazione di ricorrenza lineare di grado m : dove c0,….,cm-1 ∈ Z2 sono costanti predeterminate. Tale ricorrenza è funzione lineare dei termini precedenti, ed ha grado m perché ciascun termine dipende dagli m precedenti. In tal caso la chiave consiste dei 2m valori ( k1……km ; c0 ......cm-1 ), dove ki=zi per i = 1,….., m. 3.2.5 Cifrario di Vernam Nel 1917 Gilbert Vernam, impiegato della compagnia AT&T, inventò un ingegnosissimo sistema di protezione crittografica, per comunicazioni su telegrafo, dei testi codificati in binario. Egli costruì per prima cosa un dispositivo in grado di leggere contemporaneamente due nastri in input e generare a partire da essi un nastro di output tale che ciascun foro fosse generato mediante uno XOR dei due corrispondenti fori sui nastri input. Dopodiché prese un nastro su cui era perforata una sequenza di caratteri casuale ed un nastro su cui era perforato un testo reale e li passò nella sua macchina. Il risultato fu un nastro completamente inintellegibile, ovvero cifrato. Lo schema di crittografia di Vernam è uno schema onetime pad; un tale schema richiede che : 1. la chiave sia usata una sola volta (da qui il nome); 2. deve essere lunga almeno quanto il testo in chiaro; 3. fra i bit che compongono la chiave non deve esserci alcuna relazione; 4. la chiave deve essere generata casualmente. In pratica se il testo in chiaro è X = 0110 e la chiave è K = 1100, applicando il metodo di Vernam si ottiene il seguente testo cifrato : Y= X ⊕ K = 1010 la decifratura si ottiene nel seguente modo: X= Y ⊕ K = 0110 Notiamo che è stata applicata la stessa chiave ed è stata effettuata la stessa operazione sia per la cifratura che per la decifratura, ciò caratterizza un sistema crittografico reversibile, questo è uno dei molti aspetti notevoli del cifrario di Vernam. Per ciò che concerne la sicurezza, a tutt'oggi, questo è l'unico 32 La crittografia metodo ad essere perfetto, ossia costituisce un cifrario assolutamente indecifrabile in senso stretto. Un cifrario si dice perfetto se, dati X il testo in chiaro e Y il cifrato corrispondente, gode della seguente proprietà: per ogni X’e Y’ risulta : Pr ( X = X’ ) = Pr (X = X’ | Y = Y’ ) La proprietà di cui sopra si chiama sicurezza perfetta. Per un cifrario che gode della sicurezza perfetta, l'indecisione nello stabilire qual è il testo in chiaro X senza conoscere il testo cifrato Y è la stessa che si ha su X conoscendo il testo cifrato Y. Le proprietà che caratterizzano l’one-time pad sono estremamente restrittive, volendole rispettare si ottiene un sistema scomodo da usare in pratica, considerando che le ingombranti chiavi andrebbero generate in anticipo rispetto al loro uso previsto, e conservate in luogo sicuro. Sono questi i motivi per cui questo sistema non viene usato che per casi eccezionali, come la famosa hot-line tra Washington e Mosca. Un'altro problema è che l’one-time pad è modificabile; un intruso può cambiare Y così che il messaggio M decifrato sia differente dal messaggio spedito. Non ci sono modi per il destinatario di controllare che il mittente abbia spedito proprio il messaggio ricevuto. Ci sono delle varianti che possono evitare di utilizzare delle chiavi così grandi, ma che fanno perdere la perfezione al sistema perché introducono delle dipendenze statistiche. Un esempio è quello di prendere una chiave in un grosso testo, come la Bibbia, specificando un punto di inizio qualunque, tutti i caratteri da quel punto in poi, formeranno la chiave. La dipendenza statistica è insita proprio nel fatto che le parole devono avere senso compiuto. La difficoltà per i crittoanalisti, oltre alla conoscenza della chiave (punto di inizio nel testo), sta anche nel capire qual è il testo utilizzato. Il problema con le chiavi corte, che dunque devono essere riutilizzate ciclicamente nel corso del messaggio, è che producono, in uscita, delle regolarità statistiche che possono essere usate dai crittoanalisti per forzare il cifrario. 3.3 Sicurezza perfetta Ragionando con i moderni termini della teoria dell'informazione, si comprende come la “somma” di una chiave casuale ad un testo in chiaro annulli l'ordine intrinseco nel testo stesso, producendo un cifrario a sua volta casuale, nel quale l'entropia H, che rappresenta la quantità di informazione contenuta in un messaggio X, è massima. L'entropia H(X) di una variabile aleatoria X con distribuzione di probabilità p1 , p2 , ……, pm , è uguale a 33 La crittografia e definisce la quantità di informazione contenuta in X. In termini di entropia è possibile definire un sistema di cifratura come segue : sia X la variabile aleatoria associata al messaggio in chiaro, sia Y la variabile aleatoria associata al messaggio cifrato e sia K la variabile aleatoria associata alla chiave, tutte con distribuzione di probabilità arbitraria. Con questa definizione Pr ( X = X’ ) = Pr (X = X’ | Y = Y’ ) si può scrivere H ( X ) = H ( X | Y ) Affinché le tre variabili aleatorie X, Y, K realizzino un sistema crittografico perfetto si deve avere : • Cifratura : il testo cifrato è univocamente determinato dal testo in chiaro e dalla chiave. Formalmente : H ( Y | XK ) = 0 • Decifratura : il testo in chiaro è univocamente determinato dal testo cifrato e dalla chiave. Formalmente : H ( X | YK ) = 0 • Sicurezza perfetta : la conoscenza del testo cifrato non dà alcuna informazione sul testo in chiaro. Formalmente : H ( X | Y ) = H ( X ) Teorema In un sistema crittografico con sicurezza perfetta, la lunghezza della chiave deve essere tanto grande quanto quella del messaggio in chiaro. Dimostrazione Supponendo che X sia il messaggio in chiaro,Y il messaggio cifrato e che la chiave utilizzata sia K. La mutua informazione I ( KX | Y ) può essere scritta come I ( KX | Y ) = H ( K | Y ) - H ( K | XY ) oppure come I ( KX | Y ) = H ( X | Y ) - H ( X | YK ) da cui si ottiene H ( K | Y ) = H ( K | XY ) + H ( X | Y ) - H ( X | YK ) (3) dato che H ( X | YK ) = 0, si ottiene H ( K | Y ) = H ( X | Y ) + H ( K | XY ) (4) In più, dato che l'incertezza sulla chiave è più grande dell'incertezza che si ha sulla chiave conoscendo anche il messaggio cifrato Y, cioè H ( K ) ≥ H ( K | Y ), si può scrivere: H ( K ) ≥ H ( K | Y ) = H ( X | Y ) + H ( K | XY ) per la (4) = H ( X ) + H ( K | XY ) per la sicurezza perfetta ≥ H ( X ) siccome H ( K | XY ) ≥ 0 Ciò significa che l'incertezza che si ha sulla chiave è maggiore o uguale della incertezza che si ha sul messaggio X. Se supponiamo che X sia distribuito uniformemente, allora: H ( X ) = log |X| da cui la lunghezza di K è maggiore o uguale della lunghezza di X, cioè log |K| ≥ H ( K ) ≥ H ( X ) = log |X|. 34 La crittografia 3.4 Gli algoritmi In questa sezione verranno esaminati due dei principali algoritmi utilizzati per la cifratura di dati : il DES e l’ RSA. Prima della trattazione tecnica verrà esaminata la storia dell’ algoritmo. 3.4.1 DES Il DES (Data Encryption Standard) viene adottato dal governo degli Stati Uniti nel 1977 come standard federale. Esso deriva dall'algoritmo Lucifer inventato dall' IBM nei primi anni '70. Mentre Lucifer era ancora in via di sviluppo il NBS (National Bureau of Standard), diventato poi NIST (National Institute of Standards and Technology) , sollecitò l'industria americana alla creazione di un nuovo standard crittografico per la protezione di dati riservati ma non classificati come "segreti militari" o di "stato". L'NBS non fu accontentato molto presto forse perché il governo degli Stati Uniti non ha mai incoraggiato ricerche in questo campo, comunque nel 1974 l'IBM propose un Lucifer modificato a cui fu dato il nome di DEA (Data Encryption Algorithm). L’ NBS sceglie il DEA come standard ed è annunciato sul documento N.46 di Federal Information, col nuovo e definitivo nome di DES. Tuttavia, se si riuscisse a far lavorare qualche migliaio di computer del tipo PC simultaneamente, è possibile sperare di scoprire la chiave in un periodo di tempo ragionevole. Provando a fare un piccolo conto si ottiene che si hanno 256 possibili chiavi. Supponendo che un PC calcoli un milione di chiavi al secondo, occorreranno 256/106 = 72057594037,9 secondi, che sono 1200959900,63 minuti, che sono 20015998,3439 ore, che sono 833999,930995 giorni, che sono 2284,93 anni. Quindi, per calcolare tutte le chiavi possibili bisognerà aspettare circa 2285 anni ! Quindi, se si vuole essere sicuri di trovare la chiave in giornata, sarà necessario calcolare quanti computer dovrebbero lavorare simultaneamente. Cioè 2.285 x 365 = 834.025 macchine. Riassumendo, bisogna far lavorare 834.025 computer contemporaneamente per 24 ore per testare tutte le chiavi possibili. La chiave di crittografazione è lunga 64 bit, ma 8 bit sono di controllo, quindi la chiave effettiva è di 56 bit. Questo porta ad avere 256 (circa 72 milioni di miliardi) possibili chiavi in un tentativo di attacco brute - force. In effetti un supercomputer potrebbe scoprire la password in un tempo che va dalle 3 alle 10 ore (per quello che è noto a livello non militare). 35 La crittografia Tuttavia, anche senza basarsi sull'attacco di forza bruta, gli studiosi Biham e Shamir hanno ideato una nuova tecnica di forzatura detta crittoanalisi differenziale. Questa tecnica consiste nell'utilizzo dell'algoritmo per la cifratura di 247 testi particolari ed il confronto dei risultati. Ancora in tempi più recenti, Matsui ha ideato un altro tipo di forzatura a cui è stato dato il nome di crittoanalisi lineare. Anche in questo caso vengono cifrati dei testi noti, per la precisione 243, ed analizzati i risultati con il testo da decifrare. I tempi di decrittazione sono comunque lunghi: il primo esperimento di Matsui richiese 9735 postazioni di lavoro e 50 giorni e 12 ore di tempo. Il DES non viene più certificato dal NIST. Ha tuttavia ancora larghissimo impiego nelle trasmissione audiovisive (è incluso nello standard IRDETO, usato nelle trasmissioni svizzere) e nei sistemi di protezione di Bancomat e carte di credito, data anche l'elevata velocità di crittografazione rispetto al suo rivale RSA a chiave pubblica. Non può essere tuttavia utilizzato in quei casi dove il valore dell'informazione da proteggere superi certe cifre, dato che già tempo fa è stato dimostrato che in circa 3 ore qualsiasi testo cifrato con DES può essere riportato in chiaro tramite un computer dal costo di 1 milione di dollari. E` comunque stata costruita una versione del DES, chiamata Triplo DES, che utilizza 3 chiavi diverse ad ogni passaggio di sovracifratura. Nonostante i risultati siano inferiori alle aspettative, è stato innalzato moltissimo il tempo necessario per un attacco di brute-force. Manipolazione della chiave Adesso verrà affrontato il primo stadio del cryptaggio che consiste nel manipolare i bits della chiave. Per prima cosa, bisogna sapere che la chiave si può presentare in due forme diverse: - una chiave a 56 bits come indicato precedentemente - una chiave a 64 bits che non è altro che la stessa chiave a cui è stata aggiunta una parità. La parità La parità è utilizzata durante le trasmissioni di dati binari al fine di verificarne la corretta ricezione. Essa consiste nell’aggiungere ad un "codice binario" un bit supplementare per fare in modo che il numero totale degli 1 sia sempre pari o dispari. Si avranno, quindi, due tipi di parità, pari o dispari. Esempio 10011000 10011001 parità dispari – abbiamo tre 1 parità pari – abbiamo quattro 1 36 La crittografia Per lo stesso gruppo di dati (1001100), vengono applicati due bits diversi per ottenere la parità desiderata. Per il sistema DES, viene utilizzata la parità dispari. Ora consideriamo un chiave a 56 bits: 12 34 56 3C F0 12 34 In binario avremo: 00010010001101000101011000111100111100000001001000110100 Applicando una parità dispari su ciascun gruppo di sette bits si otterrà dunque: 00010011 13 00011010 1A 00010101 15 11000111 C7 Il numero "1" è sempre dispari. 11001110 CE 10000000 80 01001001 49 01101000 68 Quindi la chiave 12 34 56 3C F0 12 34 a 56 bits senza parità corrisponde alla chiave 13 1A 15 C7 CE 80 49 68 a 64 bits con parità dispari. Si potrà, quindi, determinare ciascuna delle due chiavi possedendo l’altra. Primo stadio Prendiamo la chiave precedente a 64 bits. 13 1A 15 C7 CE 80 49 68 Verrà attribuito a ciascun bit una posizione da 1 a 64, procedendo da sinistra verso destra. 1 2 3 0 0 0 17 18 0 0 33 34 1 1 49 50 0 1 4 5 6 1 0 0 19 20 0 1 35 36 0 0 51 52 0 0 7 8 9 1 1 0 21 22 0 1 37 38 1 1 53 54 1 0 10 0 23 0 39 1 55 0 11 0 24 1 40 0 56 1 12 1 25 1 41 1 57 0 13 1 26 1 42 0 58 1 14 0 27 0 43 0 59 1 15 1 28 0 44 0 60 0 16 0 29 0 45 0 61 1 30 1 46 0 62 0 31 1 47 0 63 0 32 1 48 0 64 0 Si cerca ora di ridurre questa chiave a 56 bits applicando la seguente tabella di conversione: 57 01 10 19 63 07 14 21 49 58 02 11 55 62 06 13 41 50 59 03 47 54 61 05 33 42 51 60 39 46 53 28 25 34 43 52 31 38 45 20 17 26 35 44 23 30 37 12 09 18 27 36 15 22 29 04 Limitandosi a sostituire i valori indicati nella tabella con i bit corrispondenti, si avrà: 37 La crittografia 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 1 1 1 0 0 0 1 0 1 0 0 0 1 0 1 0 1 0 1 1 0 0 0 0 1 0 1 1 0 1 1 1 0 0 0 0 1 1 0 1 C(0) D(0) I primi 28 bits compongono il gruppo C(0). Gli ultimi 28 bits compongono il gruppo D(0) . A questo punto occorre calcolare le sedici chiavi derivanti dalla prima. In effetti il sistema DES opera su sedici iterazioni e ciascuna di loro a bisogno della propria chiave. Il valore I corrisponde alle iterazioni e prenderà quindi i valori 1-16. Inizio del ciclo I = 1 Per ciascuno dei sedici valori di I , si effettueranno una o due rotazioni circolari verso sinistra in funzione del valore indicato nella seguente tabella: Iterazione Rotazione 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 1 1 2 2 2 2 2 2 1 2 2 2 2 2 2 1 In questo momento I=1. Dalla tabella si vede che occorre effettuare una rotazione a sinistra. La rotazione si farà su C(I-1) e su D(I-1) dunque per I=1 su C(0) e su D(0). Il risultato sarà C(I) e D(I) quindi C(1) e D(1). C(0) = MSB LSB 0 0 1 1 1 0 0 0 1 1 0 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 Il primo bit di sinistra scomparirà per passare a destra ed il secondo bit a sinistra deve diventare il primo per cui si ottiene: MSB LSB 0 1 1 1 0 0 0 1 1 0 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 C(1) 38 La crittografia D(0) = MSB LSB 0 0 0 1 1 0 1 1 0 0 0 1 1 1 0 0 1 1 0 1 0 0 1 0 0 1 1 1 MSB LSB 0 0 1 1 0 1 1 0 0 0 1 1 1 0 0 1 1 0 1 0 0 1 0 0 1 1 1 0 D(1) A questo punto si opera su C(I) e su D(I) quindi C(1) e D(1) . Si comincerà con il riunire i due gruppi da 28 bits per formare un nuovo gruppo da 56 bits. Ora verrà attribuito una riga a ciascuno dei 56 bits e verrà applicata, infine, una permutazione secondo la tavola definita più avanti. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 0 1 1 1 0 0 0 1 1 0 1 1 0 0 15 16 17 18 19 20 21 22 23 24 25 26 27 28 0 1 0 0 0 0 0 0 0 0 0 0 0 0 29 30 31 32 33 34 35 36 37 38 39 40 41 42 0 0 1 1 0 1 1 0 0 0 1 1 1 0 43 44 45 46 47 48 49 50 51 52 53 54 55 56 0 1 1 0 1 0 0 1 0 0 1 1 1 0 Tavola di permutazione 14 17 11 24 01 05 03 28 15 06 21 10 23 19 12 04 26 08 16 07 27 20 13 02 41 52 31 37 47 55 30 40 51 45 33 48 44 49 39 56 34 53 46 42 50 36 29 32 da cui otteniamo: 0 1 0 1 1 0 1 0 0 0 0 0 0 1 0 0 1 0 1 0 1 0 1 1 0 0 1 0 0 1 0 0 0 0 0 0 1 0 1 0 0 0 1 1 1 0 1 1 A questo punto si ha la chiave K(I) e dunque la chiave K(1). 001000100000001101100001101011010100101011001001 La chiave è rappresentata sicuramente da 48 bits. Sarà lo stesso per le sedici chiavi K(1)-K(16). Di seguito, si passa a I=2 e si calcola la chiave K2. 39 La crittografia Si calcoleranno così le sedici chiavi. Il blocco dei dati Ora che si hanno le sedici chiavi è possibile lavorare su un blocco di dati di 64 bits così come è il cryptaggio. Prendendo come esempio il seguente dato 45 45 15 35 50 11 05 23 in chiaro In binario, si otterrà : MSB LSB 0100010101000101 0001010100110101 0101000000010001 0000010100100011 Allora si attribuirà, come fatto in precedenza, ciascun bit ad una determinata riga (1-64) e verrà applicata una tavola di permutazione a tutti i bits. 1 2 3 0 1 0 17 18 0 0 33 34 0 1 49 50 0 0 4 5 6 0 0 1 19 20 0 1 35 36 0 1 51 52 0 0 7 8 9 0 1 0 21 22 0 1 37 38 0 0 53 54 0 1 10 1 23 0 39 0 55 0 11 0 24 1 40 0 56 1 12 0 25 0 41 0 57 0 13 0 26 0 42 0 58 0 14 1 27 1 43 0 59 1 15 0 28 1 44 1 60 0 16 1 29 0 45 0 61 0 30 1 46 0 62 0 31 0 47 0 63 1 32 1 48 1 64 1 Tavola di permutazione iniziale (IP) 58 50 42 34 26 18 10 02 60 52 44 36 28 20 12 04 62 54 46 38 30 22 14 06 64 56 48 40 32 24 16 08 57 49 41 33 25 17 09 01 59 51 43 35 27 19 11 03 61 53 45 37 29 21 13 05 63 55 47 39 31 23 15 07 da cui otteniamo: 0 0 0 1 0 1 0 1 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 0 1 1 0 0 0 0 0 0 0 1 1 1 0 1 0 0 0 1 1 1 0 0 0 0 1 0 1 1 0 0 0 0 1 0 L(0) 1 1 0 0 R(0) 0 0 I primi 32 bits compongono L(0) gli ultimi 32 bits compongono R(0). A questo punto verrà applicato alle sedici chiavi. 40 La crittografia Inizio del ciclo I=1 Prendendo il blocco R(I-1) quindi R(0), si attribuirà ciascun bit ad una riga determinata ed applichiamo la tabella d’espansione che segue: 1 2 3 4 5 6 0 0 0 0 0 0 17 18 19 20 21 0 0 0 0 0 7 0 22 0 8 9 10 11 0 1 0 0 23 24 25 26 0 0 1 0 12 13 14 15 16 0 1 0 0 0 27 28 29 30 31 32 0 0 0 0 0 0 Tabella d’espansione 32 01 02 03 04 05 04 05 06 07 08 09 08 09 10 11 12 13 12 13 14 15 16 17 16 17 18 19 20 21 20 21 22 23 24 25 24 25 26 27 28 29 28 29 30 31 32 01 da cui otteniamo: 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 E(R(0)) 0 1 0 0 Otterremo 48 bits poiché sono stai utilizzati più volte alcuni bits. Occorre quindi eseguire la seguente operazione: E(R(I-1)) Xor K(I) Per la prima iterazione si ottiene : E(R(0)) Xor K(1) Si dovrà quindi effettuare un’ operazione di XOR esclusivo fra ciascun bit di E(R(0)) e ciascun bit della chiave K1 trovata precedentemente. Si otterrà : 000000000001010001010000000000000001010000000000 E(R(0)) XOR 001000100000001101100001101011010100101011001001 K(1) ________________________________________________ 001000100001011100110001101011010101111011001001 41 La crittografia Separando i 48 bits ottenuti in otto gruppi di sei bits : 001000 100001 011100 110001 101011 010101 111011 001001 B(1) B(2) B(3) B(4) B(5) B(6) B(7) B(8) Otterremo otto valori B(1)-B(8) e ciascuno di essi sarà associato ad una delle otto tavole che seguono (S-Box). 14 4 13 1 2 15 11 0 15 7 4 14 2 13 4 1 14 8 13 6 2 15 12 8 2 4 9 1 S1 8 3 10 6 12 5 9 0 7 1 10 6 12 11 9 5 3 8 11 15 12 9 7 3 10 5 0 7 5 11 3 14 10 0 6 13 S2 15 1 8 14 6 11 3 4 9 3 13 4 7 15 2 8 14 12 0 14 7 11 10 4 13 1 5 13 8 10 1 3 15 4 2 11 7 2 13 12 0 5 10 0 1 10 6 9 11 5 8 12 6 9 3 2 15 6 7 12 0 5 14 9 S3 10 0 9 14 6 3 15 5 1 13 12 7 11 4 2 8 13 7 0 9 3 4 6 10 2 8 5 14 12 11 15 1 13 6 4 9 8 15 3 0 11 1 2 12 5 10 14 7 1 10 13 0 6 9 8 7 4 15 14 3 11 5 2 12 7 13 14 13 8 11 10 6 9 3 15 0 S4 3 0 6 9 10 1 5 6 15 0 3 4 0 12 11 7 13 15 6 10 1 13 8 9 2 12 4 1 7 10 11 14 11 2 12 4 7 13 4 2 1 11 10 13 7 11 8 12 7 1 14 2 12 1 10 15 10 15 4 2 9 14 15 5 4 3 2 12 2 7 1 4 8 5 11 12 4 15 2 12 1 10 14 9 3 14 5 2 8 4 5 11 12 7 2 14 S5 6 8 5 3 15 13 1 5 0 15 10 3 8 15 9 12 5 6 13 6 15 0 9 10 S6 9 2 6 8 0 13 3 4 7 12 9 5 6 1 13 14 2 8 12 3 7 0 4 10 9 5 15 10 11 14 1 7 0 14 9 9 8 6 3 0 14 4 5 3 14 7 5 11 0 11 3 8 1 13 11 6 6 0 8 13 42 La crittografia S7 4 11 2 14 15 0 8 13 3 12 9 7 5 10 6 1 13 0 11 7 4 9 1 10 14 3 5 12 2 15 8 6 1 4 11 13 12 3 7 14 10 15 6 8 0 5 9 2 6 11 13 8 1 4 10 7 9 5 0 15 14 2 3 12 S8 13 2 8 4 6 15 11 1 10 9 3 14 5 0 12 7 1 15 13 8 10 3 7 4 12 5 6 11 0 14 9 2 7 11 4 1 9 12 14 2 0 6 10 13 15 3 5 8 2 1 14 7 4 10 8 13 15 12 9 0 3 5 6 11 Prendiamo B(1) . Esso sarà associato alla tavola S1. 1 2 3 4 5 6 B(1)= 0 0 1 0 0 0 I bits 1 e 6 formeranno un codice di due bits che chiameremo m. m = 00 che corrisponde a 0 in decimale. I bits 2-5 formeranno un codice di quattro bits che chiameremo n. n = 0100 che corrisponde a 4 in decimale. Occorre a questo punto ritornare alla tavola S1 . m indica il numero di linea della tavola, n indica il numero della colonna. Dunque bisognerà cercare il valore rappresentato nella linea 0, colonna 4. Il valore trovato sarà 2, che in binario viene indicato 0010. B(1) assume ora questo nuovo valore: B(1)=0010 La stessa cosa viene fatta da B(2) a B(8) e troveremo i nuovi valori: B(2)=1101 B(3)=0010 B(4)=1001 B(5)=1110 B(6)=1101 B(7)=0010 B(8)=1010 Raggruppando da B(1) a B(8) , attribuiamo una riga a ciascun bit e applichiamo la tabella che segue. 1 2 3 4 5 0 0 1 0 1 17 18 19 20 1 1 1 0 6 1 21 1 7 0 22 1 8 9 10 11 12 13 14 15 16 1 0 0 1 0 1 0 0 1 23 24 25 26 27 28 29 30 31 32 0 1 0 0 1 0 1 0 1 0 Tabella di permutazione p 16 07 20 21 29 12 28 17 43 La crittografia 01 15 23 26 05 18 31 10 02 08 24 14 32 27 03 09 19 13 30 06 22 11 04 25 da cui otteniamo: 1 1 0 1 0 0 1 1 0 0 0 1 1 1 1 1 0 1 0 1 0 0 1 0 1 0 1 0 0 1 0 0 A questo punto occorre applicare un XOR esclusivo fra i risultati ottenuti ed i valori di L(I-1) per la prima iterazione L(0). 10011001000011100110011011011100 XOR 00010011001111000100111111101111 L(0) ________________________________ 10001010001100100010100100110011 R(1) L(I) = R(I-1) per la prima iterazione L(1) = R(0) Riassumendo: L(1)=R(0)= 00000000100010000000000010000000 R(1)= 10001010001100100010100100110011 Adesso bisogna ritornare all’inizio del ciclo con I=2 per la seconda iterazione. Per completare la cifratura occorrono sedici iterazioni. Fine Appena applicata la sedicesima chiave, è necessario effettuare un’ultima permutazione nel blocco R(16)-L(16). Questa volta, R(16) si trova davanti a L(16). Verrà assegnato a ciascun bit del blocco il rispettivo posto ed applicata la permutazione finale con l’aiuto della seguente tabella. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 1 1 0 0 0 0 0 0 1 1 0 1 1 0 1 0 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 0 0 0 1 1 1 1 1 0 1 0 1 1 1 0 1 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 1 1 1 1 1 0 1 0 1 0 1 1 0 1 1 1 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 1 0 1 1 1 0 0 1 0 1 0 0 1 0 0 0 44 La crittografia Tabella di permutazione finale 40 08 48 16 56 24 64 32 39 07 47 15 55 23 63 31 38 06 46 14 54 22 62 30 37 05 45 13 53 21 61 29 36 04 44 12 52 20 60 28 35 03 43 11 51 19 59 27 34 02 42 10 50 18 58 26 33 01 41 09 49 17 57 25 Da cui si ottiene : 0 0 1 0 1 1 0 1 1 0 1 1 0 1 0 0 0 0 1 0 0 1 0 1 1 0 0 1 1 1 1 1 1 0 1 1 1 1 0 1 1 0 1 0 1 0 0 0 1 1 0 1 0 0 1 1 1 1 1 1 1 0 0 0 quindi 00101101 10110100 00100101 10011111 10111101 10101000 11010011 11111000 Convertendo questi valori in esadecimale si otterrà: 2D B4 25 9F BD A8 D3 F8 Che è quindi il valore cryptato di 45 45 15 35 50 11 05 23 con la chiave 13 1A 15 C7 CE 80 49 68 3.4.2 RSA L’RSA è un algoritmo di codifica a chiave pubblica. Questo algoritmo è a stato ideato da tre matematici Ron Rivest, Adi Shamir e Leonard Adleman nel 1977. Questo algoritmo sviluppa un codice cifrato attraverso un procedimento che sfrutta le proprietà dei numeri primi. L’RSA è formato da due chiavi, quella pubblica e quella segreta. La chiave pubblica è calcolata facendo il prodotto tra due fattori primi molto grandi, il risultato che troviamo N è un numero che deve essere difficile da fattorizzare, questa N viene resa pubblica. Esempio n = modulo p = numero primo q = numero primo 45 La crittografia n = p * q = modulo Si sceglie un numero ‘e’ primo rispetto a (p-1) (q-1), in seguito si prende un numero ‘d’ tale che (e*d-1) sia divisibile per (p-1) (q-1): il numero ‘e’ viene chiamato esponente pubblico, il numero ‘d’ è l’esponente privato. Queste due chiavi concorrono a formare la chiave pubblica, che è formata dalla coppia (n,e), mentre la chiave privata è formata dai numeri (n,d). Oggi è molto difficile fattorizzare ‘n’ nei due numeri ‘p’ e ‘q’ in tempi accettabili. Al momento non è possibile pensare ad una forzatura dell’algoritmo RSA, poiché si utilizzano chiavi con un numero di cifre superiore o uguale a duecento. Figura 3.6 : Creazione di una coppia di chiavi con RSA 3.5 Macchine cifranti In questa sezione verranno trattate le due macchine che si sono rese protagoniste nella seconda guerra mondiale : Enigma e la Bomba di Turing o Colossus. 3.5.1 Enigma Nel 1918 l'inventore tedesco Arthur Scherbius avendo studiato ingegneria elettrica ad Hannover e Monaco, mise a punto un dispositivo crittografico che in sostanza era una versione elettromeccanica del disco cifrante dell'Alberti. 46 La crittografia La sua invenzione fu chiamata Enigma. Essa consiste di diversi ingegnosi elementi combinati in un potente e sofisticato dispositivo per la produzione di scritture segrete. La versione semplificata del congegno di Scherbius consiste in 3 componenti collegati da fili elettrici: una tastiera per immettere le lettere del testo in chiaro; un'unità scambiatrice che cifra la lettera trasformandola nel corrispondente elemento del crittogramma (testo cifrato); un visore con varie lampadine, che accendendosi indicano la lettera da inserire nel testo cifrato. Per generare il crittogramma, l'operatore preme il tasto corrispondente alla lettera da cifrare; l'impulso elettrico raggiunge l'unità scambiatrice, e dopo essere stato elaborato va ad illuminare il visore in modo da evidenziare la lettera cifrata corrispondente. Figura 3.7 : Versione semplificata della macchina Enigma con un alfabeto di sei lettere. Con questo schema di base lo scambiatore in sostanza definisce una corrispondenza tra le lettere del testo in chiaro e quelle cifrate, e la macchina può essere usata per realizzare una semplice cifratura per sostituzione monoalfabetica. Il passo successivo consiste nel far ruotare automaticamente il disco scambiatore di un 1/26 di giro dopo la cifratura di ogni lettera. In altre parole, la corrispondenza tra lettere in chiaro e cifrate cambia dopo la cifratura di ogni lettera cosicché la cifratura di una stessa lettera muta continuamente. Con questa disposizione rotante, lo scambiatore in sostanza definisce 26 diverse corrispondenze tra lettere in chiaro e cifrate, ed Enigma può essere usata per effettuare una cifratura polialfabetica. Tuttavia, così come è il congegno, ha un punto debole evidente; dopo 26 pressioni continue dello stesso tasto, il disco torna alla posizione iniziale, e se si continuasse a premere lo stesso tasto, lo schema di cifratura si ripeterebbe tale e quale. Per ridurre il numero di ripetizioni può essere introdotto un altro scambiatore. In questo modo, ogni volta che una lettera è cifrata, il primo disco ruota di un carattere, mentre il secondo disco invece resta immobile fin quando il primo scambiatore ha completato un giro, solo a questo punto il secondo scambiatore avanza di una posizione. L'aggiunta del secondo scambiatore comporta il vantaggio che lo schema della cifratura non si ripete finché il secondo scambiatore non è tornato al punto di partenza, il che richiede 26 giri completi del primo scambiatore, ovvero la cifratura di 26x26=676 lettere. Per una sicurezza ancora maggiore viene 47 La crittografia aggiunto un terzo rotore, per cui il numero di sostituzioni diverse è 26x25x26=16.900 (il secondo rotore effettua una rotazione in meno rispetto agli altri due, poiché dopo aver effettuato un giro completo rimane fermo una volta per far ruotare il terzo rotore). Inoltre viene aggiunto un riflessore molto simile allo scambiatore che consiste in un disco di gomma con circuiti interni che non ruotano e i fili entrano ed escono dallo stesso lato. Col riflessore installato quando si digita una lettera il segnale elettrico attraversa i 3 rotori, raggiunge il riflessore ed è mandato indietro. Quindi il segnale elettrico passa di nuovo nei rotori ma lungo un percorso diverso. Figura 3.8 : Il progetto di Scherbius del modello base di Enigma includeva un terzo scambiatore e un riflessore, che costringe l'impulso elettrico ad attraversare di nuovo gli scambiatori. Dato che il numero di chiavi è alto ma non abbastanza per scoraggiare un crittoanalista che può disporre di più macchine e più aiutanti, per accrescere l'affidabilità si dovrebbe aumentare il numero di assetti cioè il numero di chiavi. Invece di aggiungere un altro rotore e aumentare di 26 volte le chiavi sono state introdotte due nuove caratteristiche. Innanzitutto si possono utilizzare rotori removibili e sostituibili, ad esempio il primo e il terzo rotore si possono scambiare di posto. Quindi dati tre elementi intercambiabili essi possono essere permutati in sei modi differenti; con questo accorgimento il numero di chiavi aumenta di un fattore pari a sei. La seconda caratteristica è l'inserimento di un pannello a prese multiple tra la tastiera e il primo rotore. Il pannello permette al mittente di inserire alcuni cavi muniti di spinotti, che aveva l'effetto di scambiare due lettere prima della loro immissione nel rotore. L'operatore di Enigma dispone di sei cavi che gli danno la possibilità di scambiare sei coppie di lettere simultaneamente. 48 La crittografia Figura 3.9 : Il pannello a prese multiple è interposto tra la tastiera e gli scambiatori. Inserendo gli appositi cavetti è possibile scambiare due lettere. Calcolo del numero di chiavi possibili Rotori I due dischi rotanti più esterni effettuano 26 rotazioni ognuno, mentre quello centrale ne effettua 25, quindi sono ammesse 26x25x26=16.900 combinazioni di orientamenti. Unità cifratrice I tre rotori (1,2,e 3) possono essere inseriti nell'unità centrale in diverse posizioni reciproche, così riassumibili: 123, 132, 213, 231, 312, 321. Sono quindi ammesse 6 diverse posizioni reciproche dei rotori. Pannello a prese multiple I possibili abbinamenti di 2 x 6 = 12 lettere su 26 sono moltissime, per l'esattezza 100.391.791.500, che si ottiene dalla formula seguente dove p, il numero di cavi, è uguale a 6. Il numero totale di chiavi si ottiene moltiplicando le suddette possibilità: 16.900 x 6 x 100.391.791.500 49 La crittografia Figura 3.10 : Pannello a prese multiple Figura 3.11 : Disco rotante 50 La crittografia Figura 3.12 : Macchina Enigma Figura 3.13 : Scambiatore 51 La crittografia 3.5.2 La Bomba di Turing Nel 1938 Dilly Knox era conoscenza del fatto che i rotori usati dai tedeschi nella macchina Enigma fossero differenti da quelli in commercio e, molto probabilmente, non sapeva neanche il metodo di doppia cifratura del testo in chiaro, vero punto di forza per i tedeschi. In quel periodo, Alan Turing, tentò diverse vie per cercare di forzare il sistema di cifratura dei tedeschi basandosi sulle uniche informazioni in possesso dell’Inghilterra, ovvero un “testo piano conosciuto” che in seguito verrà ribattezzato con il nome di “crib”. Turing pensò che se l’analisi dei testi cifrati poteva portare a una parziale decrittazione dello stesso, l’utilizzo di calcolatori, i quali potevano testare diverse configurazioni di rotori in poco tempo, poteva portare a buoni risultati. Inoltre, Turing, attraverso l’uso delle proprie abilità matematiche, riuscì a dimostrare che una trasformazione da un testo cifrato al testo in chiaro precludeva un vasto numero di configurazioni di rotori. La GC&CS (Governement Codes & Ciphers School), tra gli anni tra il ’38 e il ’39, riuscì ad intercettare un gran numero di testi cifrati con la relativa copia in chiaro, grazie anche alla collaborazione di un impiegato polacco. Tra le caratteristiche che Turing scovò occasionalmente vi era quella che la stessa coppia chiaro/cifrato di caratteri occorreva più volte in differenti punti del medesimo messaggio. Questa caratteristica venne chiamata “clicks”. .....JYCQRPWYDEMCJMRSR .....SPRUCHNUMMERXEINS .........|…|……....|.|….|... Questo avveniva perché Enigma era reversibile, ovvero la coppia chiaro/cifrato di R,C era la stessa C,R e M,E ed E,M. L’occorrenza di una coppia è determinata dall’ordine del rotore e dalla posizione iniziale di esso. Turing capì che, l’ordine attuale dei rotori e la loro posizione di partenza, potevano essere trovati provando tutte le configurazioni che soddisfavano la coppia esaminata. Ovviamente provare tutte le combinazioni possibili su una sola macchina Enigma una alla volta avrebbe richiesto un tempo impossibile. Di conseguenza, il passo seguente, fu quello di considerare come il test poteva essere eseguito simultaneamente per una particolare configurazione iniziale della macchina. Il test di ogni coppia di lettere richiedeva un metodo per determinare rapidamente quale configurazione fosse esatta o errata. Questo faceva a capo al concetto di collegare insieme più macchine Enigma per velocizzare le operazioni di decrittazione. Il risultato fu quello di usare una macchina Enigma “aperta”. 52 La crittografia A causa della configurazione elettrica di Enigma ciò non era possibile perché gli ingressi e le uscite che conducevano corrente erano fissati sul rotore, mentre nella configurazione aperta studiata da Turing, il riflettore, che nella precedente configurazione precludeva ogni possibilità di connessione, aveva due lati. In particolare, quello di uscita era connesso a tre rotori che rappresentavano i percorsi inversi effettuati dalla corrente nella configurazione originale della macchina. Questo metodo dava la possibilità di avere delle connessioni in input/output separate, permettendo, così, di avere più macchine Enigma in serie. Figura 3.14 : Schema della macchina Enigma modificata da Turing. Nella Letchworth Enigma (chiamata così perché la fabbrica British Tabulating Machine, che l’ha costruita, si trovava a Letchworth) la cosa intelligente fu quella di includere ambedue i cablaggi, anteriore e posteriore, dei rotori di Enigma in un unico tamburo. Le connessioni tra un tamburo e il successivo avvenivano tramite quattro cerchi composti da 26 contatti fissi l’uno. I tre set di contatti erano cablati insieme, permanentemente, ai connettori di input/output. I tre tamburi, rappresentanti i tre rotori presenti sull’Enigma originale, potevano essere posizionati sull’albero, formando una macchina Enigma in configurazione aperta, con i connettori di input/output separati dagli altri. Ritornando al problema dei clicks, Turing decise di affrontarlo nel seguente modo : 53 La crittografia abcdefghijklmnopq JYCQRPWYDEMCJMRSR SPRUCHNUMMERXEINS ….|…|……....|.|……|... pose un offset, rappresentato dall’alfabeto minuscolo, per identificare ogni coppia. In questo modo C,R erano rappresentate dall’offset c e e mentre M,E da j, k e n. Alla connessione rappresentata dall’offset, in questo caso la “C”, dell’Enigma a configurazione aperta veniva applicata una tensione, in questo modo, le 26 lampadine attaccate ad essa indicavano se la possibile cifratura era esatta. In questo caso si sarebbe dovuta accendere la lampadina relativa alla lettera R. Con una singola macchina Enigma questa operazione avrebbe richiesto un incredibile numero di settaggi. Figura 3.15 : Schema di risoluzione del problema dei clicks. Le macchine Enigma in configurazione aperta erano tutte settate con lo stesso ordine di tamburi. Tutti i tamburi erano settati nel medesimo modo, tranne l’ultimo che rappresentava l’offset della lettera del crib da testare. In questo modo, attraverso un set di relè era possibile fornire un voltaggio in ingresso all’ultimo tamburo di tutte le macchine, così facendo era possibile verificare se il settaggio dei tamburi soddisfava il crib. Se il risultato era negativo si procedeva a cambiare l’ordine dei tamburi attraverso un motore elettrico. Figura 3.16 : Schema di settaggio dei tamburi per la risoluzione del problema dei clicks. 54 La crittografia Un estensione del concetto delle coppie di lettere è il loop di lettere. Abc def g hi j k lmnopq JYCQRPRYDEMCJMRSR SPRUCHNUMMERXEINS .............|………….......|| Il primo problema fu quello di trovare le posizioni principali S1, S2 e S3. Figura 3.17 : Schema di risoluzione del problema del loop. Turing capì che c’era un’altra via per scoprire le interconnessioni tra le macchine Enigma in configurazione aperta. Figura 3.18 : Schema di settaggio dei tamburi per la risoluzione del problema del loop.. Lo schema rappresenta tre macchine Enigma in configurazione aperta. I tamburi numero 1 sono settati in corrispondenza degli offset S1, S2 e S3. I tamburi numero 2 e 3 corrispondono alla configurazione standard dell’Enigma. A questo punto le posizioni dei rotori corrisponderanno alla posizione originale presente nella macchina Enigma al momento della crittazione. In questo modo il voltaggio di S1 sarà lo stesso in ingresso di S2 mentre il voltaggio di S2 sarà l’ingresso di S3. In questo modo si otterrà la configurazione originale. 55 La crittografia Ora il trucco sta nel connettere i terminali di uscita dall’ultima macchina nell’input della prima. Quest’ultima operazione porterà ad avere un loop tra le macchine, isolando, però, le connessioni S1, S2 e S3. In seguito, Turing pensò che se S1 era sconosciuto e se gli si applicasse un voltaggio casuale, questo raggiungerebbe tutte le macchine ma non influenzerebbe gli ingressi S1, S2 e S3 perché essi non erano connessi a nessun terminale. Il test finale consisteva nello spostare i rotori in modo da vedere se una o 25 lampadine si accendevano. Se tutte le lampadine erano accese la posizione era errata. Questo test avveniva in pochissimo tempo, l’unico accorgimento era quello di non surriscaldare i motori che muovevano i tamburi. L’altra idea che ha permesso di perfezionare la Bomba di Turing venne da Gordon Welchman. Egli pensò di costruire dei registri, che opportunamente modificati potessero riassumere le connessioni tra le macchine Enigma in configurazione aperta. Attraverso la “Diagonal Board” (così fu chiamata) era facile risalire alla corrispondenza tra le lettere, in particolare risultava quasi immediata la soluzione nei casi di loop di cifre. Figura 3.19 : Diagonal Board. Figura 3.20 : Vista frontale della Bomba di Turing. 56 La crittografia Figura 3.21 : Vista posteriore della Bomba di Turing. Figura 3.22 : Manopola per il settaggio dei tamburi. 3.6 Crittoanalisi La crittoanalisi è la scienza parallela alla crittografia, infatti essa è volta a debellare le protezioni offerte dalla crittografia. Di seguito verranno analizzate alcune delle tecniche usate dai crittoanalisti per decifrare i più diffusi sistemi di crittografia. 3.6.1 Crittoanalisi statistica Uno dei sistemi più utilizzati per la crittoanalisi di testi cifrati, specie quelli della famiglia dei metodi a sostituzione, è proprio l'analisi della frequenza con cui si ripetono alcune lettere in una data lingua. Analizzando come esempio, un testo scritto in italiano, anche di lunghezza limitata, si noterà sicuramente che le lettere che compaiono con più frequenza, sono nell'ordine : e,i,a,o. Questa caratteristica può essere sfruttata per decrittare cifrati sconosciuti, o perlomeno come validissima informazione iniziale per la crittoanalisi. Analizzando un qualsiasi testo italiano, inglese, ecc. è possibile stabilire per conto proprio quale sono le frequenze di 57 La crittografia ogni lettera dell'alfabeto in tale lingua. Analizzando poi le frequenze di un testo cifrato, si può capire con quale lettera è stata sostituita, associando la frequenza di ogni singola lettera del testo cifrato, con quella dell'alfabeto di tale lingua (che andrà scoperta per tentativi se non conosciuta). Se ad esempio in un testo che si sa essere italiano, spicca come lettera a frequenza più alta la lettera "x", sicuramente tale lettera deve essere sostituita con la lettera "e". Operando la sostituzione di tutte le lettere del testo cifrato secondo questo schema, il testo sarà decrittato come minimo al 60%. Ciò significa che ci si troverà ad avere un testo con lettere mancanti o errate in ogni parola, ma facilmente immaginabili. Ovviamente con gli algoritmi polialfabetici, sebbene siano metodi a sostituzione, le cose si complicano molto rispetto all'analisi di un monoalfabetico creato, ad esempio, con il cifrario di Cesare. Con i metodi monoalfabetici questo sistema di crittoanalisi porta alla soluzione in un batter d'occhio (a meno che non sia stato utilizzato anche un nomenclatore o un dizionario), mentre con i polialfabetici si può operare solo a blocchi di lunghezza pari alla chiave, dato che dopo tale lunghezza l'alfabeto di sostituzione varia. In questi casi conviene utilizzare la crittoanalisi lineare o differenziale. 3.6.2 Crittoanalisi lineare La crittoanalisi lineare è un sistema di crittoanalisi basato sull'analisi di una coppia cifrato - decifrato intercettata. L'attacco ha lo scopo di scoprire la chiave utilizzata nei messaggi. Non è necessario essere in possesso del programma utilizzato per cifrare/decifrare. Il metodo è orientato all'analisi tramite un'approssimazione lineare volta a descrivere il comportamento del blocco di bytes a partire dal testo in chiaro. Più in particolare si lavora a livello di bit utilizzando un registro a scorrimento per lo shift dei bytes ed effettuando la somma di alcuni stadi con l'uscita di sinistra di tale registro. In base ai dati così raccolti ed attentamente esaminati si può scoprire la chiave. La probabilità di successo è alta. Come funziona Per prima cosa ai ha bisogno di un registro a scorrimento lineare che sia composto di n elementi di memoria binaria, detti stadi, il cui contenuto può essere la cifra 0 o la cifra 1; n è la lunghezza del registro; l'ennupla binaria contenuta nel registro in un dato momento è lo stato del registro in quel momento (dunque gli stati possibili di un registro di lunghezza n sono 2n). Ad intervalli di tempo regolari il contenuto di ciascuno stadio viene trasferito (scorre) nello stadio di sinistra ed il contenuto di S0 "esce" dal registro. Anche il contenuto dello stadio più a 58 La crittografia sinistra, Sn-1, va aggiornato : ciò viene effettuato mediante la funzione di retroazione, detta "feedback" del registro. Tale funzione consiste in un addizionatore che è collegato a certi stadi del registro : l'addizionatore somma il contenuto di tali stadi (prima che il registro venga aggiornato) ed il risultato viene appunto trasferito in Sn-1; la somma è quella binaria modulo 2 in cui 1 + 1 = 0. Le uscite del registro sono costituite dalle cifre binarie pseudocasuali che via via occupano lo stadio S0. Chiave pseudocasuale è sinonimo di chiave "pseudoperfetta" (con riferimento al cifrario perfetto o di Vernam) e potrebbe sembrare che un simile codice sia inattaccabile ma non è così. Si immagini che un crittanalista possa venire in possesso della coppia messaggio - crittogramma; tale coppia può effettivamente essergli sufficiente per capire qual è la chiave che è stata usata, e dunque per decifrare tutti i crittogrammi futuri che sarà in grado di intercettare : bastano 2n cifre di messaggio e le 2n cifre del crittogramma corrispondente perchè il crittanalista sia in grado di forzare il cifrario in maniera completa. Si supponga che il registro in questione abbia lunghezza 5, e che il crittanalista abbia intercettato il messaggio m12 m13 m14...m20 m21, ed il crittogramma c12 c13 c14...c20 c21 (gli istanti di tempo sono t=12, 13, 14,...20, 21). Poiché il crittogramma si calcola sommando la chiave al messaggio cifra per cifra, si ha: c12=m12+S0(12) c13=m13+S0(13)... c21=m21+S0(21) Ciò consente al crittanalista di calcolare S0(12), S0(13), ...S0(21) : S0(17)=a0S0(12)+a1S0(13)+a2S0(14)+a3S0(15)+a4S0(16) S0(18)=a0S0(13)+a1S0(14)+a2S0(15)+a3S0(16)+a4S0(17) S0(19)=a0S0(14)+...a4S0(18) S0(20)=a0S0(15)+...a4S0(19) S0(21)=a0S0(16)+...a4S0(20) Queste 5 equazioni lineari consentono di trovare i valori di a0, a1, a2, a3 e a4. Il crittanalista è ormai in grado di calcolare anche S0(22), S0(23), e così via all'infinito : il cifrario è ormai forzato. Tale metodo fu per la prima volta usato da Matsui e Yamagishi in un attacco al FEAL. Successivamente Matsui lo estese e migliorò per forzare il DES, e da allora fu assai studiato. Langford e Hellman introdussero un attacco chiamato crittanalisi lineare - differenziale, che combina elementi della crittanalisi differenziale con quelli della lineare. Nello stesso modo sono stati studiati metodi per proteggere i testi cifrati da tali tipi di attacchi, e tra i maggiori 59 La crittografia esponenti di tale ricerche, hanno voce in capitolo Nyberg, Knudsen e O'Conner. 3.6.3 Crittoanalisi differenziale La crittoanalisi differenziale è un tipo di attacco che può essere adoperato per forzare dei blocchi di cifre iterativi. Il metodo si basa sull'analisi delle differenze tra due testi in chiaro cifrati con la stessa chiave. L'utilizzo di questa tecnica, sebbene con un grande lavoro, ha portato gli studiosi Biham e Shamir al successo nella forzatura dell'algoritmo DES. 3.6.4 Crittoanalisi su polialfabetici Il metodo crittografico cosiddetto "Le Chiffre Indéciffrable" o meglio conosciuto con il nome di cifrario di Vigénére è stato utilizzato molto a lungo perché ritenuto inattaccabile (da cui il nome). In effetti è il precursore del metodo più affidabile in assoluto, l’ one-time pad (o più propriamente detto cifrario di Vernam), se non fosse che la chiave di cifratura può essere anche cortissima e non casuale, cosa che lo trasforma invece in un sistema attaccabile con i metodi elaborati dal Kasiski. abcdefghijklmnopqrstuvwxyz Più in particolare, analizzando una cifratura come la seguente con chiave "abc", si nota che: Chiaro: Ciao a tutti Chiave: abca b cabca Cifr. : Dldo c wvvwj La prima e la terza "t" della parola tutti è stata crittata con la stessa lettera perchè? Perchè nel testo in chiaro, le due "t" si sono trovate ad una distanza esatta alla lunghezza della password. Pensate che un crittoanalista si lasci sfuggire un simile indizio? Sicuramente no, anzi, prenderebbe tale evento e lo confronterebbe con altri multipli o sottomultipli L'attacco alla Kasiski si basa proprio sull'osservazione che in un dato cifrato polialfabetico di questo tipo, si trovano spesso questi duplicati di cifratura a distanze precise. Individuando tutte le sequenze ripetute (e se ce ne sono già in questa frase di 3 parole possiamo immaginare che in un testo lungo ve ne saranno moltissime se la chiave è corta), il massimo comune divisore tra le distanze delle ripetizioni è la lunghezza della chiave o un suo multiplo. Trovata la lunghezza della chiave, la decrittazione diventa semplice quanto un sistema monoalfabetico. 60 La crittografia 3.6.5 Brute force Il metodo di attacco Brute force (forza bruta), consiste nell'effettuazione di una ricerca esaustiva della chiave di decifrazione. Questo tipo di attacco è possibile solo oggi, grazie ai computer : sfruttando le loro caratteristiche di velocità nell'effettuazione di operazioni quali la composizione di stringhe alfanumeriche e la velocità di test dei risultati, è possibile provare milioni di combinazioni in qualche minuto e con macchine potenti ed ancora meglio con macchine specializzate (la NSA stessa costruisce processori), anche in frazioni di secondo. Come si realizza L'occorrente per un attacco di questo tipo, consiste in : 1. un programma che il destinatario deve usare per decifrare (generalmente lo stesso programma utilizzato dal mittente per cifrare); 2. un generatore di password; 3. un programma pilota del programma decifrante; 4. un programma di test con dizionario. Il punto 1 è facile da realizzare : dall'estensione dei file o da altre caratteristiche è facile capire con quale dei programmi in commercio è stato realizzato un determinato file cifrato e procurarselo. Se non fosse possibile le cose si complicano notevolmente. Basandosi però sul fatto che anche il governo americano utilizza un programma con algoritmo pubblico, si presume che sia quasi sempre possibile entrare in possesso del programma cifrante/decifrante. I punti 2, 3 e 4, saranno funzioni di un unico programma che devono essere realizzati da un programmatore. Nello specifico, il generatore di password può tentare 2 strade : 1. la generazione di tutte le parole di un dato dizionario, se si presume che la password possa avere a che fare con qualche parola di senso compiuto (sebbene l'autore dovrebbe essere andato contro le regole del buon senso nella scelta della password); 2. la generazione di password seguendo un ordine stabilito (es. a, b,...z, aa, ab... az, aaa,aab...aaz, ecc.) Le password generate saranno introdotte nel programma di decrittazione (o decifrante, ovvero quello del punto 1), dal programma pilota, che si occupa di passargli la stringa di caratteri generalmente chiamata password, come se venisse inserita manualmente. L'operazione è semplicissima: sotto Windows, basta sfruttare l'automation, se fornita dal programma decifratore, oppure l'emulazione di tastiera che è sempre 61 La crittografia effettuabile, via software, o nel peggiore dei casi, via hardware attraverso altre macchine. Prima di tentare una nuova password, è necessario avere un feedback dei risultati, realizzabile dal programma del punto 4, il quale analizzerà il file decifrato per vederne i risultati e ricercare almeno alcune parole nel dizionario per vedere se sono di senso compiuto. Dato che la maggior parte dei programmi di crittografia non eseguono la decrittazione se la password inserita non è corretta, il programma di test dovrà dare il consenso ad un nuovo tentativo di inserimento password qualora non trovi nessun file decifrato in output. Qualora sia stato creato dal programma di decifratura, dopo averlo analizzato si dovranno prendere 2 scelte : 1. se viene trovata una o più parole di senso compiuto, deve interrompere tutte le operazioni e mostrare l'ultima password provata. 2. se non viene trovata alcuna parola di senso compiuto, deve cancellare il file appena esaminato ed avviare un nuovo tentativo di inserimento password da parte del programma (o funzione) pilota. Il dizionario che viene sfruttato dal programma di test (quello che genera quindi il feedback per il programma pilota), dovrà contenere le parole più comuni della lingua che si presume sia stata utilizzata, e sarà realizzato con un database indicizzato, oppure da un file di testo da caricare completamente in memoria per una più veloce operazione di ricerca. Tenere presente che tale dizionario potrebbe comunque essere composto anche solo da quelle congiunzioni, preposizioni, verbi ecc., onnipresenti in un testo. Può quindi essere sufficiente utilizzare un piccolo dizionario contenente parole formate da un minimo 3 caratteri (per evitare interpretazioni di successo errate, dovute al caso), come "dal", "che", "degli", "gli", "anche", "per", "non", "essere", "avere", "fare", ecc. Il sistema sopra esposto è specifico per i testi, ma può andare bene anche per la decrittazione di programmi eseguibili (software), dato che le interfacce utente dei programmi, contengono sempre parole del linguaggio parlato. Per la decrittazione di programmi eseguibili possono tuttavia essere utilizzati particolari accorgimenti, tanto per citarne uno, controllare solo i primi due byte del file decifrato, verificando che contengano il valore esadecimale 4D-5A, velocizzando le operazioni che in questo modo non necessitano neanche più del dizionario. 3.7 Curiosità e considerazioni Quanto potente deve essere un metodo crittografico per stare tranquilli? 62 La crittografia A questa domanda si può rispondere in due modi: la risposta più ovvia sarebbe: "Più si va sul sicuro, meglio è". D'altro canto, si potrebbe rispondere anche in maniera più tecnica: "Il fine della crittografia, non è sempre quello di rendere assolutamente impossibile la decifrazione, quanto quello di proteggere nella misura in cui la decifrazione richiede più tempo e risorse economiche del vantaggio che può portare la conoscenza delle informazioni protette". Se qualche secolo fa, un qualsiasi polialfabetico con chiave di 4 cifre sarebbe stato considerato impossibile da forzare, oggi c'è invece da preoccuparsi anche dei semplici attacchi a forza bruta possibili solo grazie ai computer. In altre parole, la sicurezza di un sistema crittografico deve aumentare col passare del tempo. Se oggi utilizzassimo ancora un sistema come il cifrario di Cesare, anche un ragazzino sarebbe in grado di decifrare un messaggio ed il più lento dei computers (anche uno dei primi 8086 o un 286) potrebbe trovare la soluzione in qualche frazione di millesimo di secondo. Fra una decina di anni, programmi ed algoritmi famosi potranno essere forzati col semplice brute -force, grazie ai miliardi di operazioni al secondo che già adesso alcuni PC sono in grado di compiere. C’è chi dice che in ambiente Echelon la crittografia DES ed altre a 64 bit siano decrittate in tempo reale... 63 Esempi pratici Capitolo 4 Esempi pratici 4.1 4.2 4.3 4.4 4.5 4.6 4.1 L’uso di Winsock 4.1.1 Struttura dell’applicazione 4.1.2 Implementazione dell’applicazione Il DES 4.2.1 La classe CDes Scambio di messaggi crittati 4.3.1 Struttura dell’applicazione 4.3.2 Implementazione dell’applicazione L’ analisi di un testo 4.4.1 Struttura dell’applicazione 4.4.2 Implementazione dell’applicazione I socket in Linux 4.5.1 Implementazione dell’applicazione PGP L’uso di Winsock Questa applicazione sarà la base per creare un programma che permetta l’invio di file crittati tra due terminali. In particolare verranno usate le librerie Winsock che forniscono gli strumenti necessarie per creare comunicazioni tramite il protocollo TCP/IP. Le API (Application Program Interface) Winsock sono state programmate per fornire un’interfaccia uniforme per l’esecuzione delle applicazioni di rete, indipendentemente dal software di rete utilizzato. 4.1.1 Struttura dell’applicazione L’applicazione è strutturata a finestre di dialogo. Ovvero vi è la completa assenza di menu e barre di comando, questo per rendere più pulita e semplice l’interfaccia e anche perché non se ne è resa necessaria l’inclusione nel progetto. L’interfaccia offre la possibilità di digitare l’indirizzo del server con cui comunicare (può anche essere un server di loopback, cioè la macchina stessa) e la porta da cui effettuare la scelta. Fatto questo basta cliccare sul pulsante Connect (Listen se è un server) per cominciare la comunicazione. Per quanto riguarda il funzionamento dell’applicazione ci sono due modi principali : client e server. 64 Esempi pratici Quando l’applicazione lavora come server essa si mette in ascolto di eventuali richieste da parte del client, mentre quando è in modo client l’applicazione dovrà attendere che il server si metta in ascolto per iniziare a comunicare. Indirizzo server e n° porta Apertura, chiusura connessione Tipo socket (client,server) Testo del messaggio Invia messaggio Messaggi inviati Messaggi ricevuti Figura 4.1 : Schema dell’applicazione PTerminal. Indirizzo server e numero porta Questi due campi sono riservati all’inserimento dell’indirizzo del server e il numero della porta a cui ci si vuole collegare o da cui ci si vuole mettere in ascolto, nel caso si sia client o server. È indispensabile completare entrambe i campi per aprire un socket. Tipo socket Queste due opzioni servono per scegliere se l’applicazione deve fare da server o da client. A seconda della scelta il comportamento dell’applicazione varierà. Apertura, chiusura connessione Questi due pulsanti permettono di creare la connessione e di abbatterla. Nel caso il computer è stato configurato come server il pulsante Connect diventa Listen, per sottolineare il fatto che l’applicazione, da quel momento, si metterà in ascolto di eventuali richieste da parte di un client. Testo del messaggio Questo campo è riservato al testo del messaggio. Sia il client che il server possono ricevere e mandare messaggi. 65 Esempi pratici Invia messaggio Questo pulsante permette di inviare il messaggio scritto nel campo testo del messaggio. Nel caso in cui il campo sia vuoto non verrà inviato nulla. Messaggi inviati, messaggi ricevuti In queste due finestre viene tenuto l’ordine di ricezione e di spedizione dei messaggi. 4.1.2 Implementazione dell’applicazione Come accennato in precedenza per la realizzazione dell’applicazione sono state utilizzate le API Winsock. Di seguito è riportata una breve descrizione dei metodi e degli eventi principali. Metodo Create Questo metodo prepara il socket per l’uso. La dichiarazione del metodo cambia a seconda che il computer sia client o server. Nel caso sia server occorre specificare anche l’indirizzo della porta in ascolto. Nel caso sia client non occorre specificare nessun parametro. Metodo Connect Questo metodo apre fisicamente la connessione. È utilizzata solamente dal lato client. Il client, per aprire la connessione, deve specificare il l’indirizzo IP del server e il numero della porta. Metodo Listen Questo metodo, utilizzato solamente dal lato server, abilita il server a ricevere chiamate. Il metodo Listen non ha bisogno di parametri. Metodo Accept Questo metodo viene richiamato in seguito all’evento OnAccept. Il socket in ascolto, all’arrivo della chiamata, creerà un ulteriore socket connesso all’altra applicazione. Per questo socket non bisognerà richiamare il metodo Create ma il metodo Accept. Il metodo Accept vuole come parametro la variabile associata all’altra applicazione. Metodo Send Questa primitiva permette l’invio dei messaggi attraverso una connessione via socket. Il metodo è identico per il client e per il server. I parametri indispensabili sono un puntatore ad un buffer generico e la lunghezza dello stesso. Questi parametri sono indispensabili perché il socket non conosce il tipo di dati da inviare. 66 Esempi pratici Metodo Receive Questa primitiva viene attivata dall’evento OnReceive. Grazie all’evento il socket sa che ci sono messaggi in coda. I parametri sono i medesimi del metodo Send, un puntatore ad un buffer e la sua lunghezza. Metodo Close È comune al socket e al client. Non vuole nessun parametro, inoltre è anche l’unico metodo a non restituire un codice di errore. Evento OnAccept Questo evento viene scatenato all’arrivo di una chiamata al socket in ascolto. Evento OnClose Questo evento viene scatenato all’arrivo di una segnalazione di chiusura (metodo Close) da parte di una delle due applicazioni. Evento OnConnect Questo evento viene scatenato in un socket per segnalare l’avvenuta connessione. Evento OnReceive Questo evento viene scatenato all’arrivo di un messaggio. Evento OnSend Questo evento è richiamato quando il socket è pronto a inviare dati. Di seguito verrà descritta l’implementazione della classe per la gestione dei socket. La classe creata è stata derivata dalla classe MFC CAsyncSocket. In questo modo è possibile ereditare la gestione degli eventi dalla classe MFC personalizzando quelli interessati. class CMySocket : public CAsyncSocket { private: CDialog* m_pWnd; public: CMySocket(); virtual ~CMySocket(); SetParent (CDialog *pWnd); virtual void OnAccept(int nErrorCode); virtual void OnConnect(int nErrorCode); virtual void OnReceive(int nErrorCode); }; 67 Esempi pratici Le variabili La variabile m_pWnd è un puntatore alla finestra di dialogo corrente. I metodi Funzione SetParent PROTOTIPO SetParent (CDialog *pWnd) INPUT pWnd puntatore ad una finestra di dialogo DESCRIZIONE La funzione setta la variabile privata m_pWnd con la variabile passata come parametro. Funzioni OnAccept, OnConnect, OnReceive PROTOTIPO virtual void Onxxxxx ( int nErrorCode ) INPUT nErrorCode codice errore DESCRIZIONE Queste funzioni rispondo agli eventi di base della classe. Esse sono state derivate da quelle definite nella classe CAsyncSocket. La loro funzione è quella di richiamare i metodi standard della classe per soddisfare le richieste dei socket. 4.2 Il DES Il funzionamento del DES è stato ampiamente descritto nel capitolo precedente, di conseguenza, di seguito, verrà analizzata l’implementazione in C. In particolare saranno esaminate le classi e i metodi utilizzati. Al termine, la classe creata, è stata inserita in una DLL (Dynamic Linked Library) in modo da permetterne il funzionamento congiunto con altre applicazioni. Nel nostro caso, la DLL, sarà usata insieme ad un’applicazione per l’invio di messaggi attraverso TCP/IP, in modo da rendere possibile lo scambio di messaggi crittati. 4.2.1 La classe CDes La classe CDes contiene i metodi e le variabili che caratterizzano l’algoritmo DES. class CDes { public: CDes(); virtual ~CDes(); 68 Esempi pratici void Crypt(LPTSTR Key, LPTSTR Data); void Decrypt(LPTSTR Key, LPTSTR Data); private: unsigned _int64 artoi(unsigned int *array,unsigned int length); void itoar(unsigned __int64 int64,unsigned int *array,unsigned int length); unsigned _int64 stoi(char *string,unsigned int length); void matoar32(unsigned int matrix[][4],unsigned int array[],unsigned int yStart,unsigned int xStart,unsigned int yEnd,unsigned int xEnd); void matoar48(unsigned int matrix[][6],unsigned int array[],unsigned int yStart,unsigned int xStart,unsigned int yEnd,unsigned int xEnd); void matoar56(unsigned int matrix[][7],unsigned int array[],unsigned int yStart,unsigned int xStart,unsigned int yEnd,unsigned int xEnd); void matoar64(unsigned int matrix[][8],unsigned int array[],unsigned int yStart,unsigned int xStart,unsigned int yEnd,unsigned int xEnd); void _strcat(char *strDest,char *strOr); void arcat(unsigned int *arrayOr1,unsigned int *arrayOr2,unsigned int *arrayDest,unsigned int lenDest,unsigned int lenOr); unsigned _int64 power(unsigned int b,unsigned int e); void shift(unsigned __int64 &shift,unsigned int nShift); void Calculate_Keys(unsigned int matrix[][7],unsigned int iterations); unsigned __int64 crypt(unsigned __int64 data,unsigned int iterations); unsigned __int64 crypt(unsigned __int64 data,unsigned int iterations); void Divide(unsigned int *array,unsigned int matrix[][6],unsigned int lenAr,unsigned int lenGrp); unsigned int Index(unsigned matDiv[][6],unsigned matrix[][16],unsigned row); void Group(unsigned int *array,unsigned int *arrGrp,unsigned int lenAr,unsigned int lenGrp); void Expand(unsigned int *array,unsigned int matrix[][6]); void Permute_IP(unsigned int *array,unsigned int matrix[][8]); void Permute_P2(unsigned int *array,unsigned int matrix[][4]); void Permute_FP(unsigned int *array,unsigned int matrix[][8]); void Reduce56to48(unsigned int *array,unsigned int matrix[][6]); void Reduce64to56(unsigned int *array,unsigned int matrix[][7]); void Set_Key(unsigned __int64 newKey); unsigned EX[8][6]; unsigned FP[8][8]; unsigned IP[8][8]; unsigned __int64 Keys_Array[16]; unsigned __int64 L[17]; unsigned P1[8][6]; unsigned P2[8][4]; unsigned __int64 R[17]; unsigned Rotation_Array[16]; unsigned R1[8][7]; unsigned S1[4][16]; unsigned S2[4][16]; unsigned S3[4][16]; unsigned S4[4][16]; unsigned S5[4][16]; unsigned S6[4][16]; unsigned S7[4][16]; unsigned S8[4][16]; unsigned _int64 Key; }; 69 Esempi pratici I metodi e le variabili della classe sono dichiarati tutti privati, ad eccezione dei due metodi che permettono la cifratura e la decifratura dei dati. Questo è stato fatto per evitare che ci possa essere un “furto” di dati dall’ esterno. Le variabili Le variabili EX, FP, IP, P1, P2, R1 e Sx sono matrici predefinite che servono nello sviluppo dell’algoritmo per calcolare sia le 16 chiavi che la cifratura del blocco dati. La variabile Rotation_Array è un array contenente il numero di rotazioni da effettuare per ogni iterazione. La variabile Keys_Array è un array che contiene le 16 chiavi di sovracifratura da applicare al blocco dati. Le variabili L e R sono matrici che contengono gli sviluppi dei 16 passi di cifratura. La variabile Key contiene la chiave di cifratura. I metodi Funzione Calculate_Keys PROTOTIPO void Calculate_Keys(unsigned int matrix[][7], unsigned int iterations) INPUT matrix[][7] matrice ridotta iterations iterazioni DESCRIZIONE La funzione calcola le chiavi usate per la crittazione. Il numero di chiavi da calcolare è definito dalla variabile iterations. Funzione crypt PROTOTIPO unsigned __int64 crypt(unsigned __int64 data, unsigned int iterations) INPUT data dati da cifrare iterations iterazioni OUTPUT iRes dati cifrati DESCRIZIONE La funzione critta il dato passato. La variabile iterations indica, implicitamente, il numero di chiavi da usare per la cifratura. Funzione decrypt PROTOTIPO unsigned __int64 decrypt(unsigned __int64 data, unsigned int iterations) 70 Esempi pratici INPUT data dati da decifrare iterations iterazioni OUTPUT iRes dati decifrati DESCRIZIONE La funzione decritta il dato passato. La variabile iterations indica, implicitamente, il numero di chiavi da usare per la decifratura. Funzione artoi PROTOTIPO unsigned __int64 artoi(unsigned int *array, unsigned int length) INPUT array array da convertire length lunghezza dell'array OUTPUT iRes array convertito DESCRIZIONE La funzione converte un array binario (composto da 0 o 1) in un intero a 64 bit. La funzione non effettua nessun controllo sulla lunghezza dell'array, ma è implicito che esso non debba superare i 64 byte. Di conseguenza ogni controllo deve essere effettuato prima della chiamata alla funzione. Funzione itoar PROTOTIPO void itoar(unsigned __int64 int64, unsigned int *array, unsigned int length) INPUT int64 intero da convetire array array in cui inserire l'intero convertito length lunghezza dell'array DESCRIZIONE La funzione converte un intero fino a 64 bit in un array binario (composto da 0 e 1). La funzione non effettua nessun controllo sulla lunghezza dell'array, ma è implicito che esso debba essere lungo tanto quanto la variabile da convertire e non più del tipo più grande (unsigned __int64). Di conseguenza ogni controllo deve essere effettuato prima della chiamata alla funzione. Funzione stoi PROTOTIPO void stoi(char *string, unsigned int length) INPUT string stringa da convertire length lunghezza della stringa OUTPUT iRes stringa convertita 71 Esempi pratici DESCRIZIONE La funzione converte una stringa in un intero a 64 bit. La funzione non effettua nessun controllo sulla lunghezza della stringa, ma è implicito che essa non debba superare i 64 byte. Di conseguenza ogni controllo deve essere effettuato prima della chiamata alla funzione. Funzioni matoarXX PROTOTIPO void matoarXX(unsigned int matrix[][X], unsigned int *array, unsigned int yStart, unsigned int xStart, unsigned int yEnd, unsigned int xEnd) INPUT matrix[][x] matrice da convertire array array risultato yStart riga di partenza xStart colonna di partenza yEnd riga di arrivo xEnd colonna di arrivo DESCRIZIONE Le funzioni convertono una matrice di n righe e m colonne, in un array pari alla loro dimensione. I parametri indicano implicitamente il numero di elementi da estrarre dalla matrice. La funzione non effettua nessun controllo sulla lunghezza dell' array che deve essere di lunghezza minima pari alla grandezza della matrice. Di conseguenza ogni controllo deve essere effettuato prima della chiamata alla funzione. Funzione power PROTOTIPO unsigned __int64 power(unsigned int b, unsigned int e) INPUT b base e esponente OUTPUT x risultato DESCRIZIONE La funzione calcola l'elevamento a potenza. Sia la base che l'esponente devono essere non negativi. Funzione shift PROTOTIPO void shift(unsigned __int64 &shift, unsigned int nShift) INPUT Shift valore da shiftare nShift numero di shift (1 o 2) 72 Esempi pratici OUTPUT shift valore shiftato DESCRIZIONE La funzione simula uno shift circolare supponendo che l'intero passato come parametro sia di soli 6 bit. Funzione arcat PROTOTIPO void arcat(unsigned int *arrayOr1, unsigned int *arrayOr2, unsigned int *arrayDest, unsigned int lenOr1, unsigned int lenOr2) INPUT arrayOr1 primo array da concatenare arrayOr2 secondo array da concatenare arrayDest array risultato lenOr1 lunghezza del primo array lenOr2 lunghezza del secondo array DESCRIZIONE La funzione concatena due array della lunghezza specificata dai parametri lenOr1 e lenOr2. La funzione non effettua il controllo sulla lunghezza degli array, di conseguenza tutti i controlli devono essere fatti prima della chiamata alla funzione. Funzione _strcat PROTOTIPO void _strcat(char *strDest, char *strOr) INPUT strDest stringa destinazione strOr stringa d'origine DESCRIZIONE La funzione concatena due stringhe. La stringa risultante sarà contenuta in strDest, inoltre essa sarà del tipo nullterminated. Funzioni di riduzione, espansione e permutazione PROTOTIPO void NOME_FUNZIONE(unsigned int *array, unsigned int matrix[][x]) INPUT array array a cui applicare la matrice matrix[][x] matrice risultante DESCRIZIONE Le funzioni applicano la matrice specificata, costruendone una risultante dall'operazione. Le funzioni seguono lo stesso principio di funzionamento, cambia solo la matrice applicata (le matrici si differenziano, oltre che per i valori, anche per la grandezza). Di seguito sono riassunte le funzioni con le matrici applicate. Reduce56to48 P1 = prima matrice di permutazione Reduce64to56 R1 = matrice di riduzione 73 Esempi pratici Permute_IP Permute_P2 Permute_FP Expand IP = matrice di permutazione iniziale P2 = seconda matrice di permutazione FP = matrice di permutazione finale EX = matrice di espansione Funzione Divide PROTOTIPO void Divide(unsigned int *array, unsigned int matrix[][6], unsigned int lenAr, unsigned int lenGrp) INPUT array array da dividere matrix matrice risultato lenAr lunghezza array lenGrp lunghezza gruppo DESCRIZIONE La funzione divide un array in gruppi della lunghezza specificata dalla variabile lenGrp. La massima grandezza dell'array è di 48 byte, di conseguenza la grandezza massima della matrice sarà 8*6. La funzione non effettua nessun controllo sulla lunghezza dell'array e sulla grandezza della matrice. Di conseguenza ogni controllo deve essere fatto prima della chiamata alla funzione. Funzione Group PROTOTIPO void Group(unsigned int *array, unsigned int *arrayGrp, unsigned int lenAr, unsigned int lenGrp) INPUT array array da raggruppare arrayGrp array risultato lenAr lunghezza array lenGrp lunghezza dei gruppi DESCRIZIONE La funzione unisce un array di interi (NON binario) in un unico array. La lunghezza dell'array e quella dei gruppi di bit viene passata come parametro. Funzione Index PROTOTIPO unsigned Index(unsigned int matDiv[][6], unsigned int matrix[][6], unsigned row) INPUT matDiv[][6] matrice da indicizzare matrix matrice da cui estrarre i dati row riga della matrice da indicizzare OUTPUT iRes risultato 74 Esempi pratici DESCRIZIONE La funzione preleva dalla matrice matDiv il valore binario e lo converte in modo da comporre le coordinate di ricerca (m = colonna, n = riga). L'intero risultato della ricerca verrà restituito. Funzione Set_Key PROTOTIPO void Set_Key(unsigned __int64 newKey) INPUT newKey nuova chiave DESCRIZIONE Funzione di interfaccia che setta la chiave. Funzioni Crypt e Decrypt PROTOTIPI void Crypt(LPTSTR Key, LPTSTR Data) void Decrypt(LPTSTR Key, LPTSTR Data) INPUT key chiave data dati da elaborare DESCRIZIONE Le funzioni sono i metodi principali della classe, servono per crittare e decrittare i dati. Il loro funzionamento è analogo, infatti la funzione Decrypt non fa che ripercorrere i passi della funzione Crypt al contrario. Ambedue le funzioni dividono i dati passati come stringhe in gruppi di 8 byte, in seguito, il gruppo appena ottenuto, viene crittato usando le 16 chavi precedentemente calcolate. I risultati vengono concatenati in un’ unica stringa e copiati nella stringa Data. 4.3 Scambio di messaggi crittati L’applicazione unisce l’uso di WinSock con la DLL costruita in precedenza per l’uso del DES. Attraverso questa applicazione sarà possibile mandare dei messaggi crittati attraverso l’algoritmo DES, tra un client e un server. Le finestre di dialogo dell’applicazione sono le medesime usate per l’applicazione PTerminal. Quindi sarà possibile scegliere la porta da cui effettuare lo scambio di informazioni e chi sarà il server e chi il client. La crittazione del messaggio avverrà in trasparenza, infatti il messaggio inserito dall’utente verrà crittato prima dell’invio e, di conseguenza, decrittato prima della visualizzazione che avverrà sul computer del secondo utente. La chiave dovrà essere già concordata in precedenza tra gli utenti. 75 Esempi pratici 4.3.1 Struttura dell’applicazione La struttura dell’applicazione è identica a quella di PTerminal. Figura 4.2 : Schema dell’applicazione. Come si può notare l’applicazione è strutturata in modo compatto. Non sono presenti menu ma solo un gruppo di Radio Button per decidere quale applicazione deve essere il server e quale il client. I tre Edit Box servono per inserire l’indirizzo del server e la porta a cui connettersi, l’ultimo serve per inserire i messaggi da inviare. I tre Command Button servono per aprire una connessione, chiuderla e per mandare il messaggio. Le due List Box servono per tenere traccia dei messaggi inviati e ricevuti. 4.3.2 Implementazione dell’applicazione La realizzazione dell’applicazione ha richiesto l’implementazione di una sola classe, oltre a quella usata per il DES. Essa è stata derivata dalla classe CAsyncSocket delle MFC. Ciò è stato reso necessario per gestire alcuni eventi particolari all’interno della classe, come l’invio e la ricezione. A questa classe è stato dato il nome CMySocket. 76 Esempi pratici Per l’aggiunta delle funzionalità di crittazione e decrittazione all’applicazione è stata usata la DLL creata in precedenza. L’aggiunta al progetto della DLL CDes ha richiesto solamente la dichiarazione, all’interno della classe CPTerminalDlg, del file header relativo alla DLL e l’aggiunta al progetto, come nuova risorsa, del file LIB della DLL. L’unica modifica al codice di PTerminal è stata l’aggiunta di un oggetto CDes nella classe CPTerminalDlg. Inoltre sia in ricezione che in invio, la stringa di dati viene passata al metodo Decrypt o Crypt, in modo da crittare/decrittare la stringa. Oggetti, variabili ed eventi I seguenti oggetti sono definiti nel progetto, alcuni di essi hanno associata una variabile. • IDC_RCLTSRV (Radio Button) VARIABILE int m_iType • IDC_LSENT (List Box) VARIABILE CListBox m_ctlSent • IDC_LRCVD (List Box) VARIABILE CListBox m_ctlRcvd • IDC_ESRVPORT (Edit Box) VARIABILE int m_iPort • IDC_ESRVNAME (Edit Box) VARIABILE CString m_strName • IDC_EMSG (Edit Box) VARIABILE CString m_strMessage • IDC_BCONNECT (Command Button) VARIABILE CButton m_ctlConnect • IDC_BSEND (Command Button) • IDC_BCLOSE (Command Button) I pulsanti IDC_BSEND e ICD_BCONNECT sono collegati a due eventi della classe CPTerminalDlg, OnBSend e OnBConnect. Questi due eventi creano la connessione e inviano i messaggi. Per la ricezione dei messaggi si usa la funzione Receive che viene richiamata ogniqualvolta viene generato l’evento OnReceive. Tutti questi eventi sono stati già definiti nelle classi CPTerminal e CMySocket nel progetto PTerminal. 77 Esempi pratici 4.4 Analisi di un testo In questa applicazione si cercherà di analizzare un testo cifrato e di decifrarlo senza avere la chiave. Per lo scopo si utilizzeranno tabelle contenenti le frequenze delle lettere della lingua italiana. Riportando questi valori a quelli relativi alle lettere contenute nel testo si potrà ricavare il testo in chiaro. Inoltre l’applicazione, sviluppata in Visual Basic, permetterà l’uso di algoritmi di cifratura di base (cifrario di Cesare, scacchiera di Polibio, cifrario di Vigénère). 4.4.1 Struttura dell’applicazione L’applicazione è strutturata come una tipica applicazione MDI (Multiple Document Interface). Vi è una form principale contenente il menu delle opzioni e la barra di comando, in più vi sono due form secondarie, una usata per la visualizzazione e l’editazione del testo, mentre l’altra per visualizzare attraverso un grafico le frequenze delle lettere presenti nel testo. Barra dei menu Barra di comando Testo Grafico delle frequenze Barra di stato Figura 4.3 : Schema dell’applicazione crittografia. 78 Esempi pratici La barra dei menu La barra dei menu è costituita da quattro voci principali : • File • Analizza • Critta • Decritta Attraverso queste voci è possibile effettuare tutte le operazioni permesse dall’applicazione. Menu file Figura 4.4 : Menu file dell’applicazione Crittografia. Dal menu file è possibile scegliere le seguenti opzioni : • Apri file in chiaro Questa opzione permette di aprire un file di qualsiasi estensione, visualizzandone il contenuto nella finestra di visualizzazione dei documenti. • Salva file in chiaro Questa opzione permette di salvare un file appena editato senza applicare nessuna crittografia. Inoltre, se il file da salvare è un file crittato, l’applicazione lo decritta automaticamente e lo salva in un formato definito dall’utente (il formato di default è il txt). • Apri file crittato Questa opzione permette di aprire un file precedentemente crittato. I tre formati disponibili sono : o *.csr, cifrario di Cesare; o *.plb, scacchiera di Polibio; o *.vgn, cifrario di Vigénère. Il file decrittato viene automaticamente visualizzato nella finestra di visualizzazione documenti. • Salva file crittato Questa opzione permette di salvare un testo oppure un file aperto in chiaro, usando uno dei tre algoritmi a disposizione (cifrario di Cesare, scacchiera di Polibio, cifrario di Vigénère). 79 Esempi pratici Menu analizza Questo menu non ha sottomenu. Se non è stato aperto nessun file, l’applicazione, chiede di aprirne uno e viene automaticamente visualizzato il grafico delle frequenze delle lettere. Al contrario, se un file è già stato aperto e nessun grafico è visualizzato a schermo, viene aperta una nuova finestra contenente il grafico della frequenza delle lettere. Menu critta Figura 4.5 : Menu critta dell’applicazione Crittografia. Dal menu critta è possibile scegliere uno dei seguenti algoritmi di crittazione : • Cifrario di Cesare • Scacchiera di Polibio • Cifrario di Vigénère Scegliendo uno di questi algoritmi, il testo contenuto nella finestra di visualizzazione testo, viene crittato. Per salvarlo basta scegliere dal menu File Salva file crittato. In questo modo l’applicazione riconoscerà automaticamente l’algoritmo di crittazione utilizzato e di conseguenza salverà il file con l’estensione appropriata. L’utente dovrà solamente scegliere il nome da dare al file. Menu decritta Figura 4.6 : Menu decritta dell’applicazione Crittografia. Dal menu decritta è possibile scegliere l’algoritmo da utilizzare per decrittare il file : • Cifrario di Cesare • Scacchiera di Polibio • Cifrario di Vigénère Scegliendo uno di questi algoritmi, il testo contenuto nella finestra di visualizzazione del testo, viene decrittato. Come succede per la crittazione, se si vuole salvare il file appena decrittato, basta selezionare dal menu File Salva file in chiaro. Così facendo, l’applicazione, salverà automaticamente il file nel formato preferito dall’utente. 80 Esempi pratici La barra di comando Apri file in chiaro Salva file in chiaro Figura 4.7 : Barra di comando dell’applicazione Crittografia. Salva file crittato Nuovo documento Apri file crittato La barra di comando riassume tutte le funzioni principali contenute nel menu file, con in più un ulteriore opzione, quella di creare un nuovo documento vuoto. La barra di stato Figura 4.8 : Barra di stato dell’applicazione Crittografia. La barra di stato contiene il percorso del file correntemente aperto. 4.4.2 Implementazione dell’applicazione Le form Per realizzare l’applicazione sono state utilizzate tre form principali : • mdiMain • frmDoc • frmGraph La form principale è una form MDI, che può gestire un numero elevato di form figlie. In questo modo è possibile visualizzare più finestre documento o grafico contemporaneamente. Le altre due form sono dei modelli. Ogni qualvolta viene richiesto un nuovo documento o un nuovo grafico ne viene creata una nuova. Il metodo di creazione è il seguente : Dim nome_form as frmDoc (o frmGraph) Form mdiMain Come detto in precedenza è la form principale. Essa contiene il menu, la barra di comando e quella di stato. In più permette la visualizzazione dei grafici e dei testi. Gli oggetti utilizzati al suo interno sono i seguenti : • tlbMain (Toolbar) Toolbar (barra di comando). Evento on-click. 81 Esempi pratici • • • stbMain (StatusBar) Statusbar (barra di stato). imlTlb (ImageList) Controllo che contiene le immagini delle icone presenti sulla barra di comando. cdlSaveOpen (CommonDialog) Controllo che permette l’utilizzo delle finestre standard per il salvataggio e il caricamento dei file. Funzioni Le funzioni descritte di seguito sono quelle usate per il salvataggio, l’apertura e il calcolo delle frequenze delle lettere. Le funzioni relativi agli eventi non saranno descritte. Funzione Scan PROTOTIPO Private Function Scan (strC as String) as Boolean INPUT strC carattere da cercare OUTPUT vero il carattere è stato trovato falso il carattere non è stato trovato DESCRIZIONE La funzione calcola la frequenza delle lettere nel testo, che verranno rappresentate nel grafico. Funzione OpenFile PROTOTIPO Private Function OpenFile (strFileToOpen as String) as String INPUT strFileToOpen percorso del file da aprire OUTPUT strFileOpen stringa contenente il file aperto DESCRIZIONE La funzione apre il file specificato dalla stringa strFileToOpen. Per gestire i file è stato usato l’oggetto FileSystemObject, il quale permette di creare dei file di testo. In questo modo sono disponibili dei metodi di lettura e scrittura più veloci e più semplici da utilizzare. Funzione SaveFile PROTOTIPO Private Function SaveFile (strFileToSave as String, strFileSave as string) as Boolean INPUT strFileToSave percorso in cui salvare il file strFileSave stringa da salvare 82 Esempi pratici OUTPUT vero il file è stato salvato falso il file non è stato salvato DESCRIZIONE La funzione salva la stringa passata su file. Anche in questo caso la gestione del file avviene attraverso l’oggetto FileSystemObject. Funzioni menu Queste funzioni vengono richiamate quando accade l’evento on_click su uno dei menu. Il loro compito è quello di richiamare le funzioni per la gestione dei file e per la cifratura e decifratura. Funzioni SaveCyph, OpenCyph, SaveClear, OpenClear Queste funzioni vengono utilizzate per impostare i filtri del CommonDialog e per scegliere che modalità utilizzarlo (Open o Save). Form frmDoc Questa form è usata come modello per tutte quelle che verranno create per la visualizzazione dei documenti. Gli oggetti utilizzati all’interno sono i seguenti : • txtText (TextBox) TextBox utilizzata per la visualizzazione dei documenti. All’intero non sono state definite funzioni. L’unico evento a cui risponderà la form sarà l’evento Resize. In questo modo la TextBox manterrà dimensioni costanti anche dopo il ridimensionamento della form. Form frmGraph Questa form è usata come modello per tutti i grafici delle frequenze. Gli oggetti utilizzati all’interno sono i seguenti : • mscGraph (MSChart) Oggetto utilizzato per la creazione del grafico. Come nella precedente form, non sono state definite funzioni. Anche in questo caso la form risponderà all’evento Resize, in modo da mantenere la dimensione del grafico costante. 83 Esempi pratici Modulo modInit Questo modulo contiene le inizializzazioni delle variabili, le variabili stesse e altre funzioni per il settaggio del CommonDialog. Variabili Le variabili globali definite all’interno del modulo sono : • Public ALPHA(26) As String Array contenente le lettere dell’alfabeto più lo spazio. • Public ASCII(255, 1) As String Matrice contenente i 256 caratteri ASCII, ognuno dei quali associato ad una frequenza. • Public PLOT(26, 1) Matrice contenente le lettere dell’alfabeto più lo spazio. Ad ognuna di esse è associata una frequenza. • Public FREQ(26) As String Array contenente le lettere dell’alfabeto in ordine di frequenza rispetto alla lingua italiana. • Public CaesarCyph As New Caesar • Public PolibioCyph As New Polibio • Public VigenereCyph As New Vigenere Oggetti usati per la crittazione e la decrittazione. Funzioni Funzione InitVAR PROTOTIPO Public Sub InitVAR() DESCRIZIONE La funzione inizializza tutti gli array e le matrici con i dati. Funzione Clear PROTOTIPO Public Sub Clear() DESCRIZIONE Azzerra l’array PLOT. Funzione InitCDL PROTOTIPO Public Sub InitCDL(CDL as CommonDialog, strExt as String, strTitle as String, strFilter as String, strInitDir as String, strOpenSave as String) INPUT CDL oggetto da settare 84 Esempi pratici strExt estensione standard da dare ai file strTitle titolo che apparirà nel CommonDialog strFilter possibili estensioni da dare al file strInitDir directory di default strOpenSave settaggio dei flags. DESCRIZIONE La funzione setta con i parametri passati il CommonDialog, anch’esso passato come parametro. Funzioni InitDOC e InitGRAPH PROTOTIPO Public Sub Initxxx(strFilename as String) INPUT strFilename nome del file che apparirà come titolo della finestra DESCRIZIONE Queste due funzioni creano una nuova finestra documento e una nuova finestra grafico. Moduli di classe I moduli di classe contengono le definizioni delle classi usate per gli algoritmi di crittazione. Modulo Caesar Questo modulo contiene le definizioni dei metodi per la cifratura attraverso il cifrario di Cesare. La crittazione dei dati avviene utilizzando il codice ASCII e non l’alfabeto ordinario. Variabili L’unica variabile definita all’interno del modulo è la seguente : • Private Alphabet(255) as String Array contenente il codice ASCII. Funzioni Funzioni Crypt e Decrypt PROTOTIPI Public Function (De)Crypt(iSph as Integer, strCrypt as String) as String INPUT iSph lettere di sfasamento dell’alfabeto strCrpyt stringa da crittare OUTPUT strCrypted stringa crittata DESCRIZIONE Queste due funzioni crittano e decrittano la stringa passata. 85 Esempi pratici Funzione Find PROTOTIPO Private Function Find(vChar as Variant) as Integer INPUT vChar carattere da cercare OUTPUT i posizione del carattere nell’array Alphabet DESCRIZIONE Questa funzione cerca nell’array Alphabet il carattere passato come parametro. Modulo Polibio Questo modulo contiene le definizioni dei metodi per applicare la scacchiera di Polibio. Anche in questo caso la crittazione viene effettuata sull’intero codice ASCII. Variabili L’unica variabile definita all’interno del modulo è la seguente : • Private Alphabet(15, 15) as String Matrice contenente il codice ASCII. Funzioni Funzioni Crypt e Decrypt PROTOTIPO Public Function (De)Crypt(strCrypt as String) as String INPUT strCrypt stringa da crittare OUTPUT strCrypted stringa crittata DESCRIZIONE Queste due funzioni crittano e decrittano la stringa passata come parametro. In questo caso il risultato della crittazione non sarà una stringa alfabetica ma una stringa alfanumerica. Infatti viene usato il codice esadecimale per definire le righe e le colonne. Funzione Find PROTOTIPO Private Sub Find(vChar as Variant, ByRef iY as Integer, ByRef iX as Integer) INPUT vChar carattere da cercare OUTPUT iY, iX colonna e riga in cui si trova il carattere 86 Esempi pratici DESCRIZIONE La funzione cerca nella matrice Alphabet il carattere passato e ritorna il valore di riga e colonna nelle due variabili iY e iX. Modulo Vigénère Questo modulo contiene le definizioni dei metodi per applicare il cifrario di Vigénère. Anche in questo caso il la crittazione è effettuata sull’intero codice ASCII. Nel cifrario di Vigénère viene utilizzata anche una chiave che in ogni crittazione/decrittazione verrà richiesta dall’applicazione. Variabili L’unica variabile definita all’interno del modulo è la seguente : • Private Alphabet(15, 15) as String Matrice contenente il codice ASCII. Funzioni Funzioni Crypt e Decrypt PROTOTIPI Private Function (De)Crypt(strCrypt as String, strKey as String) as String INPUT strCrypt stringa da crittare strKey chiave OUTPUT strCrypted stringa crittata DESCRIZIONE Queste due funzioni crittano e decrittano la stringa passata come parametro usando la chiave. Funzioni FindRow e FindCol PROTOTIPI Private Sub Findxxx(vChar as Variant, y as Integer x as Integer, ByRef iY as Integer ByRef iX as Integer) INPUT vChar carattere da cercare y,x colonna e riga di partenza OUTPUT iY,iX colonna e riga in cui si trova il carattere DESCRIZIONE Queste due funzioni cercano un carattere sulla linea e sulla colonna passate come parametro. 87 Esempi pratici 4.5 I socket in Linux Al fine di studiare più approfonditamente il protocollo TCP/IP è stato creato un programma che simula una trama del protocollo TCP/IP usato per la comunicazione tra le reti, sia locali che geografiche. Per poter gestire una trama TCP/IP, non è stato possibile usare un compilatore di Windows, poiché esso non permette la gestione a basso livello delle trame. Di conseguenza l’unico modo per controllare i flag del protocollo TCP/IP è stato creare un programma in C proprio del sistema operativo Linux. Infatti esso permette, tramite l’uso dei socket raw, l’uso di funzioni che permettono la gestione diretta delle trame di ricezione e invio. Nel programma si è voluto simulare l’invio di una trama di fine connessione, ossia con il FLAG di FIN =1. All’inizio il programma crea l’header dell’IP , successivamente realizza l’header del TCP della trama che si vuole inviare. Vengono inoltre calcolati i checksum del pacchetto IP e anche dell’header TCP. Parametri del programma Il programma richiede dei parametri in input: 1. porta sorgente 2. indirizzo sorgente 3. porta destinazione 4. indirizzo destinazione Senza questi parametri il programma non può funzionare, causando un segnale d’errore : “usare: porta_sorg. indirizzo sorg. porta dest. indirizzo sorg.” 4.5.1 Implementazione dell’applicazione Di seguito verranno descritte le funzioni più importanti usate nel programma. Funzioni Funzione tcp_gen PROTOTIPO void tcp_gen(char *packet, unsigned short sport, unsigned short dport, unsigned long seq, unsigned long ack) INPUT packet puntatore alla struttura IP sport porta sorgente dport porta destinazione seq numero di sequenza ack acknowledge 88 Esempi pratici DESCRIZIONE È la routine che compone un pacchetto TCP compilando la struttura tcp contenuta nell'header del programma. Questa routine setta il bit di fin a 1 indicando la chiusura della connessione. Dopo aver compilato la struttura la routine calcola il checksum sul pacchetto tcp. Funzione ip_gen PROTOTIPO void ip_gen(char *packet,unsigned char protocol, struct in_addr saddr, struct in_addr daddr, unsigned short length INPUT packet pacchetto, rappresentato dal vettore protocol costante IPPROTO. Indica il protocollo di livello di trasporto per la compilazione della struttura IP saddr indirizzo sorgente daddr indirizzo destinazione length dimensione del pacchetto vettore DESCRIZIONE È la routine che compone l'header IP compilando la struttura tcp contenuta nell'header del programma. Dopo aver compilato la struttura la routine calcola il cheksum sul pacchetto IP. Funzione trans_check PROTOTIPO unsigned short trans_check(unsigned char proto, char *packet, int length, struct in_addr source_address, struct in_addr dest_address) INPUT proto protocollo utilizzato packet puntatore della struttura del TCP header length lunghezza dell’header TCP source_address indirizzo sorgente dest_address indirizzo destinazione OUTPUT La funzione calcola il checksum sul TCP header, che non segue le gerarchie e sono inserite nel suo calcolo anche gli indirizzi IP, che in realtà fanno parte del livello 3 (IP). DESCRIZIONE È la routine che compone un pacchetto TCP compilando la struttura tcp contenuta Funzione in_cksum PROTOTIPO unsigned short in_cksum(unsigned short *addr,int len) 89 Esempi pratici INPUT addr struttura su cui eseguire il checksu len lunghezza di tale struttura OUTPUT answer checksum DESCRIZIONE È la routine che contiene l'algoritmo per il calcolo del cheksum sui pacchetti TCP/IP. Questo algoritmo viene usato per scoprire errori generati da errori di memoria all'interno dei router. Per prima cosa il campo checksum viene posto a 0 e il campo dati viene completato con uno 0 addizionale se la sua lunghezza è un numero dispari poi viene eseguito l'algoritmo che consiste nel sommare tutte le parole di 16 bit che arrivano usando l'aritmetica del complemento a 1 e quindi prendendo il complemento a 1 del risultato. Questo algoritmo del checksum è più potente e da quindi maggiore affidabilità del normale checksum. 4.6 PGP PGP (Pretty Good Privacy) è un programma di crittografia a chiave pubblica, che è diventato lo uno standard per l’utilizzo della crittografia nella posta elettronica. Esso si avvale dell’algoritmo RSA (descritto in precedenza) per crittare i file. Con PGP è possibile codificare un messaggio in modo che solamente il destinatario possa leggerlo ma non una terza persona. Inoltre, è possibile autenticare il mittente ed il messaggio. Questo risponde all’esigenza fondamentale di riservatezza e sicurezza della corrispondenza privata. La corrispondenza per posta elettronica ha da un lato innumerevoli vantaggi ma presenta intrinsecamente un basso grado di sicurezza. Ė infatti molto semplice per una terza persona andare a leggere messaggi privati destinati ad altri, oppure alterare un messaggio inviato da un altro, oppure ancora inviarne uno con il nome di un altro. L’utilizzo di PGP nella crittografia a chiave pubblica Il problema storico della crittografia classica si può riassumere in questo modo : per cifrare un messaggio si deve utilizzare una chiave (segreta) con cui effettuare la cifratura. La stessa chiave deve essere usata per decodificare il messaggio cifrato. Se ‘A’ vuole inviare il messaggio codificato al destinatario ‘B’, ha il problema di fare avere a quest’ultimo la chiave segreta con la quale egli potrà decodificare il messaggio. 90 Esempi pratici Se però ‘B’ sta all’altro capo del mondo e non c’è un canale sicuro per trasmettere la chiave, questo sistema non può funzionare, perché la chiave può essere intercettata. Per esempio, se io non voglio che un messaggio e-mail sia letto da altri, sarebbe inutile codificarlo in modo convenzionale e poi inviare la chiave usata per la codifica ancora per e-mail. Il problema viene risolto brillantemente dalla crittografia a chiave pubblica, alla cui base sta un’idea semplice e geniale. Ogni utente genera, mediante una funzione di PGP, una coppia di chiavi. L’algoritmo matematico che effettua questa operazione è tale che : • un messaggio codificato con una chiave della coppia può essere decodificato solo con l’altra chiave della stessa coppia; • non è materialmente possibile, data una chiave della coppia, ricavare l'altra. Ogni utente tiene per sé una chiave della propria coppia, denominata chiave segreta, e diffonde il più possibile l’altra, denominata chiave pubblica. Questo risolve tutti i problemi posti sopra. Privacy ‘A’ vuole inviare un messaggio a ‘B’, e codifica quel messaggio usando la chiave pubblica di quest’ultimo. Solo ‘B’, che ha la corrispondente chiave segreta, è in grado di decodificare e leggere il messaggio. Autenticazione del mittente ‘A’ codifica il suo messaggio con la propria chiave privata. Chiunque, avendo accesso alla chiave pubblica di ‘A’, può decodificare quel messaggio. Se la decodifica riesce, si è allora sicuri che esso è stato scritto da ‘A’, l’unico a possedere la corrispondente chiave segreta. ‘A’ ha posto la sua "firma" elettronica sul messaggio. Autenticazione del mittente e del messaggio Ė possibile autenticare, facendo un passo in più, oltre al mittente anche il contenuto del messaggio. ‘A’ effettua un "hashing" del suo messaggio. Si tratta di una funzione unidirezionale, che a partire da un certo messaggio ricava un valore di lunghezza fissa, detto hash, che caratterizza il messaggio: una sorta di "checksum". Se il messaggio viene alterato, l'hash non corrisponde più. ‘A’ attacca allora in fondo al suo messaggio il corrispondente hash. ‘A’ può codificare con la propria chiave privata ("firmare") tutto l'insieme, oppure lasciare il messaggio vero e proprio in chiaro e firmare solo l'hash. Chiunque può decodificare l'insieme ricevuto o il solo hash con la chiave pubblica di ‘A’, ed è così sicuro del fatto che il messaggio proviene da quel mittente. 91 Esempi pratici Se inoltre, una volta effettuata la decodifica, messaggio ed hash si corrispondono, si è sicuri che nessuno dei due è stato alterato in qualche maniera. In pratica, la firma elettronica realizzata dal PGP effettua sempre l'autenticazione sia del mittente sia del messaggio. Essa ha dunque le stesse funzioni della firma ordinaria su un documento cartaceo. Trasmissione della chiave Col sistema di crittografia a chiave pubblica non c’è, come nella crittografia convenzionale, una sola chiave usata per entrambe le funzioni di codifica e decodifica, e che deve essere posseduta solo dal mittente e dal destinatario. Pertanto non si pone il problema di dover trasmettere in modo sicuro quella chiave. Ogni utente deve semplicemente tenere al sicuro la propria chiave segreta e può diffondere senza alcun problema la propria chiave pubblica. Anzi, più questa viene diffusa e meglio è. Il PGP consente di effettuare tutte queste funzioni mediante semplici comandi. Ė possibile avere varie funzioni insieme. Due procedure comuni sono per esempio : • la corrispondenza privata firmare un messaggio e contemporaneamente codificarlo per un certo destinatario; • per i messaggi pubblici o privati effettuare l'hash di un messaggio e firmarlo per autenticarne il mittente ed il contenuto, ma lasciando il messaggio stesso in chiaro; questa procedura viene comunemente chiamata firma in chiaro, ed è quello che io ho fatto per il presente testo. Il PGP utilizza in realtà una intera collezione di algoritmi, tra i più sicuri ed internazionalmente conosciuti nel campo della crittografia. Allo scopo di illustrare il processo messo in atto da PGP, supponiamo di partire da un messaggio che deve essere firmato e codificato. La sequenza delle operazioni è la seguente : A. PGP applica l'algoritmo di hashing MD5 per generare l'hash del messaggio, avente lunghezza fissa pari a 128 bit. L'hash viene attaccato al messaggio. B. PGP applica l'algoritmo di compressione dati ZIP per comprimere l'insieme messaggio più hash ottenuto in A. C. PGP applica un algoritmo di generazione numeri casuali per generare una sequenza di 128 bit casuali. 92 Esempi pratici D. PGP applica l'algoritmo di crittografia convenzionale IDEA per codificare il messaggio compresso ottenuto in B, usando come chiave ("session key") il numero casuale generato in C. E. PGP applica l'algoritmo di crittografia a chiave pubblica RSA per codificare la session key. Il risultato viene attaccato al messaggio codificato ottenuto in D. La crittografia convenzionale è molto più veloce di quella a chiave pubblica. PGP unisce i vantaggi della crittografia a chiave pubblica e la velocità di quella convenzionale. Il messaggio viene in realtà codificato convenzionalmente, ed è la session key usata che viene codificata con l'algoritmo a chiave pubblica. PGP applica l'algoritmo ASCII Armor Radix-64 per trasformare il messaggio ottenuto in E in modo che esso contenga solo caratteri ASCII bassi. Questo algoritmo trasforma ogni gruppo di tre bytes in un gruppo di quattro bytes. Il messaggio ottenuto in F è quello finale, che può essere inviato per e-mail. Il destinatario esegue la sequenza inversa di operazioni. Gli algoritmi utilizzati da PGP sono considerati assolutamente sicuri. Per esempio, l'algoritmo di crittografia a chiave pubblica RSA si basa sul prodotto di due numeri primi. Per poter ricavare una chiave privata dalla corrispondente chiave pubblica occorrerebbe fattorizzare questo prodotto. Nel caso di chiavi a 1024 bit, è stato stimato che una rete di un milione di computers impiegherebbe 10^10 anni a risolvere il problema, un tempo pari all'età dell'universo! Poi, ci sarebbe ancora il problema di ricavare la pass phrase. E questo per una sola coppia di chiavi tra tutte quelle esistenti al mondo. Esempio pratico dell’utilizzo del PGP La prima cosa da fare è installare il programma, lo si può trovare su Internet ed è scaricabile gratuitamente (per scopi non commerciali, su www.pgpi.com) . Dopo aver scaricato il file .zip basta scompattarlo in una directory a piacimento e settare il parametro path del DOS nel modo seguente : • SET PATH = C:\<dir>%PATH% • SET TZ = C:\<dir> 93 Esempi pratici La prossima operazione sarà la generazione delle chiavi. Per generare la coppia di chiavi si utilizza il comando: pgp -kg PGP chiede di : 1. Scegliere la lunghezza delle chiavi. Vengono proposte tre possibilità, delle quali la terza genera chiavi di 1024 bit. Con la versione internazionale 2.6.3i è possibile generare chiavi della lunghezza di 2048 bit digitando appunto il numero 2048 invece di scegliere una delle tre alternative proposte. La generazione di chiavi da 2048 bit, non è possibile su un sistema particolarmente lento, in questo caso è preferibile generare chiavi a 1024 bit. Figura 4.9 : Creazione delle chiavi con PGP (passo 1). Nell’esempio che stiamo effettuando è stata scelta una chiave di 1024 bits. 2. Inserire la User ID In questo passaggio verrà scelto lo "User Name", chiamato anche "User ID". Generalmente, si usa nome e cognome seguito dall'indirizzo e-mail in parentesi angolari : Castiglioni Marco <[email protected]> (E' possibile assegnare alle chiavi più identificativi, cosa che si fa quando si hanno più indirizzi e-mail, per esempio.) Questo è ciò che viene anche suggerito a video dall’help di PGP, ed è la cosa preferibile. In alternativa, se è facile che il vostro indirizzo e-mail cambi, per creare il vostro "User Name" potete far seguire il vostro nome e cognome, anziché dall'indirizzo e-mail, da un qualunque altro dato che vi identifichi. 94 Esempi pratici 3. Inserire l a pass phrase E' molto importante, perché si tratta della frase d’accesso che permette di utilizzare la chiave segreta, senza la pass phrase la vostra chiave segreta è inutilizzabile. E' una password estesa : può essere un testo molto lungo contenente qualunque carattere. Scegliete una frase lunga che non sia intuibile, ma deve però trattarsi di una frase costruita in modo che sia facile da ricordare. Figura 4.10 : Creazione delle chiavi con PGP (passo 2). 4. Premere dei tasti casualmente Dovranno essere premuti dei tasti in modo casuale. In questo modo PGP, in base alla velocità di pressione dei tasti, calcolerà un numero casuale di 504 bits. Figura 4.11 : Creazione delle chiavi con PGP (passo 3). 95 Esempi pratici Figura 4.12 : Creazione delle chiavi con PGP (passo 4). A questo punto, PGP genera la vostra coppia di chiavi. Esse saranno contenute nei file secring.pgp (secret ring) per quella segreta, pubring.pgp (public ring) per quella pubblica. In questa versione del PGP non è necessario firmare la chiave pubblica poiché viene fatto direttamente con l’inizializzazione della chiave. Nelle vecchie versioni bisogna utilizzare il comando pgp –ks “ID” dove ID è l’identificativo dell’utente, per esempio la User Name. Per visualizzare le chiavi pubblica si utilizza il comando pgp -kv, così facendo viene visualizzata la chiave il giorno della sua creazione il tipo di chiave (numero di bit utilizzati) e l’user id. Figura 4.13 : Visualizzazione della chiave pubblica. 96 Esempi pratici Utilizzando il comando pgp -ka “ID” <percorso> si può vedere la chiave pubblica. Figura 4.14 : Estrazione della chiave pubblica. Di seguito è riportata la chiave pubblica. Type Bits/KeyID Date User ID pub 1024/B1B74DA1 2002/05/19 <[email protected]> -----BEGIN PGP PUBLIC KEY BLOCK----Version: 2.6.3ia mQCNAzznyGsAAAEEAPTc2A3d/TbAMJZww89t6Z/qiC/5asH mH2qgnqnHOtdjUXg9KWAG8wb2a4S4gIbrhpHfy9OtVFxujNgdR yQ5w8ayBDr6hO5v9gjO4+6qJKLavDqw7fpq0YsKOz++Ts7P4Zq v9e5EtZHRmKSupR8Tb/7vF14BnVvn5ragcraxt02hAAURtA88Y2 FzdGlAbXNuLmNvbT6JAJUDBRA858hrtqBytrG3TaEBAb5oA/9 rFrqrd4Y62352MrgttlJgh+Ou8xuIG0/HYAoB+M0IlbVXE5vYY9 1RC6KQsTYVgpv/sOd1/flDZMKokDoRq6IElKE3w7EHHn/r3A CRAYfk9hTkc6PPq0P2IKZ1JzZJHVpslOct9EVtaIwXrClsQXb0K LbM0FG9g7TpenLgoksKdg===zMPX -----END PGP PUBLIC KEY BLOCK----Dopo di che è possibile crittare e decrittare un file di testo. Il comando da utilizzare per crittare il testo è : pgp –esta C:\percoso • • Se si omette l'opzione "s" (sign), quindi digitate -eta, il file viene codificato, ma non firmato. Se si omette l'opzione "e" (encrypt), quindi digitate -sta, il file viene firmato in chiaro, ma non codificato. 97 Esempi pratici Non è detto che il file da codificare e/o firmare sia un testo, bensì può essere indifferentemente un file binario qualunque. PGP chiede in ogni caso di digitare la vostra pass phrase, in modo da poter utilizzare la vostra chiave segreta. Ė importante che il comando per codificare e/o firmare (nonché quello per estrarre la vostra chiave pubblica) contenga sempre l'opzione "a" (ASCII Armor), come si vede dal comando riportato sopra. Questo perché quando si invia un file per e-mail, esso passa attraverso e arriva su sistemi di tipo molto diverso. Qualunque sistema però è in grado di riconoscere e trattare caratteri ASCII il cui codice decimale è compreso tra 0 e 127 (il cosiddetto ASCII basso). Perciò è indispensabile che un file inviato per e-mail sia formato esclusivamente da tali caratteri (file ASCII armored o semplicemente ASCII), e non da caratteri qualsiasi. PGP trasforma, mediante l’opzione "a", il file prodotto in modo che sia ASCII armored. Figura 4.15 : Crittazione di un file (passo 1). Dopo di che il PGP chiederà di riscrivere la vostra password segreta, in seguito viene anche chiesto l’user ID, dopo di che verrà creato il file crittato. 98 Esempi pratici Figura 4.16 : Crittazione di un file (passo 2). Il file di testo crittato è il seguente: -----BEGIN PGP MESSAGE----Version: 2.6.3ia hIwDtqBytrG3TaEBA/42ma+Cg8giyBNS5hA31/2LHgp8xj0EHv4 PUrFuwlYc4jNCdTQUklqHdhkLh8WSIzx12ps7ucjs18H4+Mn1vY qOKp4W1pt5OxZ5gD8V0yrFOnhkWzxA+59acHgUAcuLARmTU gflkmSdDtfaWLKR+ojHDJt8rvevfaroIT2WQsejLKYAAAE3ixIbp Is10lfjG2Re3XRXKRzwHd/bhpFZIjcU5jv3gJtTnMb8gdj3Kscv8N UG+l1W2DKNVuCWryoN7+8llHOn9xERkTa5VdnMjaI9jnmgd4c cOZjaTFonmJEXVkKUGFlH1DasvsHriezxzcsRobg0y1SWl4yHc0 kbkDTEWfgz+GJQO9d+GOy19sxUXy6v/Hi7dQEXr0PhOjBfmx LW1+3U76ZIejzfX/fr7cPUU4Kin2qv85PUZ5AJMZMLLSVNO3 ObOFqTeweanlaYUTPagFL5IdAC6yU5eZ4eCa/1djFh27IkIxqXIE b2o+LpvRklKwVlSxJ2sXb/BayQbrHOM5gw0QsyZOhj+CP9NOt MXD9vsPk+Z526h5l2uU86yapABeJTu7YZBdhgRVAq5KqHYdG WfdLinPWvtK0==qHft -----END PGP MESSAGE----Per decodificare il file si dovrà utilizzare il seguente comando: pgp C:\percoso 99 Esempi pratici Figura 4.17 : Decrittazione di un file. Dopo questa operazione il file viene decodificato e il testo può comparire in chiaro. Qui sotto il testo è riportato in chiaro: Questa è la mia area di progetto questo è un file di testo fatto per provare il programma che critta e decritta i messaggi di posta elettronica PGP! Questo comando ha molteplici funzioni, perché agisce indifferentemente su codifica e firma. Se il messaggio di partenza era codificato, il comando citato lo decodifica. Se in aggiunta esso era anche firmato, il comando verifica inoltre la firma (e quindi l’autenticità del mittente e del messaggio stesso). Se era solo firmato, viene semplicemente verificata la firma. 100 Conclusioni CONCLUSIONI Dr. M : “Che difficoltà avete incontrato nello sviluppare l’area di progetto?” Pozzetti : “La difficoltà maggiore incontrata è stata lo sviluppo del DES. La manipolazione bit per bit usata dal DES rendeva più adatto lo sviluppo dell’algoritmo in Assembler.” Castiglioni : “Per quanto riguarda la parte storica riguardante la seconda guerra mondiale non ci sono stati problemi, mentre per quanto riguarda la parte della storia della crittografia ho incontrato alcuni problemi: a causa dell’abbondanza di informazioni si è dovuto estrapolare solo lo stretto necessario. Nella prova pratica con il PGP le difficoltà incontrate riguardano l’applicazione delle istruzioni, infatti alcune di esse riportate nell’help erano errate.” Trevisan : “Ho incontrato difficoltà nel programma in Linux, legatiall’uso dei socket raw. Studiando la crittografia di Outlook Express non è stato possibile verificare con esempi pratici l’utilizzo della firma elettronica e degli algoritmi crittografici, poiché non si disponeva di un ID digitale.” Dr. M : “Cosa avete imparato di nuovo durante lo sviluppo dell’area di progetto?” Pozzetti. : “Per quanto riguarda la programmazione ho imparato a programmare utilizzando Visual C++, in particolare è stato utile l’uso di Winsock. Nel campo della crittografia sono venuto a conoscenza degli algoritmi più usati quali il DES e l’RSA e alcune delle tecniche che nel futuro renderanno sempre più sicura la comunicazione via Internet.” Castiglioni: “Nella parte storica, ho scoperto quando è nata la crittografia e l’utilità che è riuscita a conquistarsi nel corso degli anni e dei secoli. Per quanto riguarda la parte applicativa, ho lavorato con il programma PGP, che permette la codifica e decodifica dei messaggi. Mi è servito per vedere praticamente e non solo teoricamente come funziona un programma per la crittografia.” Trevisan : “Ho approfondito il protocollo TCP/IP, sia teoricamente sia praticamente, costruendo un programma che simulasse una trama TCP/IP.” Dr. M : “Come ampliereste la vostra area di progetto?” Pozzetti. : “Nella parte crittografica sono state tralasciate importanti parti, come la simulazione delle macchine cifranti usate durante la seconda guerra mondiale, 101 Conclusioni oppure lo studio più approfondito di alcuni algoritmi come l’RSA, trattato solo marginalmente. In particolare mi sarebbe piaciuto realizzare una simulazione della macchina Enigma e della Bomba di Turing per rendere meglio l’idea del lavoro effettuato dagli Alleati e dal’Asse nello sviluppo dell crittografia.” Trevisan : “Nella parte della sicurezza sarebbe stato utile approfondire ulteriormente i metodi di attacco degli hacker, poiché solamente in questo modo si possono migliorare i metodi realativi alla sicurezza. D’altra parte era impossibile trattare tutti gli argomenti in modo dettagliato, poiché l’area di progetto comprendeva argomenti ampio raggio.” Castiglioni: “Vorrei aggiungere ancora delle parti sulla storia della crittografia, sulla utilità che ha avuto nella seconda guerra mondaile e che sta avendo tuttora in internet. Vorrei applicare il PGP, nella posta elettronica, anche se è difficile ottenere il permesso dalla autorità competenti.” Dr. M : “Qual è stata la fonte primaria di informazioni?” C., P., T. : “Internet e relativi manuali.” Dr. M : “Ognuno commenti il lavoro altrui.” Pozzetti. : “Il lavoro svolto da Castiglioni relativo alla storia e alle basi della crittografia è stato veramente impegnativo, soprattutto la ricerca di materiale è stata difficoltosa. Alla fine ci si è ritrovati con più informazioni di quante ne servissero. Inoltre la sua parte di lavoro mi è servita per comprendere meglio il funzionamento di alcuni algoritmi crittografici, permettendomi di implementarne alcuni nelle applicazioni sviluppate. Il lavoro di Trevisan è stata la base per lo sviluppo dell’applicazione di scambio per i messaggi crittati, che è stata integrata con il DES.” Castiglioni: “ La parte svolta da Trevisan è stata molto utile per capire come avviene lo scambio dei messaggi crittati tra due utenti. Il lavoro di Pozzetti è stato importatntissimo, poiché grazie ad esso, si può vedere come vengono crittati i messaggi con l’algoritmo DES, è stato un lavoro molto lungo e complesso, ma che è stato svolto con molta professionalità.” Trevisan : “Entrambi le altri parti sono state molto complete; la 102 Conclusioni parte di Pozzetti, che comprendeva principalmente la crittografia, è stata molto complessa ed è stata svolta in modo particolareggiato e professionale; Castiglioni è stato molto preciso e particolareggiato nella parte storica, mentre la sua descrizione riguardante il PGP è stata utile ad un suo utilizzo pratico.” Dr. M : “Come è stato lavorare in gruppo?” Pozzetti. : “Lavorando in gruppo la cosa più importante da tenere in conto è la divisione del lavoro. Se il lavoro viene diviso in maniera esatta all’ora il tutto fila via liscio, altrimenti, ci si ritrova a sprecare tempo, tralasciando alcune parti che alla fine ci si ritroverà ad affrontare con l’acqua alla gola. Un’altra cosa estremamente importante è avere già in mente il flusso del lavoro, ovvero conoscere precisamente gli argomenti da affrontare, in modo da non ritrovarsi a metà dello sviluppo con un’idea che non coincide per nulla con quello che si aveva in mente all’inizio.” Castiglioni: “ E’ stata un’esperienza molto utile, ci ha fatto capire cosa vuol dire lavorare in gruppo. Con il lavoro di gruppo ci si può confrontare, si chiedere aiuto ai propri compagni, che ti sanno aiutare e consigliare. Ed è molto gratificante mettere a disposizione le proprie conoscenze per la buona riuscita del lavoro.” Trevisan : “E’ stata un’esperienza stimolante, poiché si impara a comunicare con gli altri per suddividere il lavoro e proporre le proprie idee.” Dr. M : “Che conclusioni avete tratto dallo sviluppo dell’area di progetto?” Pozzetti. : “Personalmente credo che il mondo della crittografia sia molto affascinante, sia per quanto riguarda il lato “buono” sia per quanto riguarda il lato “cattivo”. Purtroppo la crittoanalisi (lato “cattivo”) non è stata affrontata nel modo che meritava, lasciando un po’ di amaro in bocca. La stessa affermazione può valere per le comunicazione via socket. Gli argomenti trattati in questo campo sono stati veramente pochi, soprattutto a causa del poco tempo a disposizione.” Castiglioni: “Dall’analisi che abbiamo fatto sulla crittografia, si può dire che essa prenderà sempre più parte nel mondo di internet, questo per avere una maggiore sicurezza, che permetterà di scambiare informazioni o di compiere transazioni in tutta sicurezza.” Trevisan : “Penso che analizzando la sicurezza informatica, si 103 Conclusioni possa notare che sia un campo in continua espansione e sviluppo. Quindi è molto difficile essere aggiornati, ma risulta interessante e stimolante.” Dr. M : “Definite con poche parole la vostra area di progetto.” Pozzetti. : “Una base per chi vuole incominciare a conoscere il mondo della crittografia.” Castiglioni: “Può essere una base per chi si vuole avvicinare al mondo della crittografia e un aiuto per chi si è già avvicinato alla crittografia e ne vuole sapere di più. Trevisan : “L’area di progetto è stata sviluppata in varie parti: storico, gestione di rete e crittografia. Alla parte teorica si affianca una parte di programmazione in vari linguaggi. L’argomento pur risultando molto ampio e complesso è stato cercato di essere trattato in modo completo.” 104 Appendice A Appendice A SSL 1 2 Cos’è l’SSL Creazione di una connessione SSL 1 Cos’è l’SSL SSL (Secure Socket Layer protocol) è un protocollo aperto e non proprietario; è stato sottoposto da Netscape Communications all'Engineering Task Force per la sua standardizzazione, anche se di fatto è stato accettato come uno standard da tutta la comunità di Internet ancor prima del verdetto dell'IETF. La versione 3.0 del protocollo rilasciata nel novembre 1996, è un'evoluzione della precedente versione del 1994 la SSL v2.0, e rappresenta al momento una delle soluzioni più utilizzate per lo scambio di informazioni cifrate. Tale evoluzione introduce un livello di sicurezza superiore rispetto alla precedente grazie ad una maggiore attenzione nella fase di autenticazione tra client e server. Il futuro di SSL è rappresentato dal protocollo TLS v1 (SSL v3.1) sottoposto a standardizzazione nel novembre 1998. Il protocollo SSL è nato al fine di garantire la privacy delle comunicazioni su Internet, infatti permette alle applicazioni client/server di comunicare in modo da prevenire le intrusioni, le manomissioni e le falsificazioni dei messaggi. Il protocollo SSL garantisce la sicurezza del collegamento mediante tre funzionalità fondamentali : • privatezza del collegamento: per assicurare un collegamento sicuro tra due utenti coinvolti in una comunicazione, i dati vengono protetti utilizzando algoritmi di crittografia a chiave simmetrica (ad es. DES, RC4, ecc.); • autenticazione: l'autenticazione dell'identità nelle connessioni può essere eseguita usando la crittografia a chiave pubblica (per es. RSA, DSS ecc.). In questo modo i client sono sicuri di comunicare con il server corretto, prevenendo eventuali interposizioni. Inoltre è prevista la certificazione sia del server che del client; • affidabilità: il livello di trasporto include un controllo sull'integrità del messaggio basato su un apposito MAC (Message Authentication Code) che utilizza funzioni hash sicure (per es. SHA, MD5 ecc.). In tal modo si verifica che i dati spediti tra client e server non siano stati alterati durante la trasmissione. 105 Appendice A Il protocollo SSL è composto da : • protocollo SSL handshake, permette al server ed al client di autenticarsi a vicenda e di negoziare un algoritmo di crittografia e le relative chiavi prima che il livello di applicazione trasmetta o riceva il suo primo byte. Un vantaggio di SSL è la sua indipendenza dal protocollo di applicazione, in tal modo un protocollo di livello più alto può interfacciarsi sul protocollo SSL in modo trasparente; • protocollo SSL record, è interfacciato su di un protocollo di trasporto affidabile come il TCP. Questo protocollo è usato per l'incapsulamento dei dati provenienti dai protocolli superiori. Figura 1 : SSL è un protocollo a due strati, SSL Record a livello inferiore ed SSL Handshake a livello superiore, che si interfaccia con una applicazione ad esempio HTTP. 2 Creazione di una connessione SSL SSL prevede una fase iniziale, detta di handshake, usata per iniziare una connessione TCP/IP. In particolare il risultato di tale fase è l'avvio di una nuova sessione che permette la contrattazione da parte del client e del server del livello di sicurezza da usare ed il completamento delle autenticazioni necessarie alla connessione. Quindi SSL procede con la cifratura (e/o con la messa in chiaro) della sequenza di byte del protocollo applicazione usato, ad esempio nell'HTTP tutte le informazioni sia di richiesta che di risposta sono completamente cifrate, incluso l'URL richiesto dal client, qualsiasi contenuto di form compilati (quindi anche eventuali numeri di carte di credito...), ogni informazione sulle autorizzazioni all'accesso come username e password, e tutti i dati inviati in risposta dal server al client. Il protocollo SSL usa una combinazione di chiavi pubbliche e chiavi simmetriche. La cifratura a chiave simmetrica è molto più veloce della cifratura a chiave pubblica, anche se quest'ultima provvede ad una tecnica di autenticazione migliore. Una sessione SSL inizia sempre con uno scambio di messaggi chiamati di SSL handshake. L'handshake consente al server di autenticarsi al client usando una tecnica a chiave pubblica, quindi permette al client ed al server di cooperare per la 106 Appendice A creazione delle chiavi simmetriche usate per una veloce cifratura, decifratura e controllo delle intrusione durante la sessione avviata. Eventualmente, l'handshake permette anche al client di autenticarsi al server. Nel protocollo SSL Handshake l'avvio di una nuova connessione può avvenire o da parte del client o da parte del server. Se è il client ad iniziare, allora questo invierà un messaggio di client hello, iniziando così la fase di Hello, e si porrà in attesa della risposta del server che avviene con un messaggio di server hello. Nel caso in cui sia il server ad iniziare la connessione, questo invierà un messaggio di hello request per richiedere al client di iniziare la fase di Hello. Con lo scambio di questi messaggi, il client ed il server si accorderanno sugli algoritmi da usare per la generazione delle chiavi; in particolare il client ne proporrà una lista, quindi sarà il server a decidere quale di essi dovrà essere utilizzato. A questo punto può iniziare o meno, a seconda del metodo di autenticazione impiegato (autenticazione di entrambe le parti, autenticazione del server con client non autenticato, totale anonimato), uno scambio di certificati tra client e server. L'autenticazione è un controllo che si può effettuare per provare l'identità di un client o di un server. Un client abilitato può controllare che il certificato del server sia valido e che sia stato firmato da un'autorità fidata. Questa conferma può essere utile, per esempio, se un utente invia il numero di carta di credito e vuole controllare l'identità del ricevente. Allo stesso modo un client può essere autenticato, questo potrebbe essere utile se il server è ad esempio una banca che deve inviare dati finanziari confidenziali ad un suo cliente che necessita quindi di essere autenticato. E' importante notare che sia l'autenticazione del client che quella del server implica la cifratura di alcuni dati condivisi con una chiave pubblica o privata e la decifratura con la chiave corrispondente. Nel caso dell'autenticazione del server, il client deve cifrare dei dati segreti con la chiave pubblica del server. Solo la corrispondente chiave privata può correttamente decifrare il segreto, così il client ha delle assicurazioni sulla reale identità del server poichè solo lui può possedere tale chiave. Altrimenti il server non potrà generare le chiavi simmetriche richieste per la sessione, che verrà così terminata. In caso di autenticazione del client, questi deve cifrare alcuni valori casuali condivisi con la sua chiave privata, creando in pratica una firma. La chiave pubblica nel certificato del client può facilmente convalidare tale firma se il certificato è autentico, in caso contario la sessione verrà terminata. Avvenuta l'autenticazione si procede con la generazione delle chiavi per la cifratura e per l'autenticazione dei dati provenienti dal livello di applicazione, tutto questo attraverso i messaggi di server key exchange e client key exchange. Terminata questa operazione, il server annuncerà la fine della fase di Hello al client, con l'invio di un messaggio di server hello done, dopodichè con l'invio di un messaggio di change CipherSpec entrambi 107 Appendice A controlleranno la correttezza dei dati ricevuti e se tutto è avvenuto in maniera corretta, da questo punto in poi useranno gli algoritmi di sicurezza concordati. La fase di handshake terminerà con l'invio, da entrambe le parti, di un messaggio di finished che sarà il primo dato ad essere cifrato. 108 Appendice B Appendice B La firma digitale 1 2 3 Lo standard DSS e l’algoritmo DSA Protocolli di sicurezza Sistemi di autenticazione 1 Lo standard DSS e l’algoritmo DSA Il National Institute of Standards and Technology (NIST) ha pubblicato il Digital Signature Algorithm (DSA) nell'ambito del Digital Signature Standard (DSS) che è parte del progetto Capstone attuato dal Governo degli Stati Uniti. DSS è stato scelto nel maggio 1994 dal NIST in collaborazione con l' NSA come standard di firma digitale del Governo degli USA. DSA è basato sul problema dei logaritmi discreti ed è in relazione con gli schemi di firma proposti da Schnorr ed El Gamal. DSA può essere utilizzato soltanto per la firma digitale contrariamente ad RSA, utilizzabile sia per la digital signature che per la codifica e la privacy. Nel DSA la generazione della firma è più veloce della verifica della stessa, mentre con RSA la verifica è sensibilmente più veloce della generazione, per via delle diverse dimensioni degli esponenti pubblico e privato. La scelta di rendere più veloce la fase di firma o la fase di verifica può essere oggetto di discussione e di studio, come si può apprezzare nei lavori di Wiener e Naccache che hanno cercato dei compromessi per equilibrare la velocità delle due fasi ed hanno esplorato le possibilità di miglioramento dell'efficienza di DSA. Anche se molti degli aspetti peculiari di RSA sono stati criticati sin dal momento del suo annuncio, esso è stato incorporato in un grande numero di sistemi. Le critiche mosse inizialmente si focalizzavano su pochi argomenti principali: mancava la flessibilità dell' algoritmo RSA; la verifica delle firme era troppo lenta; l'esistenza di un algoritmo diverso dallo standard RSA poteva influenzare negativamente il mercato; il procedimento per cui il NIST sceglieva DSA era poco chiaro, arbitrario e fortemente influenzato dall' NSA. Un altro argomento scottante è quello della sicurezza dell'algoritmo. Originariamente proposto dal NIST con una chiave fissa di 512 bits, dopo molte critiche per l' eventuale mancanza di sicurezza a lungo termine, dovuta alla lunghezza troppo ridotta della chiave, il NIST ha rivisto lo standard DSS ed ha introdotto chiavi della lunghezza di 1024 bits. Oggi DSA è considerato sicuro con chiavi di 1024 bits. Al giorno d' oggi non si conoscono attacchi efficienti portati al problema dei logaritmi discreti, che sorregge lo schema crittografico di DSA. 109 Appendice B 2 Protocolli di sicurezza Molti protocolli sono stati realizzati per la sicurezza delle comunicazioni via Internet, alcuni dei quali sono : • S/MIME S/MIME (Secure / Multipurpose Internet Mail Extensions) è un protocollo che aggiunge firma digitale e cifratura ai messaggi standard MIME. MIME è lo standard proposto per la posta elettronica avanzata. I messaggi di posta elettronica consistono di due parti : un’intestazione, che contiene informazioni vitali per la spedizione del messaggio e un corpo, che non ha nessun formato particolare, a meno che il messaggio non sia nel formato MIME. Questo formato, infatti, fornisce una struttura anche al corpo, ed è quindi possibile inviare testo, audio, immagini ed altri elementi multimediali. Lo standard MIME da solo non è in grado di fornire una sicurezza sufficiente all' utente e quindi si è creato il protocollo S/MIME che quindi cripta il corpo della mail rendendola indecifrabile a terzi. • S/WA La S/WAN (Secure Wide Area Network) è un' iniziativa nata per promuovere lo sviluppo e la diffusione delle VPNs Virtual Private Networks basate su Internet e su protocollo IP. Questo risultato è ottenuto adottando lo standard IP/Sec, l'architettura di sicurezza del protocollo IP. In questo modo si può garantire l'interoperabilità con firewall e prodotti basati su protocolli TCP/IP. S/WAN supporta la codifica a livello di protocollo IP, per cui può fornire una sicurezza più a bsso livello rispetto a protocolli quali SSL. S/WAN utilizza l'algoritmo RC5 con chiavi della lunghezza compresa tra 40 e 128 bits. • IP/Sec Il gruppo di lavoro IP Security Protocol (IP/Sec), facente parte dell' Internet Engineering Task Force (IETF), sta definendo un insieme di specifiche per l' autenticazione basata sulla crittografia per introdurre un alto livello di sicurezza e segretezza al livello di trasmissione datagram su Internet. I risultati di queste specifiche comprenderanno un elevato livello di sicurezza delle trasmissioni host-to-host, tunnels incapsulati e la definizione di Virtual Public Networks (VPNs) che fornirannosicurezza ai protocolli residenti ai livelli superiori rispetto al protocollo IP. I formati dei protocolli per l' IP/Sec Authentication Header (AH) e per IP Encapsulating Security Payload (ESP) sono indipendenti dall'algoritmo di codifica adottato, permettendo quindi una larga interoperabilità. 110 Appendice B 3 Sistemi di autenticazione In un ambiente di rete in cui molti utenti vogliono comunicare reciprocamente sono necessari dei protocolli che garantiscano sicurezza, riservatezza, trasparenza e velocità nelle transazioni. Di seguito sono presentate le soluzioni più usate oggigiorno : • SSH SSH (Secure Shell) è un programma che permette di connettersi ad un altro computer attraverso una rete, eseguire comandi su una macchina remota e spostare files da una macchina all'altra il tutto in maniera sicura. Fornisce solide autenticazioni e comunicazioni sicure su canali insicuri. Può essere visto come un rimpiazzo delle istruzioni rlogin, rsh, e rcp. SSH gestisce connessioni di tipo X sicure e si interfaccia a connessioni TCP già esistenti. Protezioni fornite da SSH 1. 'IP spoofing' (truffa dell'IP) : quando un host remoto vuole spedire pacchetti verso un host autenticato, SSH protegge contro truffatori che, sulla rete locale, pretendano di essere i router verso l'esterno; 2. 'IP source routing' : un host può pretendere che un pacchetto IP arrivi da un host autenticato e ciò deve essere garantito da SSH; 3. 'DNS spoofing ': un hacker tenta di forzare i record del name server; 4. Intercettazione di password in chiaro e altri dati non crittati da parte di host intermedi; 5. Manipolazione dei dati da parte di persone che possiedono il controllo di host intermedi; 6. Attacchi basati sull'ascolto di autenticazioni X e sull'utilizzo successivo di queste ultime per ottenere false connessioni al server X11. Protezioni non garantite da SSH SSH non dà aiuto a fronte di attacchi alla sicurezza del proprio host di altro genere. Così, se un hacker ha ottenuto l'accesso alla root della macchina, può sovvertire lo stesso SSH. Se qualcuno ha accesso alla nostra home directory, la sicurezza diventa inesistente. Questo può accadere nel caso in cui la nostra home directory venga esportata via NFS. Tutte le comunicazioni di SSH usano IDEA o uno degli altri protocolli simmetrici (three-key triple-DES, DES, Blowfish). Le chiavi segrete vengono scambiate usando RSA, e i dati relativi alle chiavi scambiate vengono distrutti ogni ora (le chiavi non vengono salvate da nessuna parte). Ogni host ha la propria chiave RSA che viene usata per autenticare l'host stesso 111 Appendice B (quando si usa un'autenticazione tipo RSA). La codifica è usata come protezione contro l'IP spoofing; l'autenticazione a chiave pubblica è usata a fronte del DNS e del routing spoofing. • NIS+ NIS+ Overview : NIS+, acronimo di Network Information Service, e' un'evoluzione del servizio NIS entrambi trademark di Sun Microsystems (quest'ultimo nome sostitui' l'originale YP (Yellow Pages) per ragioni di copyright). L'obiettivo di NIS era diminuire l'insieme di informazioni (di uno stesso cluster) replicate su piu' host, propagandole sottoforma di tabelle, in modo da ottenere una gestione centralizzata dei dati. NIS+ evolve questo concetto aggiungendo un meccanismo di autorizzazzione e autenticazione per tutti i client richiedenti tali informazioni. La prima differenza tra i due tipi di servizio e' l'organizzazione dell'insieme di informazioni riguardanti macchine e utenti, indicato col nome di "namespace" "flat" con NIS e "hierarchical" con NIS+. Il namespace puo' essere visto come un albero la cui radice ha due foglie ed eventuali rami ad ognuno dei quali e' attaccato un nodo figlio. Ogni nodo figlio (compresa la radice) ha due foglie costituite da due sottodirectory virtuali chiamate "groups_dir" e "org_dir"; la prima contiene eventuali sottogruppi NIS+ e la seconda varie tabelle. Secondo la definizione un "NIS+ domain" e' l'insieme del nodo figlio (sia radice o semplice nodo interno), delle due sottodirectory e delle tabelle. NIS+ rende possibile la creazione di suddivisioni tra loro indipendenti del namespace, riferiti di solito col nome di "subddomain". NIS+ Security : l'accesso al namespace e': consentito ai "NIS+ principals", fatto rispettare dai "NIS+ servers" e soggetto ai permessi di ciascun object. Un NIS+ principal e' un utente o una macchina le cui credenziali sono presenti nel namespace. Quando un client (utente o macchina) manda una richiesta al server, vi inserisce automaticamente le credenziali di NIS+ principal. Il server a sua volta accodera' tale richiesta in una delle due categorie: autenticata o non utenticata, rispettivamente per le richieste generate da principal per i quali il server ne riconosce l'identita', e per le quali il server non riesce (client qualsiasi). L'accesso ad un NIS+ object differisce a seconda della coda in cui si trova la richiesta ed avviene in base ai permessi associati alle quattro azioni possibili divise per categorie. Ognuna di queste categorie specifica una "authorization category" differente. Per le richieste nella prima coda si hanno le categorie Owner, Group e World, mentre per quelle nella seconda la Nobody. I possibili permessi in ogni categoria sono quattro e indicano rispettivamente la possibilita' di leggere (r), modificare (m), creare (c) e distruggere (d) un oggetto; tutto cio' in perfetta similitudine con quanto avviene per il meccanismo di accesso ai file nel sistema operativo UNIX. Si noti che oltre ai permessi propri di ogni oggetto (facenti parte della sua definizione) e' anche possibile specificare altri permessi per ogni colonna o entry di una tabella NIS+ (con alcune limitazioni). 112 Appendice B • Kerberos Authentication System Kerberos e' un servizio di autenticazione distribuito il cui compito è permettere ad utenti di workstations l'accesso alle risorse di rete in modo sicuro. Kerberos deve dunque gestire i permessi dei vari user inibendo la possibilità che qualcuno riesca a spacciarsi per qualcun'altro. Kerberos appartiene alla categoria "authentication for real - time" intendendo con questo termine che il processo client rimane in attesa di una risposta in modo da poter dare i risultati all'utente, questo implica una rapida risoluzione del problema di autenticazione per evitare lunghe attese. Applicazioni che richiedono questo tipo di autenticazione sono : rlogin, file system r/w, information retrieval su Web etc. Kerberos fu sviluppato a meta' degli anni 80 come parte del progetto Athena al MIT ma succesivamente furono necessarie delle modifiche per supportare nuove politiche e metodi di utilizzo, attualmente e in fase di sviluppo la versione 5 (V5) che viene considerata essere il "Kerberos standard" anche se la V4 viene utilizzata in molti siti nel mondo. Essenzialmente Kerberos si basa sull'utilizzo di chiavi per criptare le informazioni scambiate tra le entita' che partecipano al protocollo di autenticazione. Il metodo di crittografia utlizzato da Kerberos V4 e' il DES (Data Encryption Standard) che ha la caratteristica di avere la stessa chiave sia per codificare che per decodificare. 113 Appendice C Appendice C Crittografia quantica 1 2 Fondamenti sui quanti e sui fotoni Crittografia quantica 1 Fondamenti sui quanti e sui fotoni Prima di iniziare a parlare della crittografia quantica è meglio precisare il termine "quanto" : un osservatore attento può notare che il termine più vicino alla parola quanto è quantità. All'inizio del secolo i fisici hanno notato che c'era qualcosa di sbagliato nella teorica classica, per essere più precisi, essi hanno notato che la loro prospettiva delle particelle fondamentali non coincideva con quella rilevata dagli esperimenti fatti. La conclusione logica fu che c'era qualcosa di errato nella classica concezione di atomo. Max Planck introdusse per primo un nuovo approcio al problema. Nella fisica classica, gli elettroni orbitano attorno al nucleo dell'atomo e possono avere una qualsiasi energia e di conseguenza orbitare a qualsiasi distanza da esso. Il problema che generò questa idea è che l'elettrone, carico negativamente e il nucleo (composto da protoni, carica positiva e neutroni, carica neutra) carico positivamente, potessero collassare. Più precisamente si credette che l'elettrone avrebbe potuto collassare nel nucleo per circa 0.0000000001 secondi, a causa delle cariche opposte assunte da elettrone e nucleo. La risposta fu che l'elettrone non avrebbe potuto avere qualsiasi energia mentre orbita attorno al nucleo. L'energia dell'elettrone è il quanto. Questo significa che l'elettrone ha un'energia strettamente definita e può orbitare solamente ad alcune distanze dal nucleo. Per essere più precisi, tutto questo non è propriamente vero, l'elettrone non orbita esattamente nell'orbita, infatti l'orbita indica solamente il posto dove ci sono più probabilità di localizzare l'elettrone. Questo discorso ci porterà a parlare della meccanica quantistica, in cui non si parla di certezza ma solamente di possibilità. Le regole espresse in precedenza sono chiamate leggi di Heisenberg. Esse dicono che è impossibile determinare entrambe le proprietà di un atomo allo stesso tempo, senza influenzare una di esse. Di seguito verranno enunciati alcuni principi di base della meccanica quantistica. 114 Appendice C Il fenomeno della materia è che essa è costituita da piccole parti. La più piccola serve per costruire le altre costruzioni della natura, come atomi e molecole, chiamate particelle fondamentali. Quello che i fisici hanno trovato è che le particelle non sono particelle nel senso di sfere, come si potrebbe immaginare, ma esse sono sottoforma di onde. Figura 1 : Esempio di particelle.. Adesso parleremo di polarizzazione e shift di fase. Supponiamo di avere due onde della stessa lunghezza che viaggiano sullo stesso percorso x. Cosa dire degli altri assi E e B? Un'onda può avere gli assi B ed E alla stessa costante di 90° e quindi può ruotare attorno ad essi. Figura 2 : Esempio di polarizzazione. Dando una posizione casuale a due vettori in un sistema di assi, è possibile notare che essi appaiono più vicini, essendo ruotati di 90°. Dalla figura 2 è possibile dire che che l'onda elettro magnetica è polarizzata per 90°. Di conseguenza il fotone, considerato la particella elementare della luce, può essere polarizzato, perchè? Perchè, come accennato in precedenza, la luce è sia particella che onda, e di conseguenza, ogni protone può essere considerato anche come un'onda. 115 Appendice C Ora rimane un ultimo termine da definire : shift di fase. La figura sottostante descrive un'onda elettro - magnetica. Essa è una funzione seno. Essa è periodica di 360°. Questo significa che la funzione si ripete dopo alcuni valori di x. Figura 3 : Esempio di phase shifting. Dalla figura è possibile notare che le funzione verde e rossa sono le stesse, ma shiftate sull'asse x. Per essere più precisi la funzione rossa è sin(x), mentre quella verde è sin(x+pi/4). Adesso si può dire che quest'ultima è shiftata di fase pi/4 (45°). La stessa cosa succede per le onde elettromagnetiche perchè esse sono descritte da un'onda sinusoidale. 2 Crittografia quantica Ora si hanno due possibilità per mandare un messaggio. Un cifrario a chiave privata, come quello di Vernam, se è possibile tenere segreta la chiave. E' proprio in questo punto che entra in gioco la fisica quantistica. Bob e Alice devono dividere una chiave segreta, la crittografia quantistica permette a due parti separate fisicamente di creare una chiave segreta casuale senza servirsi del servizio di un corriere. La cosa migliore è che il sistema permette di verificare se la chiave è stata intercettata. La crittografia quantistica non è un sistema crittografico totalmente nuovo, ma la procedura di distribuzione della chiave in perfetta discrezione lo rende sicuro. Per capire meglio come funziona la crittografia quantistica possiamo considerare il protocollo di comunicazione BB84, introdotto nel 1984 da Charles Bennett dell'IBM e Gilles Brassard dell'Università di Montreal. 116 Appendice C Alice e Bob sono connessi da un canale quantico e da da un classico canale pubblico. Se i singoli fotoni sono usati per trasportare le informazioni il canale quantico è solitamente una fibra ottica. Il canale pubblico può essere qualsiasi mezzo di comunicazione, come una linea telefonica. Ora parliamo per un attimo di informazione. Le informazioni nel mondo dei computer sono rappresentate da una serie di 0 e 1 che uniti insieme formano l'informazione. Questi 0 e 1 quando viaggiano in una linea telefonica sono rappresentati da un voltaggio (solitamente 0V e 5V). Nel caso del canale quantico le portanti sono i fotoni e come possiamo vedere possono usare sia la polarizzazione che lo shift di fase. Figura 4 : Trasmissione tra Alice e Bob. 1. Alice ha 4 polarizzatori, che possono trasmettere singoli fotoni polarizzati sia verticalmente che orizzontalmente, a 45° o a -45°. Essa manda una serie di fotoni attraverso il canale quantico, avendo scelto a caso uno degli stati di polarizzazione per ogni fotone. 2. Bob ha 4 analizzatori (dispositivi che possono analizzare l'angolo di polarizzazione, o più angoli allo stesso tempo), non due. Un analizzatore permette a Bob di distinguere tra due fotoni polarizzati a 45° o a -45°, mentre gli altri gli permettono di distinguere tra i fotoni polarizzati verticalmente o orizzontalmente. Si noti che Alice ha 4 polarizzatori e Bob solo due analizzatori. Si noti, inoltre, come gli 0 e gli 1 sono settati da Alice. Questo è cruciale. Cosa fa Bob, allora? Egli sceglie casualmente un analizzatore e lo usa per registrare ogni protone. In seguito scriverà quale analizzatore ha usato e cosa ha registrato. Per esempio, Alice manda un protone polarizzato verticalmente e Bob sceglie di analizzare solo quelli a +/-45°. Essenzialmente se Bob sceglie un analizzatore a +/45° ci sono il 50% di probabilità che esso registri qualcosa, mentre se Bob sceglie l'analizzatore sbagliato, non ha possibilità di trovare che stato di 117 Appendice C polarizzazione Alice ha inviato. Dopo aver scambiato abbastanza fotoni, Bob annuncia nel canale pubblico la sequenza di analizzatori usata, ma non il risultato ottenuto. 3. Alice compara la sequenza con la lista dei bits originariamente inviati, e dice a Bob attraverso il canale pubblico in che occasione il suo analizzatore è compatibile con la polarizzazione del fotone. Essa non deve dire che stato di polarizzazione ha usato. Se Bob ha usato un analizzatore non compatibile con il fotone di Alice, il bit è rifiutato. Per i bit rimanenti, Alice e Bob sanno che hanno lo stesso valore. I bits che rimangono ad Alice e a Bob possono essere usati per generare una chiave che essi potranno utilizzare per crittare il messaggio. Adesso analizziamo il caso in cui ci sia Eva. Supponiamo che Eva abbia intercettato entrambi i quanti e l’informazione inviata attraverso il canale pubblico. Cosa c'è di sbagliato in quello appena descritto? Ovviamente i bits scoperti non possono essere usati ancora per la crittazione. Se Eva intercetta la loro chiave, la correlazione tra i valori dei bits diminuisce. Per esempio se Eva ha la stessa attrezzatura di Bob e taglia la fibra e misura il segnale, essa avrà dei bit casuali ogni volta che sceglierà l'analizzatore sbagliato. Ma avendo intercettato il segnale, Eva deve mandare un fotone a Bob per coprire le proprie tracce. Di conseguenza, nel 50% dei casi gli analizzatori di Alice e Bob coincidono, ma cosa succede nel caso in cui Eva abbia sbagliato analizzatore? Comunque nella metà dei casi i fotoni passeranno accidentalmente attraverso l'analizzatore giusto dalla parte di Bob. Si può vedere ora che la correlazione tra Alice e Bob scende al 25% in presenza di Eva. In questo caso Alice e Bob conosceranno l'informazione che è stata intercettata, quando compareranno le chiavi sul canale pubblico, notando un grande disaccordo. Cosa si può ottenere dalla crittografia in pratica? I fotoni sono dei buoni candidati per trasportare informazioni; essi sono semplici da produrre a da misurare. L'esempio fatto per la polarizzazione può essere valido per lo shift di fase. Infatti, è più usato della polarizzazione. Cosa migliore, i protoni, possono essere trasmessi attraverso la fibra ottica e la loro attenuazione è di circa 25 anni (misura di quanti fotoni vengono persi durante la trasmissione) a una lunghezza d'onda di 1300nm. Questo significa che i protoni possono viaggiare per 10Km prima che il 50% di essi venga perso. E' importante notare che i protoni non possono essere amplificati, perchè gli stati dei quanti non possono essere duplicati. Certamente questo non è l'unico problema. Ci sono anche problemi relativi alla linea. La non correlazione tra bit può anche essere causata da alcune imperefezioni sperimentali. Per esempio, Alice deve essere sicura di creare fotoni dello stato scelto. 118 Appendice C Per superare questi problemi, Alice e Bob devono applicare un classico algoritmo di gestione degli errori, che riporti le probabilità di errore negli standard telecomunicativi (10^-9). C'è una procedura che Alice e Bob possono usare conosciuta col nome di "amplificazione privata" in cui gruppi di bit sono combinati in uno solo. Questa procedura assicura che i bit combinati coincidano solo se i bit iniziali di Alice e Bob sono gli stessi. 119 Appendice D Appendice D Manuale PGP Gen. nuove chiavi: pgp -kg Aggiunta di chiavi: pgp -ka file [portachiavi] Esrazione di chiavi: pgp -kx[a] ID file [portachiavi] Vedere chiavi: pgp -kv[v] [ID] [portachiavi] Vedere impronte digitali: pgp -kvc [ID] [portachiavi] Vedere in dettaglio: pgp -kc [ID] [portachiavi] Rimuovere ID o chiavi: pgp -kr ID [portachiavi] (Ripetere per piu' ID su una chiave) Aggiungere un ID: pgp -ke ID [portachiavi] Modifica frase chiave: pgp -ke ID [portachiavi] Modif. param. affidab.: pgp -kx ID key.tmp [portachiavi] pgp -kr ID [portachiavi] pgp -ka key.tmp [portachiavi] Firmare una chiave: pgp -ks suo_ID [-u mio_ID] Rimuovere la firma da una chiave: pgp -krs ID [portachiavi] Revoca, disabilitaz.: pgp -kd ID [portachiavi] Criptare: pgp -e[a] filetesto dest_ID Firmare: pgp -s[a] filetesto [-u mio_ID] Firmare e criptare: pgp -se[a] filetesto dest_ID [dest2_ID...][-u mio_ID] Certif. separato: pgp -sb[a] [+clearsig=on] file principale [-u mio_ID] Criptare solo con IDEA: pgp -c filetesto Decrittare o controllo firma: pgp [-d] [-p] filecifrato (-d per tenere i dati pgp, -p per il nome originale) Verifica firma separata: pgp filefirma [fileprincipale] Aggiungere [a] per produrre files ASCII Aggiungere [-o outfile] per specificare il file di uscita Aggiungere [+batchmode] per vedere l'uscita errorlevels Aggiungere [f] per ridirigere i dati ( pgp -f[ARGS] <infile >outfile ) Aggiungere [w] per distruggere il file in chiaro (dopo la cifratura) Aggiunger [m] per permettere la sola visione del testo in chiaro senza file di uscita Aggiungere [t] per usare il terminatore di linea Unix Usare [-@] per specificare destinatari addizionali quando si cifra 120 Appendice E Appendice E Prodotti esistenti 1 Netbus Sono già in commercio alcuni programmi che svolgono operazioni simili a quelle che ci siamo proposti di raggiungere, ossia software che intercettano i messaggi provenienti dalla rete. Netbus è un dei più famosi ed efficienti. Inizialmente è stato prodotto come gestore di sistemi in remoto, infatti Netbus e' un potentissimo strumento, che se usato in maniera giusta, puo' pilotare completamente un'altro pc, a migliaia di km di distanza, risolvendo molti inconvenienti. 1 Netbus NETBUS è un programma di BACKDOOR. Grazie a questo programma l'hacker può teleguidare il vostro computer. Netbus ha una interfaccia molto più semplice, bisogna solo conoscere l'indirizzo IP del computer da colpire, poi basta premere i pulsanti in dotazione col programma client (programma dell'hacker) come Open CD-ROM che serve ad aprire e chiudere il cassettino del CD-ROM o Play sound che serve a fare suonare una musica al server remoto (il vostro computer colpito da hacker) e moltissimi altri comandi intuitivi. Figura 1 : Interfaccia di Netbus. 121 Appendice E Quando un hacker installa il suo "cavallo di troia" nel vostro computer mette una password per accedere al vostro computer, in questo modo solo lui potra accedervi; esiste però una master password. Ciò che lo rende più evoluto degli altri programmi di Back door è la possibilità di fare la scansione automatica degli indirizzi IP e la possibilità di avere più persone sotto il controllo dell'hacker, in questo modo l'hacker non deve inserire sequenzialmente ogni indirizzo IP ma sarà il programma stesso a fare la scansione; per fare la scansione basta mettere xxx.xxx.xxx.0+255 (dove xxx è un numero compreso tra 0 e 255) in questo modo Netbus farà la scansione da 0 a 255 dell'ultimo campo dell'indirizzo IP. Figura 2 : Gestione remota di file con Netbus. Il programma comprende due file: il programma server e il programma client. Il programma server è il file con dimensione minore ed è il file che infetta il computer del malcapitato, per infettare il computer il programma deve essere eseguito, il nome del file generalmente è PATCH.EXE (ma il nome può essere modificato a proprio piacimento); il programma è difficilmente visibile e si carica ogni volta che si avvia il computer Il programma client è quello che usa l'hacker per spiare (o distruggere) il vostro computer, ha un interfaccia semplicissima a pulsanti, bisogna solo inserire l'indirizzo IP del computer infetto (o la gamma di indirizzi) e premere i pulsanti. Ogni computer infetto ha una sua password di accesso esclusiva dell'hacker che vi ha infettato. 122 Appendice F Appendice F Listati 1 2 3 4 PTerminal DES Crittografia TCP 1 PTerminal class CMySocket : public CAsyncSocket { private: CDialog* m_pWnd; // Attributes public: // Operations public: CMySocket(); virtual ~CMySocket(); SetParent (CDialog *pWnd); // Overrides public: // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CMySocket) public: virtual void OnAccept(int nErrorCode); virtual void OnConnect(int nErrorCode); virtual void OnReceive(int nErrorCode); //}}AFX_VIRTUAL // Generated message map functions //{{AFX_MSG(CMySocket) // NOTE - the ClassWizard will add and remove member functions here. //}}AFX_MSG // Implementation protected: }; CMySocket::CMySocket() { } CMySocket::~CMySocket() { } CMySocket::SetParent (CDialog *pWnd) { m_pWnd = pWnd; } 123 Appendice F // Do not edit the following lines, which are needed by ClassWizard. #if 0 BEGIN_MESSAGE_MAP(CMySocket, CAsyncSocket) //{{AFX_MSG_MAP(CMySocket) //}}AFX_MSG_MAP END_MESSAGE_MAP() #endif // 0 ////////////////////////////////////////////////////////////////// /////CMySocket member functions void CMySocket::OnAccept(int nErrorCode) { if (nErrorCode == 0) ((CPTerminalDlg*)m_pWnd)->OnAccept(); } void CMySocket::OnConnect(int nErrorCode) { if (nErrorCode == 0) ((CPTerminalDlg*)m_pWnd)->OnConnect(); } void CMySocket::OnReceive(int nErrorCode) { if (nErrorCode == 0) ((CPTerminalDlg*)m_pWnd)->OnReceive(); } class CPTerminalDlg : public CDialog { // Construction private: CMySocket m_sListenSocket; CMySocket m_sConnectSocket; public: CPTerminalDlg(CWnd* pParent = NULL); constructor // standard void OnAccept(); void OnConnect(); void OnSend(); void OnReceive(); void OnClose(); // Dialog Data //{{AFX_DATA(CPTerminalDlg) enum { IDD = IDD_PTERMINAL_DIALOG }; CListBox m_ctlSent; CListBox m_ctlRecvd; CButton m_ctlConnect; CString m_strMessage; CString m_strName; int m_iPort; int m_iType; //}}AFX_DATA // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CPTerminalDlg) protected: virtual void DoDataExchange(CDataExchange* pDX); support // DDX/DDV 124 Appendice F //}}AFX_VIRTUAL // Implementation protected: HICON m_hIcon; // Generated message map functions //{{AFX_MSG(CPTerminalDlg) virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnDestroy(); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); afx_msg void OnRType(); afx_msg void OnBconnect(); afx_msg void OnBsend(); afx_msg void OnBclose(); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; CPTerminalDlg::CPTerminalDlg(CWnd* pParent /*=NULL*/) : CDialog(CPTerminalDlg::IDD, pParent) { //{{AFX_DATA_INIT(CPTerminalDlg) m_strMessage = _T(""); m_strName = _T(""); m_iPort = 0; m_iType = -1; //}}AFX_DATA_INIT // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CPTerminalDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CPTerminalDlg) DDX_Control(pDX, IDC_LSENT, m_ctlSent); DDX_Control(pDX, IDC_LRECVD, m_ctlRecvd); DDX_Control(pDX, IDC_BCONNECT, m_ctlConnect); DDX_Text(pDX, IDC_EMSG, m_strMessage); DDX_Text(pDX, IDC_ESERVNAME, m_strName); DDX_Text(pDX, IDC_ESERVPORT, m_iPort); DDX_Radio(pDX, IDC_RCLIENT, m_iType); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CPTerminalDlg, CDialog) //{{AFX_MSG_MAP(CPTerminalDlg) ON_WM_SYSCOMMAND() ON_WM_DESTROY() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_RCLIENT, OnRType) ON_BN_CLICKED(IDC_BCONNECT, OnBconnect) ON_BN_CLICKED(IDC_BSEND, OnBsend) ON_BN_CLICKED(IDC_RSERVER, OnRType) ON_BN_CLICKED(IDC_BCLOSE, OnBclose) //}}AFX_MSG_MAP END_MESSAGE_MAP() 125 Appendice F ////////////////////////////////////////////////////////////////// /////////// // CPTerminalDlg message handlers BOOL CPTerminalDlg::OnInitDialog() { CDialog::OnInitDialog(); // Add "About..." menu item to system menu. SetIcon(m_hIcon,FALSE); // IDM_ABOUTBOX must be in the system command range. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon m_iType = 0; m_strName = "loopback"; m_iPort = 4000; UpdateData(FALSE); m_sConnectSocket.SetParent (this); m_sListenSocket.SetParent (this); return TRUE; control } // return TRUE unless you set the focus to a void CPTerminalDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID, lParam); } } void CPTerminalDlg::OnDestroy() { WinHelp(0L, HELP_QUIT); 126 Appendice F CDialog::OnDestroy(); } // If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework. void CPTerminalDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } // The system calls this to obtain the cursor to display while the user drags // the minimized window. HCURSOR CPTerminalDlg::OnQueryDragIcon() { return (HCURSOR) m_hIcon; } void CPTerminalDlg::OnRType() { UpdateData(TRUE); if (m_iType == 0) m_ctlConnect.SetWindowText ("C&onnect"); else m_ctlConnect.SetWindowText ("&Listen"); } void CPTerminalDlg::OnBconnect() { UpdateData(TRUE); GetDlgItem(IDC_BCONNECT)->EnableWindow(FALSE); GetDlgItem(IDC_ESERVNAME)->EnableWindow(FALSE); GetDlgItem(IDC_ESERVPORT)->EnableWindow(FALSE); GetDlgItem(IDC_STATICNAME)->EnableWindow(FALSE); 127 Appendice F GetDlgItem(IDC_STATICPORT)->EnableWindow(FALSE); GetDlgItem(IDC_RCLIENT)->EnableWindow(FALSE); GetDlgItem(IDC_RSERVER)->EnableWindow(FALSE); GetDlgItem(IDC_STATICTYPE)->EnableWindow(FALSE); if (m_iType == 0) { // CAsyncSocket *pSock = new CAsyncSocket; // if (m_sConnectSocket.Accept (*pSock)) // { // pSock->Create (); // pSock->Connect (m_strName,m_iPort); // } m_sConnectSocket.Create(); m_sConnectSocket.Connect(m_strName,m_iPort); } else { m_sListenSocket.Create(m_iPort); m_sListenSocket.Listen(); } } void CPTerminalDlg::OnAccept() { CAsyncSocket *pSock = new CAsyncSocket; if (m_sListenSocket.Accept (*pSock)) { pSock->Create (); pSock->Connect (m_strName,m_iPort); } else delete pSock; //m_sListenSocket.Accept(m_sConnectSocket); GetDlgItem(IDC_EMSG)->EnableWindow(TRUE); GetDlgItem(IDC_BSEND)->EnableWindow(TRUE); GetDlgItem(IDC_STATICMSG)->EnableWindow(TRUE); } void CPTerminalDlg::OnConnect() { GetDlgItem(IDC_EMSG)->EnableWindow(TRUE); GetDlgItem(IDC_BSEND)->EnableWindow(TRUE); GetDlgItem(IDC_STATICMSG)->EnableWindow(TRUE); GetDlgItem(IDC_BCLOSE)->EnableWindow(TRUE); } void CPTerminalDlg::OnReceive() { char *pBuf = new char[1025]; int iBufSize = 1024; int iRcvd; CString strRecvd; iRcvd = m_sConnectSocket.Receive(pBuf, iBufSize); if (iRcvd == SOCKET_ERROR) { } else 128 Appendice F { pBuf[iRcvd] = NULL; strRecvd = pBuf; m_ctlRecvd.AddString(strRecvd); UpdateData(FALSE); } } void CPTerminalDlg::OnClose() { m_sConnectSocket.Close(); GetDlgItem(IDC_EMSG)->EnableWindow(FALSE); GetDlgItem(IDC_BSEND)->EnableWindow(FALSE); GetDlgItem(IDC_STATICMSG)->EnableWindow(FALSE); GetDlgItem(IDC_BCLOSE)->EnableWindow(FALSE); if (m_iType == 0) { GetDlgItem(IDC_BCONNECT)->EnableWindow(TRUE); GetDlgItem(IDC_ESERVNAME)->EnableWindow(TRUE); GetDlgItem(IDC_ESERVPORT)->EnableWindow(TRUE); GetDlgItem(IDC_STATICNAME)->EnableWindow(TRUE); GetDlgItem(IDC_STATICPORT)->EnableWindow(TRUE); GetDlgItem(IDC_RCLIENT)->EnableWindow(TRUE); GetDlgItem(IDC_RSERVER)->EnableWindow(TRUE); GetDlgItem(IDC_STATICTYPE)->EnableWindow(TRUE); } } void CPTerminalDlg::OnBsend() { int iLen; int iSent; UpdateData(TRUE); if (m_strMessage != "") { iLen = m_strMessage.GetLength(); iSent = m_sConnectSocket.Send(LPCSTR(m_strMessage), iLen); if (iSent == SOCKET_ERROR) { } else { m_ctlSent.AddString(m_strMessage); UpdateData(FALSE); } } } void CPTerminalDlg::OnBclose() { OnClose(); } 129 Appendice F 2 DES #if !defined(AFX_DES_H__7AF11A81_11EF_4947_8738_DF9FABD1DD25__INCLUDE) #define AFX_DES_H__7AF11A81_11EF_4947_8738_DF9FABD1DD25__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 class AFX_EXT_CLASS CDes { public: void Decrypt(LPTSTR Key,LPTSTR Data); CDes(); virtual ~CDes(); void Crypt(LPTSTR Key, LPTSTR Data); private: unsigned _int64 artoi(unsigned int *array,unsigned int length); void itoar(unsigned __int64 int64,unsigned int *array, unsigned int length); unsigned _int64 stoi(char *string,unsigned int length); void itos(char *string,unsigned __int64 int64, unsigned int length); void matoar32(unsigned int matrix[][4],unsigned int array[], unsigned int yStart,unsigned int xStart, unsigned int yEnd,unsigned int xEnd); void matoar48(unsigned int matrix[][6],unsigned int array[], unsigned int yStart,unsigned int xStart, unsigned int yEnd,unsigned int xEnd); void matoar56(unsigned int matrix[][7],unsigned int array[], unsigned int yStart,unsigned int xStart, unsigned int yEnd,unsigned int xEnd); void matoar64(unsigned int matrix[][8],unsigned int array[], unsigned int yStart,unsigned int xStart, unsigned int yEnd,unsigned int xEnd); void _strcat(char *strDest,char *strOr); void arcat(unsigned int *arrayOr1,unsigned int *arrayOr2, unsigned int *arrayDest,unsigned int lenDest, unsigned int lenOr); unsigned _int64 power(unsigned int b,unsigned int e); void shift(unsigned __int64 &shift,unsigned int nShift); void Calculate_Keys(unsigned int matrix[][7], unsigned int iterations); unsigned __int64 crypt(unsigned __int64 data, unsigned int iterations); unsigned __int64 decrypt(unsigned __int64 data, unsigned int iterations); void Divide(unsigned int *array,unsigned int matrix[][6], unsigned int lenAr,unsigned int lenGrp); unsigned int Index(unsigned matDiv[][6],unsigned matrix[][16], unsigned row); void Group(unsigned int *array,unsigned int *arrGrp, unsigned int lenAr,unsigned int lenGrp); void Expand(unsigned int *array,unsigned int matrix[][6]); void Permute_IP(unsigned int *array,unsigned int matrix[][8]); 130 Appendice F void Permute_P2(unsigned int *array,unsigned int matrix[][4]); void Permute_FP(unsigned int *array,unsigned int matrix[][8]); void Reduce56to48(unsigned int *array, unsigned int matrix[][6]); void Reduce64to56(unsigned int *array, unsigned int matrix[][7]); void Set_Key(unsigned __int64 newKey); unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned EX[8][6]; FP[8][8]; IP[8][8]; __int64 Keys_Array[16]; __int64 L[17]; P1[8][6]; P2[8][4]; __int64 R[17]; Rotation_Array[16]; R1[8][7]; S1[4][16]; S2[4][16]; S3[4][16]; S4[4][16]; S5[4][16]; S6[4][16]; S7[4][16]; S8[4][16]; unsigned _int64 Key; }; #endif #include "stdafx.h" #include "CDes.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif ////////////////////////////////////////////////////////////////// //// // Construction/Destruction ////////////////////////////////////////////////////////////////// //// CDes::CDes() { //Inizializzazione della prima matrice di riduzione. R1[0][0] = 57; R1[0][1] = 49; R1[0][2] = 41; R1[0][3] R1[0][4] = 25; R1[0][5] = 17; R1[0][6] = 9; R1[1][0] = 1; R1[1][1] = 58; R1[1][2] = 50; R1[1][3] R1[1][4] = 34; R1[1][5] = 26; R1[1][6] = 18; R1[2][0] = 10; R1[2][1] = 2; R1[2][2] = 59; R1[2][3] R1[2][4] = 43; R1[2][5] = 35; R1[2][6] = 27; R1[3][0] = 19; R1[3][1] = 11; R1[3][2] = 3; R1[3][3] R1[3][4] = 52; R1[3][5] = 44; R1[3][6] = 36; R1[4][0] = 63; R1[4][1] = 55; R1[4][2] = 47; R1[4][3] R1[4][4] = 31; R1[4][5] = 23; R1[4][6] = 15; = 33; = 42; = 51; = 60; = 39; 131 Appendice F R1[5][0] R1[5][4] = R1[6][0] R1[6][4] = R1[7][0] R1[7][4] = = 7; R1[5][1] 38; R1[5][5] = = 14; R1[6][1] 45; R1[6][5] = = 21; R1[7][1] 20; R1[7][5] = = 62; R1[5][2] 30; R1[5][6] = = 6; R1[6][2] 37; R1[6][6] = = 13; R1[7][2] 12; R1[7][6] = = 54; R1[5][3] = 46; 22; = 61; R1[6][3] = 53; 29; = 5; R1[7][3] = 28; 4; //Inizializzazione della prima matrice di permutazione P1[0][0] = 14; P1[0][1] = 17; P1[0][2] = 11; P1[0][3] P1[0][4] = 1; P1[0][5] = 5; P1[1][0] = 3; P1[1][1] = 28; P1[1][2] = 15; P1[1][3] P1[1][4] = 21; P1[1][5] = 10; P1[2][0] = 23; P1[2][1] = 19; P1[2][2] = 12; P1[2][3] P1[2][4] = 26; P1[2][5] = 8; P1[3][0] = 16; P1[3][1] = 7; P1[3][2] = 27; P1[3][3] P1[3][4] = 13; P1[3][5] = 2; P1[4][0] = 41; P1[4][1] = 52; P1[4][2] = 31; P1[4][3] P1[4][4] = 47; P1[4][5] = 55; P1[5][0] = 30; P1[5][1] = 40; P1[5][2] = 51; P1[5][3] P1[5][4] = 33; P1[5][5] = 48; P1[6][0] = 44; P1[6][1] = 49; P1[6][2] = 39; P1[6][3] P1[6][4] = 34; P1[6][5] = 53; P1[7][0] = 46; P1[7][1] = 42; P1[7][2] = 50; P1[7][3] P1[7][4] = 29; P1[7][5] = 32; //Inizializzazione della seconda matrice P2[0][0] = 16; P2[0][1] = 7; P2[0][2] P2[1][0] = 29; P2[1][1] = 12; P2[1][2] P2[2][0] = 1; P2[2][1] = 15; P2[2][2] P2[3][0] = 5; P2[3][1] = 18; P2[3][2] P2[4][0] = 2; P2[4][1] = 8; P2[4][2] P2[5][0] = 32; P2[5][1] = 27; P2[5][2] P2[6][0] = 19; P2[6][1] = 13; P2[6][2] P2[7][0] = 22; P2[7][1] = 11; P2[7][2] = 24; = 6; = 4; = 20; = 37; = 45; = 56; = 36; di permutazione = 20; P2[0][3] = = 28; P2[1][3] = = 23; P2[2][3] = = 31; P2[3][3] = = 24; P2[4][3] = = 3; P2[5][3] = = 30; P2[6][3] = = 4; P2[7][3] = 21; 17; 26; 10; 14; 9; 6; 25; //Inizializzazione della matrice di permutazione iniziale IP[0][0] = 58; IP[0][1] = 50; IP[0][2] = 42; IP[0][3] = 34; IP[0][4] = 26; IP[0][5] = 18; IP[0][6] = 10; IP[0][7] = 2; IP[1][0] = 60; IP[1][1] = 52; IP[1][2] = 44; IP[1][3] = 36; IP[1][4] = 28; IP[1][5] = 20; IP[1][6] = 12; IP[1][7] = 4; IP[2][0] = 62; IP[2][1] = 54; IP[2][2] = 46; IP[2][3] = 38; IP[2][4] = 30; IP[2][5] = 22; IP[2][6] = 14; IP[2][7] = 6; IP[3][0] = 64; IP[3][1] = 56; IP[3][2] = 48; IP[3][3] = 40; IP[3][4] = 32; IP[3][5] = 24; IP[3][6] = 16; IP[3][7] = 8; IP[4][0] = 57; IP[4][1] = 49; IP[4][2] = 41; IP[4][3] = 33; IP[4][4] = 25; IP[4][5] = 17; IP[4][6] = 9; IP[4][7] = 1; IP[5][0] = 59; IP[5][1] = 51; IP[5][2] = 43; IP[5][3] = 35; IP[5][4] = 27; IP[5][5] = 19; IP[5][6] = 11; IP[5][7] = 3; IP[6][0] = 61; IP[6][1] = 53; IP[6][2] = 45; IP[6][3] = 37; IP[6][4] = 29; IP[6][5] = 21; IP[6][6] = 13; IP[6][7] = 5; IP[7][0] = 63; IP[7][1] = 55; IP[7][2] = 47; IP[7][3] = 39; IP[7][4] = 31; IP[7][5] = 23; IP[7][6] = 15; IP[7][7] = 7; //Inizializzazione della matrice di permutazione finale FP[0][0] = 40; FP[0][1] = 8; FP[0][2] = 48; FP[0][3] FP[0][4] = 56; FP[0][5] = 24; FP[0][6] = 64; FP[0][7] = FP[1][0] = 39; FP[1][1] = 7; FP[1][2] = 47; FP[1][3] FP[1][4] = 55; FP[1][5] = 23; FP[1][6] = 63; FP[1][7] = FP[2][0] = 38; FP[2][1] = 6; FP[2][2] = 46; FP[2][3] FP[2][4] = 54; FP[2][5] = 22; FP[2][6] = 62; FP[2][7] = FP[3][0] = 37; FP[3][1] = 5; FP[3][2] = 45; FP[3][3] FP[3][4] = 53; FP[3][5] = 21; FP[3][6] = 61; FP[3][7] = = 16; 32; = 15; 31; = 14; 30; = 13; 29; 132 Appendice F FP[4][0] FP[4][4] = FP[5][0] FP[5][4] = FP[6][0] FP[6][4] = FP[7][0] FP[7][4] = = 36; FP[4][1] 52; FP[4][5] = = 35; FP[5][1] 51; FP[5][5] = = 34; FP[6][1] 50; FP[6][5] = = 33; FP[7][1] 49; FP[7][5] = = 4; FP[4][2] 20; FP[4][6] = = 3; FP[5][2] 19; FP[5][6] = = 2; FP[6][2] 18; FP[6][6] = = 1; FP[7][2] 17; FP[7][6] = = 44; FP[4][3] 60; FP[4][7] = = 43; FP[5][3] 59; FP[5][7] = = 42; FP[6][3] 58; FP[6][7] = = 41; FP[7][3] 57; FP[7][7] = //Inizializzazione della prima matrice di permutazione EX[0][0] = 32; EX[0][1] = 1; EX[0][2] = 2; EX[0][3] EX[0][4] = 4; EX[0][5] = 5; EX[1][0] = 4; EX[1][1] = 5; EX[1][2] = 6; EX[1][3] EX[1][4] = 8; EX[1][5] = 9; EX[2][0] = 8; EX[2][1] = 9; EX[2][2] = 10; EX[2][3] EX[2][4] = 12; EX[2][5] = 13; EX[3][0] = 12; EX[3][1] = 13; EX[3][2] = 14; EX[3][3] EX[3][4] = 16; EX[3][5] = 17; EX[4][0] = 16; EX[4][1] = 17; EX[4][2] = 18; EX[4][3] EX[4][4] = 20; EX[4][5] = 21; EX[5][0] = 20; EX[5][1] = 21; EX[5][2] = 22; EX[5][3] EX[5][4] = 24; EX[5][5] = 25; EX[6][0] = 24; EX[6][1] = 25; EX[6][2] = 26; EX[6][3] EX[6][4] = 28; EX[6][5] = 29; EX[7][0] = 28; EX[7][1] = 29; EX[7][2] = 30; EX[7][3] EX[7][4] = 32; EX[7][5] = 1; = 12; 28; = 11; 27; = 10; 26; = 9; 25; = 3; = 7; = 11; = 15; = 19; = 23; = 27; = 31; //Inizializzazione delle 8 tavole (S-Box) //1° S1[0][0] = 14; S1[0][1] = 4; S1[0][2] = 13; S1[0][3] = 1; S1[0][4] = 2; S1[0][5] = 15; S1[0][6] = 11; S1[0][7] = 8; S1[0][8] = 3; S1[0][9] = 10; S1[0][10] = 6; S1[0][11] = 12; S1[0][12] = 5; S1[0][13] = 9; S1[0][14] = 0; S1[0][15] = 7; S1[1][0] = 0; S1[1][1] = 15; S1[1][2] = 7; S1[1][3] = 4; S1[1][4] = 14; S1[1][5] = 2; S1[1][6] = 13; S1[1][7] = 1; S1[1][8] = 10; S1[1][9] = 6; S1[1][10] = 12; S1[1][11] = 11; S1[1][12] = 9; S1[1][13] = 5; S1[1][14] = 3; S1[1][15] = 8; S1[2][0] = 4; S1[2][1] = 1; S1[2][2] = 14; S1[2][3] = 8; S1[2][4] = 13; S1[2][5] = 6; S1[2][6] = 2; S1[2][7] = 11; S1[2][8] = 15; S1[2][9] = 12; S1[2][10] = 9; S1[2][11] = 7; S1[2][12] = 3; S1[2][13] = 10; S1[2][14] = 5; S1[2][15] = 0; S1[3][0] = 15; S1[3][1] = 12; S1[3][2] = 8; S1[3][3] = 2; S1[3][4] = 4; S1[3][5] = 9; S1[3][6] = 1; S1[3][7] = 7; S1[3][8] = 5; S1[3][9] = 11; S1[3][10] = 3; S1[3][11] = 14; S1[3][12] = 10; S1[3][13] = 0; S1[3][14] = 6; S1[3][15] = 13; //2° S2[0][0] = 15; S2[0][1] S2[0][4] = 6; S2[0][5] = S2[0][8] = 9; S2[0][9] = S2[0][12] = 12; S2[0][13] S2[1][0] = 3; S2[1][1] S2[1][4] = 15; S2[1][5] = S2[1][8] = 12; S2[1][9] = S2[1][12] = 6; S2[1][13] S2[2][0] = 0; S2[2][1] S2[2][4] = 10; S2[2][5] = S2[2][8] = 5; S2[2][9] = S2[2][12] = 9; S2[2][13] S2[3][0] = 13; S2[3][1] S2[3][4] = 3; S2[3][5] = S2[3][8] = 11; S2[3][9] = S2[3][12] = 0; S2[3][13] = 1; S2[0][2] = 8; S2[0][3] = 14; 11; S2[0][6] = 3; S2[0][7] = 4; 7; S2[0][10] = 2; S2[0][11] = 13; = 0; S2[0][14] = 5; S2[0][15] = 10; = 13; S2[1][2] = 4; S2[1][3] = 7; 2; S2[1][6] = 8; S2[1][7] = 14; 0; S2[1][10] = 1; S2[1][11] = 10; = 9; S2[1][14] = 11; S2[1][15] = 5; = 14; S2[2][2] = 7; S2[2][3] = 11; 4; S2[2][6] = 13; S2[2][7] = 1; 8; S2[2][10] = 12; S2[2][11] = 6; = 3; S2[2][14] = 2; S2[2][15] = 15; = 8; S2[3][2] = 10; S2[3][3] = 1; 15; S2[3][6] = 4; S2[3][7] = 2; 6; S2[3][10] = 7; S2[3][11] = 12; = 5; S2[3][14] = 14; S2[3][15] = 9; 133 Appendice F //3° S3[0][0] = 10; S3[0][1] S3[0][4] = 6; S3[0][5] = S3[0][8] = 1; S3[0][9] = S3[0][12] = 11; S3[0][13] S3[1][0] = 13; S3[1][1] S3[1][4] = 3; S3[1][5] = S3[1][8] = 2; S3[1][9] = S3[1][12] = 12; S3[1][13] S3[2][0] = 13; S3[2][1] S3[2][4] = 8; S3[2][5] = S3[2][8] = 11; S3[2][9] = S3[2][12] = 5; S3[2][13] S3[3][0] = 1; S3[3][1] S3[3][4] = 6; S3[3][5] = S3[3][8] = 4; S3[3][9] = S3[3][12] = 11; S3[3][13] = 0; S3[0][2] = 9; S3[0][3] = 14; 3; S3[0][6] = 15; S3[0][7] = 5; 13; S3[0][10] = 12; S3[0][11] = 7; = 4; S3[0][14] = 2; S3[0][15] = 8; = 7; S3[1][2] = 0; S3[1][3] = 9; 4; S3[1][6] = 6; S3[1][7] = 10; 8; S3[1][10] = 5; S3[1][11] = 14; = 11; S3[1][14] = 15; S3[1][15] = 1; = 6; S3[2][2] = 4; S3[2][3] = 9; 15; S3[2][6] = 3; S3[2][7] = 0; 1; S3[2][10] = 2; S3[2][11] = 12; = 10; S3[2][14] = 14; S3[2][15] = 7; = 10; S3[3][2] = 13; S3[3][3] = 0; 9; S3[3][6] = 8; S3[3][7] = 7; 15; S3[3][10] = 14; S3[3][11] = 3; = 5; S3[3][14] = 2; S3[3][15] = 12; //4° S4[0][0] = 7; S4[0][1] S4[0][4] = 0; S4[0][5] = S4[0][8] = 1; S4[0][9] = S4[0][12] = 11; S4[0][13] S4[1][0] = 13; S4[1][1] S4[1][4] = 6; S4[1][5] = S4[1][8] = 4; S4[1][9] = S4[1][12] = 1; S4[1][13] S4[2][0] = 10; S4[2][1] S4[2][4] = 12; S4[2][5] = S4[2][8] = 15; S4[2][9] = S4[2][12] = 5; S4[2][13] S4[3][0] = 3; S4[3][1] S4[3][4] = 10; S4[3][5] = S4[3][8] = 9; S4[3][9] = S4[3][12] = 12; S4[3][13] = 13; S4[0][2] = 14; S4[0][3] = 3; 6; S4[0][6] = 9; S4[0][7] = 10; 2; S4[0][10] = 8; S4[0][11] = 5; = 12; S4[0][14] = 4; S4[0][15] = 15; = 8; S4[1][2] = 11; S4[1][3] = 5; 15; S4[1][6] = 0; S4[1][7] = 3; 7; S4[1][10] = 2; S4[1][11] = 12; = 10; S4[1][14] = 14; S4[1][15] = 9; = 6; S4[2][2] = 9; S4[2][3] = 0; 11; S4[2][6] = 7; S4[2][7] = 13; 1; S4[2][10] = 3; S4[2][11] = 14; = 2; S4[2][14] = 8; S4[2][15] = 4; = 15; S4[3][2] = 0; S4[3][3] = 6; 1; S4[3][6] = 13; S4[3][7] = 8; 4; S4[3][10] = 5; S4[3][11] = 11; = 7; S4[3][14] = 2; S4[3][15] = 14; //5° S5[0][0] = 2; S5[0][1] S5[0][4] = 7; S5[0][5] = S5[0][8] = 8; S5[0][9] = S5[0][12] = 13; S5[0][13] S5[1][0] = 14; S5[1][1] S5[1][4] = 4; S5[1][5] = S5[1][8] = 5; S5[1][9] = S5[1][12] = 3; S5[1][13] S5[2][0] = 4; S5[2][1] S5[2][4] = 10; S5[2][5] = S5[2][8] = 15; S5[2][9] = S5[2][12] = 6; S5[2][13] S5[3][0] = 11; S5[3][1] S5[3][4] = 1; S5[3][5] = S5[3][8] = 6; S5[3][9] = S5[3][12] = 10; S5[3][13] = 12; S5[0][2] = 4; S5[0][3] = 1; 10; S5[0][6] = 11; S5[0][7] = 6; 5; S5[0][10] = 3; S5[0][11] = 15; = 0; S5[0][14] = 14; S5[0][15] = 9; = 11; S5[1][2] = 2; S5[1][3] = 12; 7; S5[1][6] = 13; S5[1][7] = 1; 0; S5[1][10] = 15; S5[1][11] = 10; = 9; S5[1][14] = 8; S5[1][15] = 6; = 2; S5[2][2] = 1; S5[2][3] = 11; 13; S5[2][6] = 7; S5[2][7] = 8; 9; S5[2][10] = 12; S5[2][11] = 5; = 3; S5[2][14] = 0; S5[2][15] = 14; = 8; S5[3][2] = 12; S5[3][3] = 7; 14; S5[3][6] = 2; S5[3][7] = 13; 15; S5[3][10] = 0; S5[3][11] = 9; = 4; S5[3][14] = 5; S5[3][15] = 3; //6° S6[0][0] = 12; S6[0][1] S6[0][4] = 9; S6[0][5] = S6[0][8] = 0; S6[0][9] = S6[0][12] = 14; S6[0][13] = 1; S6[0][2] = 10; S6[0][3] = 15; 2; S6[0][6] = 6; S6[0][7] = 8; 13; S6[0][10] = 3; S6[0][11] = 4; = 7; S6[0][14] = 5; S6[0][15] = 11; 134 Appendice F S6[1][0] = 10; S6[1][1] S6[1][4] = 7; S6[1][5] = S6[1][8] = 6; S6[1][9] = S6[1][12] = 0; S6[1][13] S6[2][0] = 9; S6[2][1] S6[2][4] = 2; S6[2][5] = S6[2][8] = 7; S6[2][9] = S6[2][12] = 1; S6[2][13] S6[3][0] = 4; S6[3][1] S6[3][4] = 9; S6[3][5] = S6[3][8] = 11; S6[3][9] = S6[3][12] = 6; S6[3][13] = 15; S6[1][2] = 4; S6[1][3] = 2; 12; S6[1][6] = 9; S6[1][7] = 5; 1; S6[1][10] = 13; S6[1][11] = 14; = 11; S6[1][14] = 3; S6[1][15] = 8; = 14; S6[2][2] = 15; S6[2][3] = 5; 8; S6[2][6] = 12; S6[2][7] = 3; 0; S6[2][10] = 4; S6[2][11] = 10; = 13; S6[2][14] = 11; S6[2][15] = 6; = 3; S6[3][2] = 2; S6[3][3] = 12; 5; S6[3][6] = 15; S6[3][7] = 10; 14; S6[3][10] = 1; S6[3][11] = 7; = 0; S6[3][14] = 8; S6[3][15] = 13; //7° S7[0][0] = 4; S7[0][1] S7[0][4] = 15; S7[0][5] = S7[0][8] = 3; S7[0][9] = S7[0][12] = 5; S7[0][13] S7[1][0] = 13; S7[1][1] S7[1][4] = 4; S7[1][5] = S7[1][8] = 14; S7[1][9] = S7[1][12] = 2; S7[1][13] S7[2][0] = 1; S7[2][1] S7[2][4] = 12; S7[2][5] = S7[2][8] = 10; S7[2][9] = S7[2][12] = 0; S7[2][13] S7[3][0] = 6; S7[3][1] S7[3][4] = 1; S7[3][5] = S7[3][8] = 9; S7[3][9] = S7[3][12] = 14; S7[3][13] = 11; S7[0][2] = 2; S7[0][3] = 14; 0; S7[0][6] = 8; S7[0][7] = 13; 12; S7[0][10] = 9; S7[0][11] = 7; = 10; S7[0][14] = 6; S7[0][15] = 1; = 0; S7[1][2] = 11; S7[1][3] = 7; 9; S7[1][6] = 1; S7[1][7] = 10; 3; S7[1][10] = 5; S7[1][11] = 12; = 15; S7[1][14] = 8; S7[1][15] = 6; = 4; S7[2][2] = 11; S7[2][3] = 13; 3; S7[2][6] = 7; S7[2][7] = 14; 15; S7[2][10] = 6; S7[2][11] = 8; = 5; S7[2][14] = 9; S7[2][15] = 2; = 11; S7[3][2] = 13; S7[3][3] = 8; 4; S7[3][6] = 10; S7[3][7] = 7; 5; S7[3][10] = 0; S7[3][11] = 15; = 2; S7[3][14] = 3; S7[3][15] = 12; //8° S8[0][0] = 13; S8[0][1] S8[0][4] = 6; S8[0][5] = S8[0][8] = 10; S8[0][9] = S8[0][12] = 5; S8[0][13] S8[1][0] = 1; S8[1][1] S8[1][4] = 10; S8[1][5] = S8[1][8] = 12; S8[1][9] = S8[1][12] = 0; S8[1][13] S8[2][0] = 7; S8[2][1] S8[2][4] = 9; S8[2][5] = S8[2][8] = 0; S8[2][9] = S8[2][12] = 15; S8[2][13] S8[3][0] = 2; S8[3][1] S8[3][4] = 4; S8[3][5] = S8[3][8] = 15; S8[3][9] = S8[3][12] = 3; S8[3][13] = 2; S8[0][2] = 8; S8[0][3] = 4; 15; S8[0][6] = 11; S8[0][7] = 1; 9; S8[0][10] = 3; S8[0][11] = 14; = 0; S8[0][14] = 12; S8[0][15] = 7; = 15; S8[1][2] = 13; S8[1][3] = 8; 3; S8[1][6] = 7; S8[1][7] = 4; 5; S8[1][10] = 6; S8[1][11] = 11; = 14; S8[1][14] = 9; S8[1][15] = 2; = 11; S8[2][2] = 4; S8[2][3] = 1; 12; S8[2][6] = 14; S8[2][7] = 2; 6; S8[2][10] = 10; S8[2][11] = 13; = 3; S8[2][14] = 5; S8[2][15] = 8; = 1; S8[3][2] = 14; S8[3][3] = 7; 10; S8[3][6] = 8; S8[3][7] = 13; 12; S8[3][10] = 9; S8[3][11] = 0; = 5; S8[3][14] = 6; S8[3][15] = 11; //Inizializzazione dell'array delle rotazioni Rotation_Array[0] = 1; Rotation_Array[1] = 1; Rotation_Array[2] = 2; Rotation_Array[3] = 2; Rotation_Array[4] = 2; Rotation_Array[5] = 2; Rotation_Array[6] = 2; Rotation_Array[7] = 2; Rotation_Array[8] = 1; Rotation_Array[9] = 2; Rotation_Array[10] = 2; Rotation_Array[11] = 2; Rotation_Array[12] = 2; 135 Appendice F Rotation_Array[13] = 2; Rotation_Array[14] = 2; Rotation_Array[15] = 1; } CDes::~CDes() { } void CDes::Crypt(LPTSTR Key, LPTSTR Data) { unsigned C[8][7]; unsigned Index_Array[64]; unsigned __int64 iCrypted = 0; unsigned __int64 iData = 0; unsigned __int64 iKey = 0; int k = 0; int iLen = 0; int iIter = 0; int iIter_Mod = 0; iLen = strlen(Data); if (iLen < 8) iIter++; else { iIter = iLen / 8; iIter_Mod = iLen % 8; if (iIter_Mod != 0) iIter++; } char *strData = new char[8]; char *strCrypt = new char[64]; char *strRes = new char[iIter * 8]; unsigned __int64 *arrayCrypt = new unsigned __int64[iIter]; strcpy(strRes," "); strcpy(strCrypt," "); iKey = _atoi64(Key); Set_Key(iKey); itoar(iKey,Index_Array,64); Reduce64to56(Index_Array,C); Calculate_Keys(C,16); for (register int i=0;i<iIter;i++) { strcpy(strData," "); for (register int j=0;j<8;j++) { if (k > iLen) strData[j] = NULL; else { strData[j] = Data[k]; k++; } } iData = stoi(strData,iLen); 136 Appendice F arrayCrypt[i] = crypt(iData,16); } for (i=0;i<iIter;i++) { itos(strCrypt,arrayCrypt[i],8); _strcat(strRes,strCrypt); } strcpy(Data,strRes); delete delete delete delete [] [] [] [] strData; strCrypt; strRes; arrayCrypt; } void CDes::Decrypt(LPTSTR Key, LPTSTR Data) { unsigned C[8][7]; unsigned Index_Array[64]; unsigned __int64 iCrypted = 0; unsigned __int64 iData = 0; unsigned __int64 iKey = 0; int k = 0; int iLen = 0; int iIter = 0; int iIter_Mod = 0; iLen = strlen(Data); if (iLen < 8) iIter++; else { iIter = iLen / 8; iIter_Mod = iLen % 8; if (iIter_Mod != 0) iIter++; } char *strData = new char[8]; char *strCrypt = new char[64]; char *strRes = new char[iIter * 8]; unsigned __int64 *arrayCrypt = new unsigned __int64[iIter]; strcpy(strRes," "); strcpy(strCrypt," "); iKey = _atoi64(Key); Set_Key(iKey); itoar(iKey,Index_Array,64); Reduce64to56(Index_Array,C); Calculate_Keys(C,16); for (register int i=0;i<iIter;i++) { strcpy(strData," "); for (register int j=0;j<8;j++) { if (k > iLen) strData[j] = NULL; 137 Appendice F else { strData[j] = Data[k]; k++; } } iData = stoi(strData,iLen); arrayCrypt[i] = decrypt(iData,16); } for (i=0;i<iIter;i++) { itos(strCrypt,arrayCrypt[i],8); _strcat(strRes,strCrypt); } strcpy(Data,strRes); delete delete delete delete [] [] [] [] strData; strCrypt; strRes; arrayCrypt; } ////////////////////////////////////////////////////////////////// //PROTOTIPO : void Calculate_Keys(unsigned int matrix[][7], // unsigned int iterations) //INPUT : matrix[][7] -> matrice ridotta // iterations -> iterazioni //DESCRIZIONE // La funzione calcola le chiavi usate per la crittazione. Il //numero di chiavi da calcolare è definito dalla variabile //iterations. ////////////////////////////////////////////////////////////////// void CDes::Calculate_Keys(unsigned int matrix[][7], unsigned int iterations) { unsigned unsigned unsigned unsigned matrixKey[8][6]; __int64 iMsb = 0; __int64 iLsb = 0; __int64 iKey = 0; unsigned unsigned unsigned unsigned *arrayMsb *arrayLsb *arrayCat *arrayKey = = = = new new new new unsigned[28]; unsigned[28]; unsigned[56]; unsigned[48]; //Vengono creati due array, il primo con la parte bassa della //matrice il secondo con la parte alta. La matrice utilizzata è //quella contenente la chiave ridotta a 56 bit. matoar56(matrix,arrayLsb,0,0,4,7); matoar56(matrix,arrayMsb,4,0,8,7); //Vengono convertiti gli array prima calcolati in due interi. iMsb = artoi(arrayMsb,28); //D(0) iLsb = artoi(arrayLsb,28); //C(0) //Ciclo principale che permette il calcolo delle chiavi. for (register unsigned i=0;i<iterations;i++) 138 Appendice F { //Vengono shiftati i valori precedentemente calcolati //secondo il valore contenuto nel array Rotation_Array. shift(iMsb,Rotation_Array[i]); shift(iLsb,Rotation_Array[i]); //I valori appena calcolati vengono convertiti in array. itoar(iMsb,arrayMsb,28); itoar(iLsb,arrayLsb,28); //Gli array appena calcolati vengono concatenati in uno //solo. arcat(arrayLsb,arrayMsb,arrayCat,28,28); //L'array appena calcolato viene ridotto, e trasformato //in una matrice. Reduce56to48(arrayCat,matrixKey); //La matrice risultante dall'ultima operazione viene //trasformata in un array. matoar48(matrixKey,arrayKey,0,0,8,6); //L'array ottenuto viene trasformato in un intero che //sarà la chiave. iKey = artoi(arrayKey,48); //La chiave viene memorizzata. Keys_Array[i] = iKey; } delete delete delete delete [] [] [] [] arrayMsb; arrayLsb; arrayCat; arrayKey; } ////////////////////////////////////////////////////////////////// //PROTOTIPO : unsigned __int64 decrypt(unsigned __int64 data, // unsigned int iterations) //INPUT : data -> dati da decifrare // iterations -> iterazioni //OUTPUT : iRes -> dati cifrati //DESCRIZIONE // La funzione decritta il dato passato. La variabile iterations //indica, implicitamente, il numero di chiavi da usare per la //cifratura. ////////////////////////////////////////////////////////////////// unsigned __int64 CDes::decrypt(unsigned __int64 data, unsigned int iterations) { unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned matrixData[8][8]; matrixExp[8][6]; matrixPer[8][4]; __int64 iExp = 0; __int64 iXor = 0; __int64 iRes = 0; __int64 iCrypted = 0; j = 0; x = 16; 139 Appendice F unsigned unsigned unsigned unsigned *arrayData = new unsigned[64]; *arrayLR = new unsigned[32]; *arrayExp = new unsigned[48]; *arraySBox = new unsigned[8]; //I dati passati vengono convertiti in un array. itoar(data,arrayData,64); //L'array ottenuto viene permutato. Il risultato sarà una //matrice. Permute_IP(arrayData,matrixData); //La parte bassa della matrice viene convertita in un array. matoar64(matrixData,arrayLR,0,0,4,8); //L'array risultante viene convertito in un intero. Sarà il //primo blocco cifrato. L[0] = artoi(arrayLR,32); //Vengono effettuate le stesse operazioni precedenti, con //la parte alta della matrice. matoar64(matrixData,arrayLR,4,0,8,8); R[0] = artoi(arrayLR,32); //Il ciclo applica al blocco dati tutte le chiavi calcolate in //precedenza. for (register unsigned i=0;i<iterations + 1;i++) { //Il blocco cifrato R[i] viene converito in un array. itoar(L[i],arrayLR,32); //All'array risultante viene applicata la matrice di //espansione. Expand(arrayLR,matrixExp); //La matrice ottenuta viene convertita in una array. matoar48(matrixExp,arrayExp,0,0,8,6); //L'array ottenuto viene convertito in un intero. iExp = artoi(arrayExp,48); //Viene fatta un XOR con il risultato e la chiave //corrispondente all'iterazione. iXor = iExp ^ Keys_Array[x]; //Il risultato viene convertito in un array. itoar(iXor,arrayExp,48); //L'array risultante viene diviso in gruppi di 6 bit. Divide(arrayExp,matrixExp,48,6); //Per ogni gruppo di 6 bit (8 in totale), viene //calcolato il rispettivo coefficiente contenuto //nella S-box corrispondente. arraySBox[j] = Index(matrixExp,S1,j); j++; arraySBox[j] = Index(matrixExp,S2,j); j++; arraySBox[j] = Index(matrixExp,S3,j); j++; arraySBox[j] = Index(matrixExp,S4,j); 140 Appendice F j++; arraySBox[j] j++; arraySBox[j] j++; arraySBox[j] j++; arraySBox[j] j++; = Index(matrixExp,S5,j); = Index(matrixExp,S6,j); = Index(matrixExp,S7,j); = Index(matrixExp,S8,j); //I coefficienti ricavati dalle S-box vengono //riuniti in un unico array. Group(arraySBox,arrayLR,32,4); //L'array ottenuto viene permutato. Permute_P2(arrayLR,matrixPer); //La matrice ottenuta viene convertita in un array. matoar32(matrixPer,arrayLR,0,0,8,4); //L'array viene convertito in un intero. iRes = artoi(arrayLR,32); //Viene fatta una XOR con il blocco dati appena //cifrato e quello precedente. L[i] = iRes ^ R[i + 1]; R[i] = L[i + 1]; j = 0; x--; } j = 0; //L'ultimo blocco cifrato di R e di L viene convertito in //un array e concatenato. itoar(R[iterations],arrayLR,32); for (register int k=0;k<32;k++) { arrayData[j] = arrayLR[k]; j++; } itoar(L[iterations],arrayLR,32); for (k=0;k<32;k++) { arrayData[j] = arrayLR[k]; j++; } //L'array ottenuto viene permutato. Permute_FP(arrayData,matrixData); //La matrice ottenuta viene convertita in un array. matoar64(matrixData,arrayData,0,0,8,8); //L'array viene convertito in un array. Questo sarà il //dato cifrato. iCrypted = artoi(arrayData,64); 141 Appendice F delete delete delete delete [] [] [] [] arrayData; arrayLR; arrayExp; arraySBox; return iCrypted; } ////////////////////////////////////////////////////////////////// //PROTOTIPO : unsigned __int64 crypt(unsigned __int64 data, // unsigned int iterations) //INPUT : data -> dati da cifrare // iterations -> iterazioni //OUTPUT : iRes -> dati cifrati //DESCRIZIONE // La funzione critta il dato passato. La variabile iterations //indica, implicitamente, il numero di chiavi da usare per la //cifratura. ////////////////////////////////////////////////////////////////// unsigned __int64 CDes::crypt(unsigned __int64 data, unsigned int iterations) { unsigned unsigned unsigned unsigned unsigned unsigned unsigned unsigned matrixData[8][8]; matrixExp[8][6]; matrixPer[8][4]; __int64 iExp = 0; __int64 iXor = 0; __int64 iRes = 0; __int64 iCrypted = 0; j = 0; unsigned unsigned unsigned unsigned *arrayData = new unsigned[64]; *arrayLR = new unsigned[32]; *arrayExp = new unsigned[48]; *arraySBox = new unsigned[8]; //I dati passati vengono convertiti in un array. itoar(data,arrayData,64); //L'array ottenuto viene permutato. Il risultato sarà una //matrice. Permute_IP(arrayData,matrixData); //La parte bassa della matrice viene convertita in un array. matoar64(matrixData,arrayLR,0,0,4,8); //L'array risultante viene convertito in un intero. Sarà il //primo blocco cifrato. L[0] = artoi(arrayLR,32); //Vengono effettuate le stesse operazioni precedenti, con //la parte alta della matrice. matoar64(matrixData,arrayLR,4,0,8,8); R[0] = artoi(arrayLR,32); //Il ciclo applica al blocco dati tutte le chiavi calcolate in //precedenza. for (register unsigned i=0;i<iterations + 1;i++) { 142 Appendice F //Il blocco cifrato R[i] viene converito in un array. itoar(R[i],arrayLR,32); //All'array risultante viene applicata la matrice di //espansione. Expand(arrayLR,matrixExp); //La matrice ottenuta viene convertita in una array. matoar48(matrixExp,arrayExp,0,0,8,6); //L'array ottenuto viene convertito in un intero. iExp = artoi(arrayExp,48); //Viene fatta un XOR con il risultato e la chiave //corrispondente all'iterazione. iXor = iExp ^ Keys_Array[i]; //Il risultato viene convertito in un array. itoar(iXor,arrayExp,48); //L'array risultante viene diviso in gruppi di 6 bit. Divide(arrayExp,matrixExp,48,6); //Per ogni gruppo di 6 bit (8 in totale), viene //calcolato il rispettivo coefficiente contenuto //nella S-box corrispondente. arraySBox[j] = Index(matrixExp,S1,j); j++; arraySBox[j] = Index(matrixExp,S2,j); j++; arraySBox[j] = Index(matrixExp,S3,j); j++; arraySBox[j] = Index(matrixExp,S4,j); j++; arraySBox[j] = Index(matrixExp,S5,j); j++; arraySBox[j] = Index(matrixExp,S6,j); j++; arraySBox[j] = Index(matrixExp,S7,j); j++; arraySBox[j] = Index(matrixExp,S8,j); j++; //I coefficienti ricavati dalle S-box vengono //riuniti in un unico array. Group(arraySBox,arrayLR,32,4); //L'array ottenuto viene permutato. Permute_P2(arrayLR,matrixPer); //La matrice ottenuta viene convertita in un array. matoar32(matrixPer,arrayLR,0,0,8,4); //L'array viene convertito in un intero. iRes = artoi(arrayLR,32); //Viene fatta una XOR con il blocco dati appena //cifrato e quello precedente. R[i + 1] = iRes ^ L[i]; L[i + 1] = R[i]; j = 0; } 143 Appendice F j = 0; //L'ultimo blocco cifrato di R e di L viene convertito in //un array e concatenato. itoar(R[iterations],arrayLR,32); for (register int k=0;k<32;k++) { arrayData[j] = arrayLR[k]; j++; } itoar(L[iterations],arrayLR,32); for (k=0;k<32;k++) { arrayData[j] = arrayLR[k]; j++; } //L'array ottenuto viene permutato. Permute_FP(arrayData,matrixData); //La matrice ottenuta viene convertita in un array. matoar64(matrixData,arrayData,0,0,8,8); //L'array viene convertito in un array. Questo sarà il //dato cifrato. iCrypted = artoi(arrayData,64); delete delete delete delete [] [] [] [] arrayData; arrayLR; arrayExp; arraySBox; return iCrypted; } ////////////////////////////////////////////////////////////////// //PROTOTIPO : unsigned __int64 artoi(unsigned int *array, // unsigned int length) //INPUT : array -> array da convertire // length -> lunghezza dell'array //OUTPUT : iRes -> array convertito //DESCRIZIONE // La funzione converte un array binario (composto da 0 o 1) in un //intero a 64 bit. La funzione non effettua nessun controllo // sulla lunghezza dell'array, ma è implicito che esso non debba //superare i 64 byte. Di conseguenza ogni controllo deve essere // effettuato prima della chiamata alla funzione. ////////////////////////////////////////////////////////////////// unsigned _int64 CDes::artoi(unsigned int *array, unsigned int length) { unsigned __int64 iBit = 0; unsigned __int64 iRes = 0; unsigned j = 0; for (register int i=length - 1;i>=0;i--) { 144 Appendice F iBit = array[i]; iBit = iBit << j; iRes |= iBit; j++; } return iRes; } ////////////////////////////////////////////////////////////////// //PROTOTIPO : void itoar(unsigned __int64 int64, unsigned int // *array, unsigned int length) //INPUT : int64 -> intero da convetire // array -> array in cui inserire l'intero convertito // length -> lunghezza dell'array //DESCRIZIONE // La funzione converte un intero fino a 64 bit in un array //binario (composto da 0 e 1). La funzione non effettua nessun // controllo sulla lunghezza dell'array, ma è implicito che esso //debba essere lungo tanto quanto la variabile da convertire e // non più del tipo più grande (unsigned __int64). Di conseguenza //ogni controllo deve essere effettuato prima della chiamata alla // funzione. ////////////////////////////////////////////////////////////////// void CDes::itoar(unsigned __int64 int64, unsigned int *array, unsigned int length) { unsigned __int64 iCopy = 0; unsigned __int64 j = 1; unsigned k = 0; for (register int i=length - 1;i>=0;i--) { j = power(2,i); iCopy = int64 & j; switch (iCopy) { case 0 : array[k] = 0; k++; break; default : array[k] = 1; k++; } } } ////////////////////////////////////////////////////////////////// //PROTOTIPO : void stoi(char *string, unsigned int length) //INPUT : string -> stringa da convertire // length -> lunghezza della stringa //OUTPUT : iRes -> stringa convertita //DESCRIZIONE // La funzione converte una stringa in un intero a 64 bit. La //funzione non effettua nessun controllo sulla lunghezza della //stringa,ma è implicito che essa non debba superare i 64 byte. Di //conseguenza ogni controllo deve essere effettuato prima della // chiamata alla funzione. ////////////////////////////////////////////////////////////////// unsigned _int64 CDes::stoi(char *string, unsigned int length) { unsigned __int64 iRes = 0; unsigned __int64 x = 0; 145 Appendice F for (register unsigned i=0;i<length;i++) { x = string[i]; x = x << 8 * i; iRes |= x; } return iRes; } void CDes::itos(char *string, unsigned __int64 int64, unsigned int length) { unsigned __int64 x = 0; register unsigned j = 0; for (register unsigned i=0;i<length;i++) { x = int64; x = x >> 8 * i; string[j] = (char )x; j++; } string[length] = NULL; } /////Le seguenti funzioni convertono una matrice in un array////// ////////////////////////////////////////////////////////////////// //PROTOTIPO : void matoarXX(unsigned int matrix[][4], unsigned // int *array, unsigned int yStart, unsigned int xStart, // unsigned int yEnd, unsigned int xEnd) //INPUT : matrix[][x] -> matrice da convertire // array -> array risultato // yStart -> linea di partenza // xStart -> colonna di partenza // yEnd -> linea di arrivo // xEnd -> colonna di arrivo //DESCRIZIONE // Le funzioni convertono una matrice di n righe e m colonne, in //un array pari alla loro dimensione. I parametri indicano // implicitamente il numero di elementi da estrarre dalla matrice. //La funzione non effettua nessun controllo sulla lunghezza // dell' array che deve essere di lunghezza minima pari alla //grandezza della matrice. Di conseguenza ogni controllo deve //essere effettuato prima della chiamata alla funzione. ////////////////////////////////////////////////////////////////// void CDes::matoar32(unsigned int matrix[][4], unsigned int *array, unsigned int yStart, unsigned int xStart, unsigned int yEnd, unsigned int xEnd) { register unsigned j = 0; for (register unsigned y=yStart;y<yEnd;y++) for (register unsigned x=xStart;x<xEnd;x++) { array[j] = matrix[y][x]; j++; } 146 Appendice F } void CDes::matoar48(unsigned int matrix[][6], unsigned int *array, unsigned int yStart, unsigned int xStart, unsigned int yEnd, unsigned int xEnd) { register unsigned j = 0; for (register unsigned y=yStart;y<yEnd;y++) for (register unsigned x=xStart;x<xEnd;x++) { array[j] = matrix[y][x]; j++; } } void CDes::matoar56(unsigned int matrix[][7], unsigned int *array, unsigned int yStart, unsigned int xStart, unsigned int yEnd, unsigned int xEnd) { register unsigned j = 0; for (register unsigned y=yStart;y<yEnd;y++) for (register unsigned x=xStart;x<xEnd;x++) { array[j] = matrix[y][x]; j++; } } void CDes::matoar64(unsigned int matrix[][8], unsigned int *array, unsigned int yStart, unsigned int xStart, unsigned int yEnd, unsigned int xEnd) { register unsigned j = 0; for (register unsigned y=yStart;y<yEnd;y++) for (register unsigned x=xStart;x<xEnd;x++) { array[j] = matrix[y][x]; j++; } } ////////////////////////////////////////////////////////////////// //PROTOTIPO :unsigned __int64 power(unsigned int b,unsigned int e) //INPUT : b -> base // e -> esponente //OUTPUT : x -> risultato //DESCRIZIONE // La funzione calcola l'elevamento a potenza. Sia la base che //l'esponente devono essere non negativi. ////////////////////////////////////////////////////////////////// unsigned _int64 CDes::power(unsigned int b, unsigned int e) { unsigned __int64 x = 1; 147 Appendice F if (e == 0) return x; for (register unsigned __int64 i=1;i<=e;i++) x = x * b; return x; } ////////////////////////////////////////////////////////////////// //PROTOTIPO : void shift(unsigned __int64 &shift, unsigned int // n_Shift) //INPUT : shift -> valore da shiftare // n_Shift -> numero di shift (1 o 2) //OUTPUT : shift -> valore shiftato //DESCRIZIONE // La funzione simula uno shift circolare supponendo che l'intero //passato come parametro sia di soli 6 bit. ////////////////////////////////////////////////////////////////// void CDes::shift(unsigned __int64 &shift, unsigned int nShift) { unsigned __int64 iCopy; iCopy = shift; switch (nShift) { case 1 : if ((shift & 0x8000000) != 0) { iCopy &= 0x3ffffff; iCopy = iCopy << 1; iCopy++; } else iCopy = iCopy << 1; break; case 2 : if ((shift & 0x8000000) != 0) { iCopy &= 0x7ffffff; iCopy = iCopy << 1; iCopy++; } else iCopy = iCopy << 1; if ((iCopy & 0x8000000) != 0) { iCopy &= 0x7ffffff; iCopy = iCopy << 1; iCopy ++; } else iCopy = iCopy << 1; } shift = iCopy; } ////////////////////////////////////////////////////////////////// //PROTOTIPO : void arcat(unsigned int *arrayOr1, unsigned int // *arrayOr2, unsigned int *arrayDest, // unsigned int lenOr1, // unsigned int lenOr2) //INPUT : arrayOr1 -> primo array da concatenare // arrayOr2 -> secondo array da concatenare // arrayDest -> array risultato 148 Appendice F // lenOr1 -> lunghezza del primo array // lenOr2 -> lunghezza del secondo array //DESCRIZIONE // La funzione concatena due array della lunghezza specificata dai //parametri lenOr1 e lenOr2. La funzione non effettua il controllo //sulla lunghezza degli array, di conseguenza tutti i controlli //devono essere fatti prima della chiamata alla funzione. ////////////////////////////////////////////////////////////////// void CDes::arcat(unsigned int *arrayOr1, unsigned int *arrayOr2, unsigned int *arrayDest, unsigned int lenOr1, unsigned lenOr2) { register unsigned j = 0; for (register unsigned i=0;i<lenOr1;i++) { arrayDest[j] = arrayOr1[i]; j++; } for (i=0;i<lenOr2;i++) { arrayDest[j] = arrayOr2[i]; j++; } } ////////////////////////////////////////////////////////////////// //PROTOTIPO : void _strcat(char *strDest, char *strOr) //INPUT : strDest -> stringa destinazione // strOr -> stringa d'origine //DESCRIZIONE // La funzione concatena due stringhe. La stringa risultante sarà //contenuta in strDest,inoltre essa sarà del tipo null-terminated. ////////////////////////////////////////////////////////////////// void CDes::_strcat(char *strDest, char *strOr) { int lenDest, lenOr; lenDest = strlen(strDest); lenOr = strlen(strOr); for (register int i=0;i<lenOr;i++) { strDest[lenDest - 1] = strOr[i]; lenDest ++; } strDest[i + 1] = NULL; } //Le seguenti funzioni applicano una matrice predefinita ad un array// ////////////////////////////////////////////////////////////////// //PROTOTIPO : void NOME_FUNZIONE(unsigned int *array, unsigned // int matrix[][x]) //INPUT : array -> array a cui applicare la matrice // matrix[][x] -> matrice risultante //DESCRIZIONE // Le funzioni applicano la matrice specificata, costruendone una 149 Appendice F //risultante dall'operazione. Le funzioni seguono lo stesso // principio di funzionamento, cambia solo la matrice applicata //(si differenziano, oltre che per i valori, per la grandezza). // Di seguito sono riassunte le funzioni con le matrici applicate. // Reduce56to48 -> P1 = prima matrice di permutazione // Reduce64to56 -> R1 = matrice di riduzione // Permute_IP -> IP = matrice di permutazione iniziale // Permute_P2 -> P2 = seconda matrice di permutazione // Permute_FP -> FP = matrice di permutazione finale // Expand -> EX = matrice di espansione ////////////////////////////////////////////////////////////////// void CDes::Reduce56to48(unsigned int *array, unsigned int matrix[][6]) { for (register int y=0;y<8;y++) for (register int x=0;x<6;x++) matrix[y][x] = array[P1[y][x] - 1]; } void CDes::Reduce64to56(unsigned int *array, unsigned int matrix[][7]) { for (register int y=0;y<8;y++) for (register int x=0;x<7;x++) matrix[y][x] = array[R1[y][x] - 1]; } void CDes::Permute_IP(unsigned int *array, unsigned int matrix[][8]) { for (register int y=0;y<8;y++) for (register int x=0;x<8;x++) matrix[y][x] = array[IP[y][x] - 1]; } void CDes::Permute_P2(unsigned int *array, unsigned int matrix[][4]) { for (register int y=0;y<8;y++) for (register int x=0;x<4;x++) matrix[y][x] = array[P2[y][x] - 1]; } void CDes::Permute_FP(unsigned int *array, unsigned int matrix[][8]) { for (register int y=0;y<8;y++) for (register int x=0;x<8;x++) matrix[y][x] = array[FP[y][x] - 1]; } void CDes::Expand(unsigned int *array, unsigned int matrix[][6]) { 150 Appendice F for (register int y=0;y<8;y++) for (register int x=0;x<6;x++) matrix[y][x] = array[EX[y][x] - 1]; } ////////////////////////////////////////////////////////////////// //PROTOTIPO : void Divide(unsigned int *array, unsigned int // matrix[][6], unsigned int lenAr, // unsigned int lenGrp) //INPUT : array -> array da dividere // matrix -> matrice risultato // lenAr -> lunghezza array // lenGrp -> lunghezza gruppo //DESCRIZIONE // La funzione divide un array in gruppi della lunghezza //specificata dalla variabile lenGrp. La massima grandezza //dell'array è di 48 byte, di conseguenza la grandezza massima della matrice sarà 8*6. La funzione non effettua nessun controllo sulla // lunghezza dell'array e sulla grandezza della matrice. Di //conseguenza ogni controllo deve essere fatto prima della //chiamata alla funzione. ////////////////////////////////////////////////////////////////// void CDes::Divide(unsigned int *array, unsigned int matrix[][6], unsigned int lenAr, unsigned int lenGrp) { register unsigned j = 0; unsigned y = 0; while (j < lenAr) { for (register unsigned x=0;x<lenGrp;x++) { matrix[y][x] = array[j]; j++; } y++; } } ////////////////////////////////////////////////////////////////// //PROTOTIPO : void Group(unsigned int *array, unsigned int // *arrayGrp, unsigned int lenAr, unsigned // int lenGrp) //INPUT : array -> array da raggruppare // arrayGrp -> array risultato // lenAr -> lunghezza array // lenGrp -> lunghezza dei gruppi //DESCRIZIONE // La funzione unisce un array di interi (NON binario) in un unico //array. La lunghezza dell'array e quella dei gruppi di bit // viene passata come parametro. ////////////////////////////////////////////////////////////////// void CDes::Group(unsigned int *array, unsigned int *arrayGrp, unsigned int lenAr, unsigned int lenGrp) { 151 Appendice F unsigned unsigned register register iCopy = 0; j = 1; unsigned k = 0; unsigned y = 0; while (k < lenAr) { for (register int i=lenGrp - 1;i>=0;i--) { j = power(2,i); iCopy = array[y] & j; switch (iCopy) { case 0 : arrayGrp[k] = 0; k++; break; default : arrayGrp[k] = 1; k++; } } y++; } } ////////////////////////////////////////////////////////////////// //PROTOTIPO : unsigned Index(unsigned int matDiv[][6], unsigned // int matrix[][6], unsigned row) //INPUT : matDiv[][6] -> matrice da indicizzare // matrix -> matrice da cui estrarre i dati // row -> riga della matrice da indicizzare //OUTPUT : iRes -> risultato //DESCRIZIONE // La funzione preleva dalla matrice matDiv il valore binario e lo //converte in modo da comporre le coordinate di ricerca // (m = colonna, n = riga). L'intero risultato della ricerca verrà //restituito. ////////////////////////////////////////////////////////////////// unsigned CDes::Index(unsigned int matDiv[][6], unsigned int matrix[][16],unsigned row) { unsigned m = 0; unsigned n = 0; unsigned iRes = 0; if (matDiv[row][0] != 0) m += 2; if (matDiv[row][5] != 0) m ++; if if if if (matDiv[row][1] (matDiv[row][2] (matDiv[row][3] (matDiv[row][4] != != != != 0) 0) 0) 0) n n n n += 8; += 4; += 2; ++; iRes = matrix[m][n]; return iRes; } ////////////////////////////////////////////////////////////////// //PROTOTIPO : void Set_Key(unsigned __int64 newKey) //INPUT : newKey -> nuova chiave //DESCRIZIONE // Funzione di interfaccia che setta la chiave. 152 Appendice F ////////////////////////////////////////////////////////////////// void CDes::Set_Key(unsigned __int64 newKey) { Key = newKey; } 3 Crittografia Private Function Scan(strC As String) As String For i = 0 To 26 If (PLOT(i, 0) = strC) Then PLOT(i, 1) = PLOT(i, 1) + 1 GoTo End_Function End If Next i Scan = False Exit Function End_Function: Scan = True End Function Private Function OpenFile(strFileToOpen As String) As String Dim strFileOpen As String Dim objFS, txtFile Set objFS = CreateObject("Scripting.FileSystemObject") Set txtFile = objFS.OpenTextFile(strFileToOpen) Do While txtFile.AtEndOfStream <> True c = txtFile.Read(1) Scan (LCase(c)) strFileOpen = strFileOpen & c Loop txtFile.Close OpenFile = strFileOpen End Function Private Function SaveFile(strFileToSave As String, strFileSave As String) As Boolean On Error GoTo Err_Handler Dim objFS, txtFile Set objFS = CreateObject("Scripting.FileSystemObject") Set txtFile = objFS.CreateTextFile(strFileToSave) txtFile.Write (strFileSave) txtFile.Close SaveFile = True Exit Function 153 Appendice F Err_Handler: SaveFile = False End Function Private Sub OpenCl() On Error GoTo Err_Handler Call InitCDL(cdlSaveOpen, "*.txt", "Apri file in chiaro", _ "File di testo (*.txt)|*.txt|Tutti i file (*.*)|*.*|", _ App.Path, "Open") cdlSaveOpen.ShowOpen stbMain.Panels(1).Text = cdlSaveOpen.FileName Err_Handler: End Sub Private Sub SaveCl() On Error GoTo Err_Handler Call InitCDL(cdlSaveOpen, "*.txt", "Salva file in chiaro", _ "File di testo (*.txt)|*.txt|", App.Path, "Save") cdlSaveOpen.ShowSave Err_Handler: End Sub Private Sub OpenCyph() On Error GoTo Err_Handler Dim strFilter As String strFilter = "Cifrario di Cesare (*.csr)|*.csr|Scacchiera di_ Polibio (*.plb)|*.plb|" & _ "Cifrario di Vigénère (*.vgn)|*.vgn|" Call InitCDL(cdlSaveOpen, "*.csr", "Apri file crittato", strFilter, App.Path, "Open") cdlSaveOpen.ShowOpen Err_Handler: End Sub Private Sub SaveCyph() On Error GoTo Err_Handler Dim strFilter As String strFilter = "Cifrario di Cesare (*.csr)|*.csr|Scacchiera di_ Polibio (*.plb)|*.plb|" & _ "Cifrario di Vigénère (*.vgn)|*.vgn|" Call InitCDL(cdlSaveOpen, "*.csr", "Salva file crittato", strFilter, App.Path, "Save") 154 Appendice F cdlSaveOpen.ShowSave Err_Handler: End Sub Private Sub Analize_Click() On Error GoTo Err_Handler If ActiveForm Is Nothing Then InitDOC "" If ActiveForm.txtText.Text = "" Then Clear OpenCl ActiveForm.txtText.Text = OpenFile(cdlSaveOpen.FileName) ActiveForm.Caption = cdlSaveOpen.FileTitle InitGRAPH cdlSaveOpen.FileTitle Else InitGRAPH cdlSaveOpen.FileTitle End If Err_Handler: End Sub Private Sub CaesarCrypt_Click() ActiveForm.txtText.Text = CaesarCyph.Crypt(3, _ ActiveForm.txtText.Text) End Sub Private Sub CaesarDecrypt_Click() ActiveForm.txtText.Text = CaesarCyph.Decrypt(4, _ ActiveForm.txtText.Text) End Sub Private Sub MDIForm_Load() InitVAR InitDOC "" End Sub Private Sub OpenClear_Click() On Error GoTo Err_Handler If ActiveForm Is Nothing Then InitDOC "" Clear OpenCl ActiveForm.txtText.Text = OpenFile(cdlSaveOpen.FileName) ActiveForm.Caption = cdlSaveOpen.FileTitle Err_Handler: End Sub Private Sub OpenCrypt_Click() 155 Appendice F On Error GoTo Err_Handler Dim strKey As String Dim strFile As String Dim iFil As Integer Clear OpenCyph strFile = OpenFile(cdlSaveOpen.FileName) If ActiveForm Is Nothing Then InitDOC "" iFil = cdlSaveOpen.FilterIndex Select Case iFil Case 1: ActiveForm.txtText.Text = CaesarCyph.Decrypt(4,_ strFile) ActiveForm.Caption = cdlSaveOpen.FileTitle Case 2: ActiveForm.txtText.Text = _ PolibioCyph.Decrypt(strFile) ActiveForm.Caption = cdlSaveOpen.FileTitle Case 3: strKey = InputBox("Inserisci la chiave:", _ "Cifrario di Vigénère") ActiveForm.txtText.Text = _ VigenereCyph.Decrypt(strFile, strKey) ActiveForm.Caption = cdlSaveOpen.FileTitle End Select Err_Handler: End Sub Private Sub PolibioCrypt_Click() ActiveForm.txtText.Text = _ PolibioCyph.Crypt(ActiveForm.txtText.Text) End Sub Private Sub PolibioDecrypt_Click() ActiveForm.txtText.Text = _ PolibioCyph.Decrypt(ActiveForm.txtText.Text) End Sub Private Sub Quit_Click() End End Sub Private Sub SaveCrypt_Click() On Error GoTo Err_Handler Dim Dim Dim Dim strKey As String strCyph As String bRet As Boolean iFil As Integer If (ActiveForm.txtText.Text = "") Then GoTo Err_Handler SaveCyph iFil = cdlSaveOpen.FilterIndex Select Case iFil 156 Appendice F Case 1: strCyph = CaesarCyph.Crypt(4, _ ActiveForm.txtText.Text) bRet = SaveFile(cdlSaveOpen.FileName, strCyph) If (bRet = False) Then GoTo Err_Handler Case 2: strCyph = _ PolibioCyph.Crypt(ActiveForm.txtText.Text) bRet = SaveFile(cdlSaveOpen.FileName, strCyph) If (bRet = False) Then GoTo Err_Handler Case 3: strKey = InputBox("Inserisci la chiave:", _ "Cifrario di Vigénère") strCyph = _ VigenereCyph.Crypt(ActiveForm.txtText.Text, strKey) bRet = SaveFile(cdlSaveOpen.FileName, strCyph) If (bRet = False) Then GoTo Err_Handler End Select Exit Sub Err_Handler: MsgBox "Non è stato possibile salvare il file." End Sub Private Sub SaveClear_Click() On Error GoTo Err_Handler Dim bRet As Boolean If (ActiveForm.txtText.Text = "") Then GoTo Err_Handler SaveCl bRet = SaveFile(cdlSaveOpen.FileName, ActiveForm.txtText.Text) If (bRet = False) Then GoTo Err_Handler Exit Sub Err_Handler: MsgBox "Non è stato possibile salvare il file." End Sub Private Sub tlbMain_ButtonClick(ByVal Button As MSComctlLib.Button) Select Case Button.Key Case "New": If ActiveForm Is Nothing Then InitDOC "" Case "OpenClear": OpenClear_Click Case "OpenCyph": OpenCrypt_Click Case "SaveClear": SaveClear_Click Case "SaveCyph": SaveCrypt_Click End Select End Sub Private Sub VigenereCrypt_Click() Dim strKey As String strKey = InputBox("Inserisci la chiave:", "Cifrario di _ Vigénère") ActiveForm.txtText.Text = _ VigenereCyph.Crypt(ActiveForm.txtText.Text, strKey) 157 Appendice F End Sub Private Sub VigenereDecrypt_Click() Dim strKey As String strKey = InputBox("Inserisci la chiave:", "Cifrario di _ Vigénère") ActiveForm.txtText.Text = _ VigenereCyph.Decrypt(ActiveForm.txtText.Text, strKey) End Sub Private Sub Form_Resize() On Error Resume Next txtText.Move 100, 100, Me.ScaleWidth - 200, Me.ScaleHeight - 200 End Sub Private Sub Form_Resize() On Error Resume Next mscGraph.Move 100, 100, Me.ScaleWidth - 200, Me.ScaleHeight - 200 End Sub Public Public Public Public Public Public Public ALPHA(26) As String ASCII(255, 1) As String PLOT(26, 1) FREQ(26) As String CaesarCyph As New Caesar PolibioCyph As New Polibio VigenereCyph As New Vigenere Public Sub InitVAR() j = 0 For i = 97 To 122 ALPHA(j) = Chr(i) PLOT(j, 0) = ALPHA(j) j = j + 1 Next i ALPHA(j) = " " PLOT(j, 0) = " " For i = 0 To 255 ASCII(i, 0) = Chr(i) Next i FREQ(0) FREQ(1) FREQ(2) FREQ(3) FREQ(4) FREQ(5) FREQ(6) = = = = = = = " " "e" "a" "i" "o" "n" "r" 158 Appendice F FREQ(7) = "t" FREQ(8) = "l" FREQ(9) = "s" FREQ(10) = "c" FREQ(11) = "d" FREQ(12) = "u" FREQ(13) = "p" FREQ(14) = "m" FREQ(15) = "v" FREQ(16) = "g" FREQ(17) = "h" FREQ(18) = "b" FREQ(19) = "f" FREQ(20) = "q" FREQ(21) = "z" FREQ(22) = "j" FREQ(23) = "k" FREQ(24) = "w" FREQ(25) = "x" FREQ(26) = "y" End Sub Public Sub Clear() For i = 0 To 26 PLOT(i, 1) = 0 Next i End Sub Public Sub InitCDL(CDL As CommonDialog,strExt As String,strTitle _ As String, strFilter As String, strInitDir _ As String, strOpenSave As String) On Error GoTo Err_Handler CDL.CancelError = True CDL.DefaultExt = strExt CDL.DialogTitle = strTitle CDL.Filter = strFilter CDL.FilterIndex = 1 CDL.InitDir = strInitDir Select Case strOpenSave Case "Save": CDL.Flags = cdlOFNOverwritePrompt Case "Open": CDL.Flags = cdlOFNFileMustExist End Select Err_Handler: End Sub Public Sub InitDOC(strFilename As String) Static lDocumentCount As Long Dim frmD As New frmDoc lDocumentCount = 1 159 Appendice F If (strFilename = "") Then strFilename = "Document" & lDocumentCount frmD.Caption = strFilename frmD.Show End Sub Public Sub InitGRAPH(strFilename As String) Static lChartCount Dim frmG As New frmGraph If (strFilename = "") Then strFilename = "Chart" & lChartCount With frmG .Caption = strFilename .mscGraph = PLOT .Show End With End Sub Private Alphabet(255) As String Public Function Crypt(iSph As Integer, strCrypt As String) As String Dim c As Variant Dim strCrypted As String Dim iRes As Integer For i = 1 To Len(strCrypt) c = Mid(strCrypt, i, 1) iRes = Find(c) If ((iRes + iSph) > 255) Then j = (iRes + iSph) - 255 strCrypted = strCrypted & Alphabet(j) Else strCrypted = strCrypted & Alphabet(iRes + iSph) End If Next i Crypt = strCrypted End Function Public Function Decrypt(iSph As Integer, strCrypt As String) As String Dim c As Variant Dim strCrypted As String Dim iRes As Integer For i = 1 To Len(strCrypt) c = Mid(strCrypt, i, 1) iRes = Find(c) 160 Appendice F If ((iRes - iSph) < 0) Then j = (iRes - iSph) + 255 strCrypted = strCrypted & Alphabet(j) Else strCrypted = strCrypted & Alphabet(iRes - iSph) End If Next i Decrypt = strCrypted End Function Private Function Find(vChar As Variant) As Integer For i = 0 To 255 If (Alphabet(i) = vChar) Then Find = i GoTo End_Function End If Next i End_Function: End Function Private Sub Init() Dim c As String Alphabet(0) = " " For i = 1 To 255 c = Chr(i) Alphabet(i) = c Next i End Sub Private Sub Class_Initialize() Init End Sub Private Alphabet(15, 15) As String Private Sub Find(vChar As Variant, ByRef iY As Integer, ByRef iX As Integer) For i = 0 To 15 For j = 0 To 15 If (Alphabet(i, j) = vChar) Then iY = i iX = j GoTo End_Function End If Next j Next i End_Function: End Sub 161 Appendice F Private Function HexToDec(c As Variant) As Long Dim lRes As Long If ((c >= Hex(10)) And (c <= Select Case c Case Hex(10): lRes = Case Hex(11): lRes = Case Hex(12): lRes = Case Hex(13): lRes = Case Hex(14): lRes = Case Hex(15): lRes = End Select Else lRes = c End If Hex(15))) Then 10 11 12 13 14 15 HexToDec = lRes End Function Public Function Crypt(strCrypt As String) As String Dim Dim Dim Dim Dim Dim c As Variant strCrypted As String l As Long x As Integer y As Integer j As Long j = 0 For i = 1 To Len(strCrypt) c = Mid(strCrypt, i, 1) Find c, y, x strCrypted = strCrypted & Hex(y) & Hex(x) Next i Crypt = strCrypted End Function Public Function Decrypt(strCrypt As String) As String Dim Dim Dim Dim Dim c As Variant strCrypted As String x As Long y As Long p As Long p = 1 For i = 1 To Len(strCrypt) / 2 c y p c x p = = = = = = Mid(strCrypt, p, 1) HexToDec(c) p + 1 Mid(strCrypt, p, 1) HexToDec(c) p + 1 162 Appendice F strCrypted = strCrypted & Alphabet(y, x) Next i Decrypt = strCrypted End Function Private Sub Init() Dim c As Integer c = 0 For i = 0 To 15 For j = 0 To 15 Alphabet(i, j) = Chr(c) c = c + 1 Next j Next i End Sub Private Sub Class_Initialize() Init End Sub Private Alphabet(255, 255) As String Private Sub FindRow(vChar As Variant, y As Integer, x As Integer, ByRef iY As Integer, ByRef iX As Integer) On Error GoTo End_Function For i = y To 255 For j = x To 255 If (Alphabet(i, j) = vChar) Then iY = i iX = j GoTo End_Function End If Next j Next i End_Function: End Sub Private Sub FindCol(vChar As Variant, y As Integer, x As Integer, ByRef iY As Integer, ByRef iX As Integer) On Error GoTo End_Function For j = x To 255 For i = y To 255 If (Alphabet(i, j) = vChar) Then iY = i iX = j GoTo End_Function 163 Appendice F End If Next i Next j End_Function: End Sub Public Function Decrypt(strCrypt As String, strKey As String) As String Dim Dim Dim Dim Dim Dim Dim Dim Dim strCrypted As String j As Integer cCrypt As String cKey As String cRes As String iYCrypt As Integer iXCrypt As Integer iYKey As Integer iXKey As Integer j = 1 For i = 1 To Len(strCrypt) If (j > Len(strKey)) Then j = 1 cCrypt = Mid(strCrypt, i, 1) cKey = Mid(strKey, j, 1) FindCol cKey, 0, 0, iYKey, iXKey FindRow cCrypt, iYKey, 0, iYCrypt, iXCrypt cRes = Alphabet(0, iXCrypt) strCrypted = strCrypted & cRes j = j + 1 Next i Decrypt = strCrypted End Function Public Function Crypt(strCrypt As String, strKey As String) As String Dim Dim Dim Dim Dim Dim Dim Dim Dim strCrypted As String j As Integer cCrypt As String cKey As String cRes As String iYCrypt As Integer iXCrypt As Integer iYKey As Integer iXKey As Integer j = 1 For i = 1 To Len(strCrypt) 164 Appendice F If (j > Len(strKey)) Then j = 1 cCrypt = Mid(strCrypt, i, 1) cKey = Mid(strKey, j, 1) FindRow cCrypt, 0, 0, iYCrypt, iXCrypt FindCol cKey, 0, 0, iYKey, iXKey cRes = Alphabet(iYKey, iXCrypt) strCrypted = strCrypted & cRes j = j + 1 Next i Crypt = strCrypted End Function Private Sub Init() Dim Dim Dim Dim Dim x y j c k As As As As As Integer Integer Integer Integer Integer j = 0 c = 0 k = 0 For y = 0 To 255 For x = 0 To (255 - j) Alphabet(y, x) = Chr(k) k = k + 1 Next x If Not (j = 0) Then For i = (255 - j) + 1 To 255 Alphabet(y, i) = Chr(c) c = c + 1 Next i End If c = 0 j = j + 1 k = j Next y End Sub Private Sub Class_Initialize() Init End Sub 165 Appendice F 4 TCP /***********GENERATORI DI PACCHETTI TCP*************************/ /* Dichiarazione delle librerie principali usate nel programma */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include <stdlib.h> <stdio.h> <sys/types.h> <sys/socket.h> <netinet/in.h> <arpa/inet.h> <netinet/in_systm.h> <netinet/ip.h> <netinet/tcp.h> <string.h> <unistd.h> <time.h> <stdlib.h> <stdio.h> <sys/types.h> /* Dichiarazione dei prototipi delle funzioni */ void tcp_gen(char *packet,unsigned short sport,unsigned short dport,unsigned long seq,unsigned long ack); void udp_gen(char *packet,unsigned short sport,unsigned short dport,unsigned short length); void ip_gen(char *packet,unsigned char protocol,struct in_addr saddr,struct in_addr daddr,unsigned short length); unsigned short trans_check(unsigned char proto, char *packet,int length, struct in_addr source_address, struct in_addr dest_address); unsigned short in_cksum(unsigned short *addr,int len); #define IPVERSION 4 /* versione del pacchetto IP */ #define DEFAULT_TTL 60 // Definizione del tempo di vita dei pacchetti // #define TH_OFFSET 5 #define TCP_WINDOW_SIZE 512 /*larghezza della finestra del tcp */ /* struttura per il calcolo del checksum sul pacchetto tcp*/ struct psuedohdr { struct in_addr source_address; struct in_addr dest_address; unsigned char place_holder; unsigned char protocol; unsigned short length; } psuedohdr; /****** calcolo del checksum sul tcp header *******************/ unsigned short trans_check(unsigned char proto,char *packet,int length,struct in_addr source_address, struct in_addr dest_address) { char *psuedo_packet; 166 Appendice F unsigned short answer; /* compilazione della struttura pseudohdr tcp */ psuedohdr.protocol = proto; psuedohdr.length = htons(length); psuedohdr.place_holder = 0; psuedohdr.source_address = source_address; psuedohdr.dest_address = dest_address; /* allocazione della struttura pseudohdr */ if((psuedo_packet = malloc(sizeof(psuedohdr) + length)) == NULL) { perror("malloc"); exit(1); } /* copia la struttura pseudohdr nella blocco puntato da pseudo_packet */ memcpy(psuedo_packet,&psuedohdr,sizeof(psuedohdr)); memcpy(psuedo_packet,&psuedohdr,sizeof(psuedohdr,packet,length));/ /memcpy((psuedo_packet + sizeof(psuedohdr,packet,length))); /* applica l'algoritmo del checksum allo pseudo pacchetto*/ answer = (unsigned short)in_cksum((unsigned short*)psuedo_packet, length + sizeof(psuedohdr))); free( psuedo_packet ) ; return answer; } /************************* algoritmo del checksum **************/ unsigned short in_cksum(unsigned short *addr,int len) { register int sum = 0; u_short answer = 0; register u_short *w = addr; register int nleft = len; /*Questo ciclo somma nel registro accumulatore (sum) 32 bit le parole di 16 bit che vengono estratte dalla struttura addr.*/ while (nleft > 1) { sum += *w++; nleft -= 2; } /* se la lunghezza del campo dati è numero dispari viene completato */ /* con un 0 addizionale .*/ if (nleft == 1) { *( u_char * )( &answer ) = *( u_char * )w ; sum += answer; } /* viene calcolato il complemento a 1 della somma delle word */ sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); answer = ~sum; return(answer); } /*********************** generatore pacchetto IP ***************/ 167 Appendice F void ip_gen(char *packet,unsigned char protocol,struct in_addr saddr,struct in_addr daddr,unsigned short length) { /* definisco un puntatore alla struttura */ struct iphdr *iphdr; /* La variabile pacchetto diventa puntatore alla struttura iphdr */ iphdr = (struct iphdr *)packet; memset((char *)iphdr,'\0',sizeof(struct iphdr)); /* compilo la struttura ip */ iphdr->ihl = 5; iphdr->version = IPVERSION; /* BIG ENDIAN e LITTLE ENDIAN */ #ifdef IP_LEN_HORDER iphdr->tot_len = length; #else iphdr->tot_len = htons(length); #endif /* IP_LEN_HORDER */ iphdr->id = htons(getpid()); iphdr->ttl = DEFAULT_TTL; iphdr->protocol = protocol; iphdr->saddr = saddr.s_addr; iphdr->daddr = daddr.s_addr; /* calcola il checksum del pacchetto*/ iphdr->check = (unsigned short)in_cksum((unsigned short *)iphdr, sizeof(struct iphdr)); return; } /***dichiarazione del prototipo della funzione tcp_gen ********/ void tcp_gen(char *packet,unsigned short sport,unsigned short dport, unsigned long seq,unsigned long ack) { /* puntatore alla struttura tcphdr */ struct tcphdr *tcp; /* Cast di packet da (char *) a (struct tcphdr*) */ tcp = (struct tcphdr *)packet; memset((char *)tcp,'\0',sizeof(struct tcphdr)); /* compilazione della struttura tcp */ tcp->source = htons(sport); tcp->dest = htons(dport); tcp->seq = htonl(seq); tcp->ack_seq = htonl(ack); tcp->res1 = 0; tcp->doff = TH_OFFSET; tcp->window = htons(TCP_WINDOW_SIZE); tcp->fin = 1; return; } /*************** M A I N **************************************/ 168 Appendice F /*argv: 1-porta sorgente 2-indirizzo sorgente 3-porta destinazione 4-indirizzo destinazione */ int main(int argc,char *argv[]) { /* vettore pacchetto di lunghezza ip header + tcp header */ unsigned char packet[ sizeof(struct iphdr) + sizeof(struct tcphdr) ]; /* sockaddr_in struttura della socket */ struct sockaddr_in mysocket; /* porte sorgenti e destinazioni */ unsigned short sport, dport; /* struttura per l'indirizzamento ID/RETE ID/HOST */ struct in_addr saddr, daddr; /* puntatore alla struttura tcphdr */ struct tcphdr *tcp; unsigned long seq, ack; int sockd, on = 1; /* Prelevo gli argomenti dalla riga di comando */ if(argc < 5) { fprintf(stderr,"usare: %s porta_sorg. indirizzo_sorg. porta_dest. indirizzo_dest\n", argv[0]); exit(1); } /* Compila la struttura per le socket con porta sorgente e indirizzo sorgente */ sport = (unsigned short)atoi(argv[1]); saddr.s_addr = inet_addr(argv[2]); /* Compila la struttura per le socket con porta destinazione e indirizzo destinazione */ dport = (unsigned short)atoi(argv[3]); daddr.s_addr = inet_addr(argv[4]); /* Creo il socket descriptor con l'opzione socket raw */ if((sockd = socket(AF_INET,SOCK_RAW,IPPROTO_RAW)) < 0) { perror("socket"); exit(1); } /* Setto alcune opzioni inerenti al livello del protocollo IP */ if(setsockopt(sockd,IPPROTO_IP,IP_HDRINCL,(char *)&on,sizeof(on)) < 0) { perror("setsockopt"); exit(1); } /* Genero numero di sequenza ed ack casuali */ srand(getpid()); seq = rand()%time( NULL ); ack = rand()%time( NULL ); /* Genero pacchetto IP */ 169 Appendice F ip_gen(packet,IPPROTO_TCP,saddr,daddr,sizeof(packet)); /* Sposto il puntatore della struttura tcp header della dimensione del */ /* pacchetto + la struttura ip header */ tcp = (struct tcphdr *)(packet + sizeof(struct iphdr)); /* Genero il pacchetto TCP */ tcp_gen((char *)tcp,sport,dport,seq,ack); /* checksum calcolato sul pacchetto IP */ tcp->check = trans_check(IPPROTO_TCP,(char *)tcp, sizeof(struct tcphdr), saddr, daddr); /*inizializza la struttura mysocket */ memset(&mysocket,'\0',sizeof(mysocket)); /*Compilo la struttura mysocket */ mysocket.sin_family = AF_INET; mysocket.sin_port = htons(dport); mysocket.sin_addr = daddr; /* Spedisco il pacchetto da me creato con il flag fin a a 1 secondo i parametri immessi da linea di comando.*/ if(sendto(sockd,&packet,sizeof(packet),0x0,(struct sockaddr *)&mysocket, sizeof(mysocket)) != sizeof(packet)) { perror("sendto"); exit(1); } exit(0); } /****************************************************************/ 170 Glossario GLOSSARIO Albam metodo crittografico usato dagli ebrei. Consiste nel dividere in due parti l’alfabeto e nel sostituire ogni lettera con la corrispondente nell’altra metà. ARPA da Advanced Research Project Agency, Agenzia per progetti di ricerca avanzata. Agenzia del Dipartimento della Difesa statunitense, attualmente ribattezzata DARPA, fondata nel 1958 per il finanziamento della ricerca militare. ARPANet da Advance Research Project Agency Network, rete dell’Agenzia per progetti di ricerca avanzata. Rete a lunga distanza creata nel 1969 dell’Agenzia per progetti di ricerca avanzata (ARPA) statunitense, in collaborazione con le principali università e centri di ricerca, con il fine di utilizzare la comunicazione di dati ad alta velocità per la collaborazione scientifica e le operazioni militari. Atbash dall’unione delle prime e dalle ultime due lettere dell’alfabeto ebraico, Aleph Taw Beth Shin. Codice di cifratura usato nel Vecchio Testamento dal profeta Geremia, consiste nel sostituire la prima lettera dell’alfabeto con l’ultima la seconda con la penultima e così via. Brute force nella crittografia e in altri campi matematici, tecnica di risoluzione dei problemi che impiega un computer programmato per eseguire ripetutamente un compito semplice, nella speranza di trovare la risposta. Checksum somma di controllo. Tecnica di rilevazione di errori che verifica la corretta ricezione di un blocco dati. Consiste nell’eseguire la somma dei valori dei bit contenuti nel blocco dati trasmesso e nel confrontarla con la somma analoga eseguita in ricezione. DARPA da Defense Advanced Research Project Agency, Agenzia della Difesa per progetti di ricerca avanzata. Attuale denominazione dell’Agenzia per progetti di ricerca avanzata del Dipartimento della Difesa Statunitense. 171 Glossario DES da Data Encryption Standard, standard di cifratura dati. Metodo di cifratura sviluppato da IBM e certificata nel 1977 dal governo USA come tecnica ufficiale di cifratura per informazioni non classificate; sebbene abbia perso la certificazione nel 1998, è ancora ampiamente usato. DLL da Dynamic Link Library, libreria di collegamento dinamico. Modulo software dell’ambiente Windows contenente codice eseguibile e dati che possono essere richiamati e usati da applicazioni Windows e da altre DLL. Funzioni e dati in una DLL sono caricati e linkati durante l’esecuzione, quando sono richiamati da un’applicazione o altre DLL. FTP da File Transfer Protocol, protocollo di trasferimento file. Protocollo Internet per lo scambio di file con computer ospiti remoti, basato sul modello client/server. FTP può copiare dall’ospite uno o più file e fornisce gli strumenti necessari per identificare la directory corrente sull’ospite remoto, elencare i suoi file, cambiare directory e rinominare i file o cancellarli. Hash funzione che, dato un numero in ingresso, ne genera un altro dal numero di cifre prestabilite. Da quest’ultimo non è possibile ricavare il numero che l’ha generato. Host computer usato da più di un utente come mezzo di accesso a Internet, di cui funge da punto terminale di trasferimenti dati. HTTP da HyperText Transport Protocol, protocollo per trasferimento di ipertesti. Protocollo e software servitore che lo implementa per la navigazione di ipertesti usato da World Wide Web. ICMP da Internet Control Message Protocol, protocollo di controllo dei messaggi in Internet. Protocollo standard che gestisce la situazione in cui un instradatore sia congestionato o comunque non in grado d’inviare a destinazione un datagramma. 172 Glossario LAN da Local Area Network, rete locale. Collegamento di computer di vario tipo entro un’area limitata (10 m – 10 Km) per mezzo di un canale fisico costituito da cavo coassiale, doppino telefonico o fibra ottica. MFC da Microsoft Foundation Classes, classi fondate da Mircrosoft. Insieme di librerie DLL, che forniscono numerose funzioni, come l’uso dei socket e la gestione delle finestre. NETBIOS da NETwork Basic Input/Output System, sistema di base di ingresso/uscita di rete. Gruppo di funzioni di servizio, residenti in memoria di sola lettura, che favoriscono la trasmissione e la ricezione di dati fra un computer e la scheda di collegamento a una rete locale. NIST da National Institute for Standards and Technology, Istituto nazionale per gli standard e la tecnologia. Istituto erede del National Bureau of Standards (NBS) e riconosciuto dall’ANSI, che definisce le specifiche per gli appalti pubblici. NNTP da Network News Transfer Protocol, protocollo di trasferimento delle notizie di rete. Nella rete Usenet, protocollo standard che regola la diffusione dei messaggi ai siti che si siano accordati per ricevere le notizie di rete. NSF da National Science Foundation, Fondazione nazionale per la scienza. Agenzia indipendente del governo statunitense, fondata nel 1950 per promuovere la scienza e la tecnologia attraverso la sponsorizzazione di ricerche scientifiche, ingegneristiche ed educative. NSFNet rete a commutazione di pacchetto ad alta velocità basata sui protocolli TCP/IP, che costituisce una delle dorsali di Internet e gestisce i dati prodotti da reti regionali. 173 Glossario OSI da Open System Interconnection, interconnessione di sistemi aperti. Standard internazionale per l’organizzazione di reti locali, definito dall’Organizzazione internazionale per gli standard (ISO) e dall’Istituto di ingegneri elettrici ed elettronici (IEEE) nei primi anni ’80. PGP da Pretty Good Privacy, riservatezza molto buona. Software di cifratura di pubblico dominio sviluppato da Phil Zimmerman. da Post Office Protocol 3, protocollo postale. Protocollo che specifica gli scambi di posta elettronica tra un PC e un provider. POP3 Router apparato che esegue l’interconnessione di reti locali multiprotocollo. Opera allo strato 3 del modello OSI e utilizza l’indirizzo logico contenuto in un pacchetto di dati per decidere il percorso da utilizzare per l’instradamento all’utente di destinazione; in presenza di più percorsi tra due LAN, li può utilizzare tutti in modo ottimizzato. SMTP da Simple Mail Transfer Protocol, protocollo semplice per il trasporto di posta. Nello strato di applicazione di Internet, protocollo che regola il formato dei messaggi di posta elettronica. Sviluppato inizialmente da ARPANet, è diventato il protocollo mondiale di fatto per i messaggi di posta elettronica. Socket nell’indirizzamento di Internet, combinazione di un indirizzo IP, che identifica un computer ospite, con un indirizzo di porta, che identifica un’applicazione in funzione sull’ospite. Steganografia deriva dalle parole greche steganòs, coperto e gràphein, scrivere. Tecnica di comunicazione segreta basata sull’occultamento del messaggio. nell’indirizzamento di Internet, subunità nella rete di un’organizzazione, che è stata identificata come entità distinta ai fini dell’instradamento di datagrammi, modificando la struttura degli indirizzi IP. Subnet 174 Glossario TCP/IP da Transmission Control Protocol/Internet Protocol, protocollo di controllo di trasmissione/protocollo Internet. Sigla che indica propriamente i due protocolli principali di Internet, il protocollo di controllo di trasmissione e il protocollo Internet, progettati alla fine degli anni ’70 da Bobert E. Kahn e Vinton G. Cerf a Berkeley. Telnet nome di un protocollo e del software che lo implementa, che definisce un terminale virtuale di rete e permette a un utente di entrare in un computer ospite remoto. UDP da User Datagram Protocol, protocollo di datagramma di utente. Nello strato di trasporto di Internet, protocollo non affidabile e senza collegamento che non tenta di verificare se un messaggio sia stato ricevuto. Unix sistema operativo multiutente/multitask sviluppato a partire dal 1969 da Ken Thompson nel Bell Telephone Labs. Scritto originariamente nel linguaggio assembly, è stato presto tradotto in C, potendo così essere trasportato su numerosi sistemi. WAN da Wide – Area Network, rete ad ampio raggio. Rete dati pubblica, con topologia di solito a maglia o ibrida, che impiega linee telefoniche dedicate o satelliti per collegare più reti locali (LAN), estendendosi su una regione geografica più estesa di un’area metropolitana. Winsock nell’ambiente Microsoft Windows, file di una libreria DLL che contiene le informazioni e le procedure necessarie a Windows per interfacciarsi con i protocolli TCP/IP. 175 Bibliografia BIBLIOGRAFIA Visual C++ 6 Guida completa Davis Chapman Apogeo Dizionario di informatica Angelo Gallippi Tecniche nuove The Alan Turing home page www.turing.org.uk/turing Eli Biham’s home page www.cs.technion.ac.il/~biham/ MAW 97 CIPHERS The Enigma machine www.math.arizona.edu/~dsl/enigma.htm Riksoft – Software – Protezione – Servizi www.riksoft.com/indexok.asp?Goto=critlogia.htm Sockaddr.com www.sockaddr.com/ MSDN Library www.microsoft.com Manuali.it www.manuali.it WWII Codes and cyphers www.codesandciphers.org.uk 176