Introduzione alla Crittografia

La crittografia è un metodo di protezione delle informazioni e delle comunicazioni mediante l'uso di codici, in modo che solo coloro per i quali le informazioni sono destinate possano leggerle e processarle.

Nella scienza informatica, la crittografia si riferisce a tecniche di sicurezza delle informazioni e delle comunicazioni derivate da concetti matematici e da un insieme di calcoli basati su regole chiamati algoritmi, per trasformare i messaggi in modi difficili da decifrare. Questi algoritmi deterministici sono utilizzati per la generazione di chiavi crittografiche, la firma digitale, la verifica per proteggere la privacy dei dati, la navigazione web su internet e le comunicazioni riservate come le transazioni con carte di credito e le email.

Obiettivi della crittografia

La crittografia moderna si occupa dei seguenti quattro obiettivi:

  1. Confidenzialità
    Le informazioni non possono essere comprese da nessuno per cui non sono destinate.

  2. Integrità
    Le informazioni non possono essere alterate durante l'archiviazione o il transito tra il mittente e il destinatario previsto senza che l'alterazione venga rilevata.

  3. Non ripudio
    Il creatore/mittente delle informazioni non può negare, in una fase successiva, le proprie intenzioni nella creazione o nella trasmissione delle informazioni.

  4. Autenticazione
    Il mittente e il destinatario possono confermare l'identità reciproca e l'origine/destinazione delle informazioni.

Crittosistemi

Le procedure e i protocolli che soddisfano alcuni o tutti i criteri sopra menzionati sono noti come crittosistemi. I crittosistemi sono spesso considerati solo procedure matematiche e programmi per computer; tuttavia, includono anche la regolazione del comportamento umano, come la scelta di password difficili da indovinare, il disconnettersi dai sistemi inutilizzati e il non discutere di procedure sensibili con estranei.

Nei prossimi paragrafi verra illustrato il funzionamento di numerosi sistemi crittografici, vedremo inizialmente alcuni concetti fondamentali per definire un sistema crittografico come sicuro; successivamente vedremo come scambiare messaggi in modo sicuro, analizzando i due diversi approcci: la crittografia simmetrica e quella asimmetrica; vedremo come firmare digitalmente i messaggi e come garantire l'integrità dei dati con le funzioni hash. Infine vedremo alcune applicazioni pratiche della crittografia in sistemi reali.

Concetti fondamentali

In questa sezione verranno analizzati alcuni concetti fondamentali riguardo i sistemi crittografici che vedremo più avanti, i concetti sono:

  • Security through obscurity
  • Bits of security
  • Confusion and Diffusion
  • Perfect Cipher

Security through obscurity

Portiamo alcuni esempi di sistemi crittografici insicuri per introdurre alcuni concetti chiave della crittografia. Immaginiamo il seguente algoritmo di cifratura: per cifrare un messaggio, si sostituisce ogni lettera con la lettera 3 posizioni più avanti nell'alfabeto. Ad esempio, la lettera 'A' diventa 'D', 'B' diventa 'E', la 'Z' diventa 'C' ecc.

Questo cifrario è noto come cifrario di Cesare, perché fu utilizzato da Giulio Cesare per comunicazioni segrete.

Immaginiamo di voler cifrare il seguente messaggio: attaccare all'alba; togliendo la punteggiatura e gli spazi il messaggio cifrato diventa: dwwdffduhdoodoed. Una volta ricevuto il messaggio cifrato, il destinatario può decifrarlo semplicemente spostando ogni lettera di tre posizioni all'indietro nell'alfabeto. Durante il transito il messaggio è apparentemente incomprensibile, dunque sembrebbe essere un buon metodo di cifratura. Tuttavia la segretezza del messaggio è basata sulla segretezza dell'algoritmo, un attaccante che conosce il metodo di cifratura può facilmente decifrare il messaggio. Questa pratica è nota appunto come sicurezza tramite segretezza (security through obscurity) e non è considerata un metodo sicuro di cifratura. La crittografia moderna si basa su algoritmi crittografici ben definiti e pubblici, la sicurezza dei dati non dipende dalla segretezza dell'algoritmo ma dalla segretezza della chiave. Un gran numero di sistemi crittografici per le telecomunicazioni e la gestione dei diritti digitali che utilizzavano la sicurezza tramite segretezza alla fine sono stati compromessi.

Bits of security

Dunque un algoritmo di cifratura deve avere come parametro una chiave, segreta tra le parti comunicanti, che permette di cifrare e decifrare i messaggi. Dovesse essere scoperta la chiave le parti comunicanti possono cambiare la chiave e continuare a comunicare in sicurezza. Con questa premessa possiamo modificare il cifrario di Cesare in modo da utilizzare una chiave: la chiave sarà un numero intero compreso tra 0 e 25 (alfabeto inglese) che indica di quante posizioni spostare le lettere nell'alfabeto; chiamiamo questo algoritmo ROTK. Con chiave "3" si ottiene esattamente il cifrario di Cesare.

Anche in questo caso l'algoritmo di cifratura è insicuro e facilmente attaccabile, un attaccante può semplicemente provare tutte le chiavi possibili fino a trovare una chiave che decifri il messaggio in un testo comprensibile. Questo attacco è noto come attacco a forza bruta e la sua fattibilità dipende dal numero di chiavi possibili, nel caso di ROTK sono solamente 26, decisamente poche per garantire sicurezza contro attacchi a forza bruta. Un algoritmo crittografico sicuro deve avere un numero di chiavi possibili tale da rendere impraticabile un attacco a forza bruta, il modo più comune per misurare la sicurezza di un algoritmo crittografico è il numero di bit di sicurezza (bits of security). Un algoritmo ha \(n\) bit di sicurezza se occorrono \(2^n\) operazioni per romperlo. Per dare una idea di ordine di grandezza, un algoritmo con 128 bit di sicurezza è considerato altamente sicuro.

Confusion and Diffusion

Dunque per quanto detto precedentemente occorre un algoritmo di cifratura che abbia una chiave come parametro, e questa chiave deve poter assumere un numero sufficientemente grande di valori per garantire sicurezza contro attacchi a forza bruta. Introduciamo il seguente cifrario: utilizziamo come chiave una permutazione casuale dell'alfabeto, per ogni lettera del messaggio in chiaro sostituiamo con la lettera nella stessa posizione nella permutazione. Ad esempio supponendo che la chiave sia la permutazione UZSIAFXGQLKRMPHNBTOJEVWYDC la lettera 'A' sarà cifrata con 'U', 'B' con 'Z', 'C' con 'S' ecc. Il messaggio attaccare all'alba cifrato con questa chiave diventa UJJUSSUTAURRURZU. Questo cifrario è noto come cifrario a sostituzione monoalfabetica, vediamo se ha un sufficiente numero di bit di sicurezza. L'alfabeto inglese ha 26 lettere, dunque il numero di chiavi possibili è \(26!\) (26 fattoriale) che è circa \(2^{88}\), dunque il cifrario di sostituzione monoalfabetica ha circa 88 bit di sicurezza, un numero sufficientemente grande per garantire sicurezza contro attacchi a forza bruta.

In questo caso l'algoritmo si può considerare sicuro? Anche in questo caso un attaccante può decifrare il messaggio senza conoscere la chiave, l'idea di base è la seguente: un testo in italiano (ma vale per ogni lingua) ha una distribuzione delle lettere non uniforme, alcune lettere sono più frequenti di altre, e su testi ragionevolmente lunghi (è sufficiente qualche paragrafo) questa distribuzione risulta sempre uguale. Dunque sapendo che nella lingua italiana la lettera che compare più frequentemente è la e, si può assumere che nel testo cifrato la lettera più frequente corrisponda alla e, e cosi' via per le altre lettere. Questo attacco è noto come attacco per analisi delle frequenze e permette di decifrare il messaggio senza conoscere la chiave.

A primo impatto questo metodo può sembrare poco convincente, ma effettivamente funziona come descritto sopra; esistono numerosi tool online che permettono di decifrare testi cifrati con sostituzione monoalfabetica, ad esempio dcode.fr. Dato il seguente testo cifrato:

QPBEAOJHSUOHRURXHTQJMHOQNEHSHPOQIATUTAOQSETHUPSGAQPBEAOJHSUOHEPUJJUSSUPJANEHIASQFTUTAQRMAOOUXXQHOAPCUSHPHOSATARUSGQUVARQIAUIQZUOAARUOAXEAPJAEPJAOJHQPQJURQUPHMUVURANATHXPQRQPXEUGUEPUIQOJTQZECQHPAIARRARAJJATAPHPEPQFHTMAURSEPARAJJATAOHPHNQEFTABEAPJQIQURJTAAOEJAOJQTUXQHPAVHRMAPJAREPXGQAOEFFQSQAPJABEURSGANUTUXTUFHBEAOJUIQOJTQZECQHPATQOERJUOAMNTAEXEURAIEPBEAOUNAPIHSGAPARRURQPXEUQJURQUPURURAJJATUSGASHMNUTANQEFTABEAPJAMAPJAARUAOQNEHUOOEMATASGAPARJAOJHSQFTUJHRURAJJATUNQEFTABEAPJASHTTQONHPIUURRUAASHOQVQUNATRAURJTARAJJATABEAOJHUJJUSSHAPHJHSHMAUJJUSSHNATUPURQOQIARRAFTABEAPCAANATMAJJAIQIASQFTUTAQRMAOOUXXQHOAPCUSHPHOSATARUSGQUVA

è possibile decifrarlo in un istante attraverso il tool appena citato. La debolezza di questo cifrario risiede nel fatto che mantiene le proprieta' statistiche del messaggio originario, un cifrario sicuro deve produrre un testo cifrato che sia indistinguibile da un testo casuale. Questo concetto è noto come confusione e diffusione (confusion and diffusion) e rappresenta un principio fondamentale della crittografia moderna. Nelle definizioni originali di Shannon, la confusione si riferisce a rendere la relazione tra il testo cifrato e la chiave simmetrica il più complessa e intricata possibile; la diffusione si riferisce a dissipare la struttura statistica del testo in chiaro su tutto il testo cifrato.

Tutti gli algoritmi crittografici moderni sono progettati per garantire le proprietà discusse in questo capitolo, per portare un esempio che verrà approfondito in seguito, l'algoritmo AES (Advanced Encryption Standard) è uno dei più utilizzati algoritmi di cifratura simmetrica; l'algoritmo è di pubblico dominio ed ha una chiave di 128 bit (o più) dunque è sicuro contro attacchi a forza bruta, inoltre è progettato per garantire confusione e diffusione.

Perfect Cipher

In crittografia, un perfect cipher è un sistema di cifratura che è teoricamente sicuro, cioè un attaccante non può decifrare il messaggio cifrato senza conoscere la chiave, indipendentemente dalla potenza computazionale. Il più noto esempio di perfect cipher è il One-Time Pad (OTP). Un OTP utilizza una chiave casuale, lunga quanto il messaggio da cifrare, e ciascuna chiave viene utilizzata solo una volta. Il messaggio viene cifrato combinando ciascun bit del messaggio con il bit corrispondente della chiave tramite l'operazione di XOR.

Lo XOR (o esclusivo OR) è un'operazione logica che funziona su coppie di bit. La seguente è la tabella di verità dello xor (spesso riassunta con: 1 se i due bit sono diversi e 0 se i due bit sono uguali):

\(A\)\(B\)\(A \oplus B\)
000
011
101
110

E seguono direttamente le seguenti proprietà:

  1. Commutatività: \( A \oplus B = B \oplus A \)
  2. Associatività: \( (A \oplus B) \oplus C = A \oplus (B \oplus C) \)
  3. Identità: \( A \oplus 0 = A \)
  4. Involutività: \( A \oplus A = 0 \)

Per cifrare un messaggio con un OTP, si esegue l'operazione XOR tra ciascun bit del messaggio e il bit corrispondente della chiave. Per decifrare il messaggio, si esegue di nuovo l'operazione XOR tra il messaggio cifrato e la stessa chiave. Il sistema crittografico funziona perché si ha \(C = M \oplus K\), \(M = C \oplus K = (M \oplus K) \oplus K = M \oplus (K \oplus K) = M\) (con C si intende il crittogramma, con M il messaggio e con K la chiave).

Ad esempio, se il messaggio è 1101 e la chiave è 1011, il messaggio cifrato sarà 1100. Decifrando 1100 con la chiave 1011 si ottiene di nuovo 1101. Questo metodo garantisce che il messaggio cifrato non riveli alcuna informazione sul messaggio originale senza conoscere la chiave, rendendo l'OTP un perfect cipher se la chiave è davvero casuale, della stessa lunghezza del messaggio e utilizzata una sola volta. Per convincerci di ciò immaginiamo di effettuare un attacco forza bruta contro il testo cifrato, ossia proviamo a decifrare con tutti i valori possibili della chiave:

crittogrammachiavemessaggio
011000000110
011000010111
011000100100
011000110101
011001000010
011001010011
011001100000
011001110001
011010001110
011010011111
011010101100
011010111101
011011001010
011011011011
011011101000
011011111001

Osserviamo che nella colonna del messaggio otteniamo tutti i messaggi possibili di lunghezza 4, ovviamente tra questi è presente anche il messaggio originale ma a priori non è possibile in alcun modo distinguerlo dagli altri. L'esempio con messaggi di 4 bit è chiaramente poco realistico ma serve per dare l'intuizione che, anche con messaggi di lunghezza arbitraria, non vi è alcun modo per estrarre informazioni sul messaggio in chiaro se è stato cifrato con OTP.

Il problema di OTP è che necessita di una chiave lunga quanto il messaggio, è chiaro che questo in molti casi può risultare problematico, ed è il motivo per cui in pratica OTP non viene utilizzato.

Da notare che il problema della lunghezza della chiave è proprio la proprietà che lo rende un cifrario perfetto, tentare di usare una chiave più corta, per esempio ripetendola ciclicamente rende il cifrario insicuro. Vediamo in un esempio come mai questo accade: se il messaggio è \(m_0, m_1, m_2, m_3\) ma la chiave è \(k_0, k_1\) e per coprire tutto il messaggio viene ripetuta un volta, in modo da ottenere \(k_0, k_1, k_0, k_1\), cifrando i bit del crittogramma saranno: \(m_0 \oplus k_0, m_1 \oplus k_1, m_2 \oplus k_0, m_3 \oplus k_1\). Adesso effettuando lo XOR tra il primo e il terzo bit ed il secondo con il quarto bit del crittogramma otteniamo:

  • \(c_0 \oplus c_2\) = \((m_0 \oplus k_0) \oplus (m_2 \oplus k_0)\) = \(m_0 \oplus m_2\)
  • \(c_1 \oplus c_3\) = \((m_1 \oplus k_1) \oplus (m_3 \oplus k_1)\) = \(m_1 \oplus m_3\)

dunque otteniamo delle informazioni sul testo in chiaro, che in alcuni casi possono essere sufficienti a decifrare tutto o parte del messaggio.

Crittografia Simmetrica

La crittografia simmetrica è una tecnica di crittografia in cui mittente e destinatario condividono la stessa chiave segreta per cifrare e decifrare i messaggi. Il problema di scambiare una chiave segreta su un canale pubblico verrà discusso nella sezione successiva, per il momento assumiamo che le parti comunicanti abbiano già concordato una chiave segreta.

Il cifrario AES (Advanced Encryption Standard) ed è una specifica per la crittografia dei dati elettronici stabilita dal National Institute of Standards and Technology (NIST) degli Stati Uniti nel 2001 ed è il cifrario simmetrico più comunemente utilizzato.

Questo è un algoritmo a blocchi, ovvero cifra i dati in blocchi di 128 bit, e supporta chiavi di 128, 192 e 256 bit. L'algoritmo è stato progettato per essere efficiente sia in termini di velocità che di memoria. Dal momento che AES cifra i dati in blocchi, è necessario un metodo per gestire i dati che non sono multipli di 128 bit. Questo viene fatto attraverso l'uso di modalità di operazione, che specificano come i blocchi di dati vengono cifrati e decifrati.

Modalità di operazione di AES

ECB

Il modo più intuitivo di utilizzare un cifrario a blocchi è la modalità ECB (Electronic Codebook). In questa modalità il messaggio viene diviso in blocchi di 128 bit e ogni blocco viene cifrato indipendentemente dagli altri. Al messaggio viene aggiunto del padding se necessario per raggiungere una lunghezza che sia multiplo di 128 bit. La seguente immagine mostra come funziona la modalità ECB:

è facile vedere che la decifratura di un testo cifrato con la modalità ECB è semplicemente la decifratura di ogni blocco di testo cifrato. Questa modalità è molto semplice da implementare e veloce, ma ha un grosso difetto: se due blocchi di testo in chiaro sono uguali, i blocchi cifrati saranno uguali. Questo non rispetta il requisito di nascondere la struttura del testo in chiaro e in alcuni casi può rivelare informazioni sul testo in chiaro. La seguente immagine mostra come un'immagine bitmap cifrata con la modalità ECB permette di riconoscere alcuni pattern sul contenuto dell'immagine originale:

In un certo senso si può vedere la modalità ECB come un cifrario a sostituzione monoalfabetica, dove ogni blocco di testo in chiaro viene cifrato con la stessa chiave. Per evitare questo problema si utilizzano altre modalità di operazione.

CBC

Per ovviare a questo problema si utilizza la modalità CBC (Cipher Block Chaining). In questa modalità il primo blocco di testo in chiaro viene cifrato con la chiave segreta e il risultato viene combinato con il secondo blocco di testo in chiaro tramite l'operazione XOR. Il risultato di questa operazione viene cifrato e cosi' via per tutti i blocchi di testo in chiaro. La seguente immagine mostra come funziona la modalità CBC:

Si vede chiaramente come un cambiamento nel primo blocco di testo in chiaro si propaghi a tutti i blocchi successivi, rendendo difficile riconoscere pattern nel testo cifrato. Dal momento che il primo blocco di testo in chiaro non ha un blocco precedente con cui combinarsi, si utilizza un blocco di inizializzazione (IV) che viene combinato con il primo blocco di testo in chiaro. L'IV deve essere casuale e non deve essere riutilizzato con la stessa chiave, altrimenti il cifrario diventa vulnerabile ad alcuni attacchi. Da notare che sebbene l'IV debba essere casuale non deve essere segreto, al contrario viene normalmente inviato insieme al testo cifrato. La decifratura di un testo cifrato con la modalità CBC è un po' più complessa rispetto alla modalità ECB, ma è comunque abbastanza semplice: si decifra il testo cifrato e si combina con il blocco precedente tramite l'operazione XOR, come mostrato nella seguente immagine:

CTR

Nella modalità CTR (Counter) AES non è utilizzato come un cifrario a blocchi ma come un generatore di flusso di byte (stream cipher). In questa modalità si utilizza un contatore che viene cifrato con la chiave segreta e combinato con il blocco di testo in chiaro tramite l'operazione XOR. La seguente immagine mostra come funziona la modalità CTR:

Il nonce è un numero casuale che viene combinato con il contatore per generare il blocco di testo cifrato. Anche in questo caso il nonce non è privato ma deve essere casuale e non deve essere riutilizzato con la stessa chiave. Un nonce ripetuto con la stessa chiave genera lo stesso flusso di byte, rendendo il cifrario vulnerabile a Many Time Pad. Per le proprietà dello XOR la decifratura di un testo cifrato con la modalità CTR è identica alla cifratura. Da notare che con questa modalità di operazione non è necessario aggiungere padding al testo in chiaro, in quanto è possibile troncare il flusso di byte cifrato al termine del testo in chiaro, questo pero' significa che CTR rivela la lunghezza del testo in chiaro, cosa che potrebbe essere un problema in alcuni contesti.

Introduzione alla crittografia asimmetrica

La crittografia asimmetrica, o crittografia a chiave pubblica, è un metodo di crittografia che utilizza due chiavi separate ma matematicamente correlate: una chiave pubblica e una chiave privata. A differenza della crittografia simmetrica, dove la stessa chiave è utilizzata sia per cifrare che per decifrare i dati, nella crittografia asimmetrica la chiave pubblica è utilizzata per cifrare i messaggi, mentre la chiave privata è utilizzata per decifrarli.

Alcuni problemi che le crittografia asimmetrica permette di risolvere sono:

  • Scambio di chiavi: permette a due parti di stabilire una chiave condivisa in modo sicuro senza dover scambiare una chiave segreta in anticipo

  • Cifrare un messaggio con chiave pubblica: permette a un mittente di cifrare un messaggio utilizzando la chiave pubblica del destinatario, garantendo che solo il destinatario possa decifrare il messaggio

  • Firme digitali: permettono di garantire l'integrità e l'autenticità di un messaggio, consentendo al mittente di firmare un messaggio con la propria chiave privata e al destinatario di verificare la firma utilizzando la chiave pubblica del mittente

Nei capitoli successivi approfondiremo i problemi sopra citati e vedremo alcuni protocolli e algoritmi che permettono di risolverli.

Scambio di Chiavi

Il problema dello scambio di chiavi è uno dei problemi fondamentali della crittografia. Se due parti vogliono comunicare in modo sicuro, devono concordare una chiave segreta che verrà utilizzata per cifrare e decifrare i messaggi. Il problema è che se le parti comunicanti condividono la chiave segreta su un canale pubblico, un attaccante potrebbe intercettare la chiave e decifrare i messaggi. L'algoritmo di scambio di chiavi più noto è Diffie-Hellman.

Per capire il funzionamento di Diffie-Hellman occorre introdurre alcuni concetti della matematica modulare. Si intende con \(a \mod n\) il resto della divisione intera di \(a\) per \(n\), ad esempio \(7 \mod 3 = 1\) in quanto il resto della divisione di 7 per 3 è 1. La matematica modulare ci è utile perché alcune operazioni che sono semplici sui numeri reali risultano complesse sui numeri in modulo. Ad esempio, il problema di trovare \(x\) tale che \(a^x = b\) è semplice sui numeri reali, è l'operazione del logaritmo; l'equivalente in matematica modulare invece è estremamente difficile e non si conoscono modi per risolverlo in modo efficiente. Ossia non c'è un algoritmo veloce (il termine corretto è polinomiale) per trovare \(x\) tale che \(a^x \mod n = b\), tale problema è detto problema del logaritmo discreto ed è alla base del funzionamento e della sicurezza di Diffie-Hellman.

Diffie-Hellman

Diamo una rapida panoramica di come funziona Diffie-Hellman, alcuni dettagli tecnici saranno omessi a favore di una spiegazione intuitiva. I passaggi dell'algoritmo sono i seguenti:

  • Alice e Bob concordano due parametri: un numero primo \(p\) e un numero \(g\) detto generatore.
  • Alice sceglie un numero segreto \(a\) detto chiave privata e calcola \(A = g^a \mod p\), detto chiave pubblica.
  • Bob sceglie un numero segreto \(b\) detto chiave privata e calcola \(B = g^b \mod p\), detto chiave pubblica.
  • Alice e Bob scambiano i valori \(A\) e \(B\).
  • Alice calcola \(s = B^a \mod p\).
  • Bob calcola \(s = A^b \mod p\).
  • Alice e Bob hanno concordato una chiave segreta \(s\) che possono utilizzare per cifrare e decifrare i messaggi.

L'algoritmo è corretto perché Alice calcola (è sottointesa l'applicazione del modulo) \(s = B^a = (g^b)^a = g^{ab}\) e Bob calcola \(s = A^b = (g^a)^b = g^{ab}\), dunque Alice e Bob concordano la stessa chiave segreta \(g^{ab}\). L'algoritmo è sicuro perché un attaccante che intercetta i valori \(A\) e \(B\) non può calcolare la chiave segreta \(s\) senza conoscere \(a\) o \(b\), e come detto precedentemente non esiste un algoritmo efficiente per risolvere il problema del logaritmo discreto.

Il paragone che viene fatto spesso per capire il funzionamento di Diffie-Hellman è di immagine i numeri dell'algoritmo come colori e l'operazione di esponenziazione come mescolare i colori. Alice e Bob concordano un colore (il generatore) e un colore di partenza (la chiave privata), e scambiano i colori mescolati (la chiave pubblica). Una volta ricevuto il colore mescolato, Alice e Bob mescolano il colore ricevuto con il proprio colore di partenza e ottengono lo stesso colore, che è la chiave segreta. Ma in tutto questo scambio di colori, un attaccante che intercetta i colori mescolati non può ottenere il colore segreto senza conoscere i colori di partenza.

Cifrari a chiave pubblica

Nei cifrari a chiave pubblica ogni utente possiede una coppia di chiavi: una chiave pubblica e una chiave privata. La chiave pubblica è accessibile a tutti, mentre la chiave privata è nota solo al proprietario. La chiave pubblica viene utilizzata per cifrare i messaggi, mentre la chiave privata viene utilizzata per decifrarli. Questo permette a chiunque di inviare messaggi cifrati all'utente, che può decifrarli solo con la propria chiave privata.

Il cifrario a chiave pubblica più noto è il cifrario RSA, che prende il nome dai suoi inventori Rivest, Shamir e Adleman.

RSA

Anche RSA come Diffie-Hellman funziona utilizzando la matematica modulare, tramite alcune proprietà dell'algebra modulare è possibile costruire una trapdoor function. Nella crittografia, una trapdoor function è una funzione che è facile da calcolare in una direzione, ma difficile da calcolare nella direzione opposta (trovare il suo inverso) senza informazioni speciali, chiamate trapdoor. Vediamo una rapida panoramica di come funziona RSA, anche in questo caso alcuni dettagli tecnici saranno omessi a favore una spiegazione intuitiva. I passaggi dell'algoritmo sono i seguenti:

  • Alice genera due numeri primi grandi \(p\) e \(q\) e calcola \(n = p \cdot q\).
  • Alice sceglie un numero \(e\) e rende pubblica la coppia \((n, e)\), questa è la chiave pubblica.
  • Alice calcola \(d\) tale che \(e \cdot d = 1 \mod \phi(n)\), dove \(\phi(n) = (p-1) \cdot (q-1)\), \(d\) è la chiave privata.
  • Bob cifra un messaggio \(m\) con la chiave pubblica di Alice calcolando \(c = m^e \mod n\).
  • Alice decifra il messaggio calcolando \(m = c^d \mod n\).

Il passaggio numero 3 potrebbe sembrare un po' oscuro, il motivo per cui \(d\) viene calcolato in quel modo è che \(m^{ed} = m \mod n\) se e solo se \(e \cdot d = 1 \mod \phi(n)\), questo è un risultato noto come generalizzazione del piccolo teorema di Fermat. La cosa importante è che la quantità \(d\) si può calcolare facilmente solamente conoscendo la fattorizzazione di \(n\), e come detto precedentemente non esiste un algoritmo efficiente per fattorizzare numeri grandi.

Facciamo un esempio con numeri piccoli per capire meglio il funzionamento di RSA:

  • Alice sceglie due numeri primi \(p = 61\) e \(q = 53\), calcola \(n = 61 \cdot 53 = 3233\).
  • Alice sceglie \(e = 17\) e rende pubblica la coppia \((n, e) = (3233, 17)\).
  • Alice calcola \(d = 2753\) (calcolato con l'algoritmo di Euclide esteso) e mantiene segreta la coppia \((n, d)\).
  • Bob vuole inviare il messaggio \(m = 1234\) ad Alice, calcola \(c = 1234^{17} \mod 3233 = 2183\).
  • Alice riceve il messaggio cifrato \(c = 2183\) e lo decifra calcolando \(m = 2183^{2753} \mod 3233 = 1234\).

Una osservazione da fare è che con RSA è possibile cifrare solamente messaggi di lunghezza inferiore alla lunghezza della chiave. Per cifrare messaggi più lunghi si potrebbe pensare di dividere il messaggio in blocchi più piccoli e cifrarli singolarmente, tuttavia RSA non è progettato per cifrare grandi quantità di dati, in quanto è molto più lento rispetto ai cifrari simmetrici. In pratica si utilizza RSA per cifrare una chiave casuale e si utilizza il cifrario simmetrico per cifrare i dati. Questa tecnica è conosciuta come envelope encryption ed è utilizzata da numerosi protocolli crittografici moderni, alcuni esempi verranno discussi nei capitoli successivi.

Firme digitali

Una firma digitale è uno schema matematico per verificare l'autenticità di messaggi o documenti digitali. Una firma digitale valida su un messaggio offre al destinatario la certezza che il messaggio provenga da un mittente noto al destinatario. Nello specifico, le firme digitali garantiscono le seguenti proprietà:

  • Autenticità: garantisce che un messaggio o documento provenga realmente dall'emittente dichiarato. Le firme digitali assicurano questa proprietà, poiché solo il possessore della chiave privata può generare una firma verificabile con la chiave pubblica corrispondente.

  • Integrità: assicura che il contenuto di un messaggio o documento non sia stato modificato durante la trasmissione. Le firme digitali e le funzioni hash crittografiche permettono di rilevare qualsiasi alterazione nei dati.

  • Non Ripudiabilità: impedisce all'emittente di negare di aver inviato un messaggio o effettuato una transazione. Le firme digitali forniscono questa proprietà, poiché la firma è generata con la chiave privata dell'emittente, rendendo impossibile la negazione da parte sua.

In modo simile a quanto visto per RSA, vi sono una coppia di chiavi legate da una relazione matematica tali che una chiave è utilizzata per firmare i messaggi (chiave privata) e l'altra per verificarli (chiave pubblica).

Firme con RSA

Portiamo un esempio di sistema di firma digitale basato su RSA. La generazione della coppia di chiavi funziona come visto precedentemente con e nel complesso il processo funziona in questo modo:

  • Alice genera due numeri primi grandi \(p\) e \(q\) e calcola \(n = p \cdot q\).
  • Alice sceglie un numero \(e\) e rende pubblica la coppia \((n, e)\), questa è la chiave pubblica.
  • Alice calcola \(d\) tale che \(e \cdot d = 1 \mod \phi(n)\), dove \(\phi(n) = (p-1) \cdot (q-1)\), \(d\) è la chiave privata.
  • Alice firma un messaggio \(m\) con la chiave privata calcolando \(s = m^d \mod n\).
  • Bob riceve il messaggio e la firma e verifica la firma calcolando \(m = s^e \mod n\).

La correttezza del processo di verifica della firma è garantita dalla stessa relazione matematica che garantisce la correttezza della decifratura dei messaggi cifrati con RSA. Infatti dato il messaggio \(m\) e la chiave pubblica \((n, e)\) è non c'è modo di trovare velocemente la quantità \(s\) tale che \(m = s^e \mod n\) senza conoscere la chiave privata \(d\). Notare che trovare \(s\) noto \(m\) equivale a trovare il messaggio conoscendo il crittogramma in RSA, quindi la sicurezza del sistema è basata sull'assunzione che non esista un algoritmo efficiente per fattorizzare numeri grandi.

In realtà non si firma mai direttamente il messaggio, ma si firma l'hash del messaggio. Questo perché le firme digitali sono spesso utilizzate per firmare documenti di grandi dimensioni e calcolare la firma su un hash è molto più efficiente. Le funzioni hash saranno discusse nei capitoli successivi.

Questo algoritmo rende chiara l'idea di come funzionano le firme digitali, tuttavia nel mondo reale si utilizzano protocolli più sofisticati come DSA (o la sua variante su curve ellittiche ECDSA).

Funzioni HASH

Una funzione di hash è una funzione matematica che mappa dati di dimensione arbitraria in dati di dimensione fissa. Questo processo è deterministico, ovvero per lo stesso input la funzione di hash restituirà sempre lo stesso output. Le funzioni di hash sono utilizzate in crittografia in diversi contesti, tra cui:

  • Integrità dei dati: per verificare che un messaggio non sia stato alterato durante la trasmissione. Per esempio, un hash può essere calcolato su un messaggio e inviato insieme al messaggio. Il destinatario può quindi calcolare l'hash sul messaggio ricevuto e confrontarlo con l'hash ricevuto per verificare l'integrità del messaggio.
  • Firma digitale: per generare firme digitali. Una firma digitale è un hash di un messaggio cifrato con la chiave privata del mittente. Il destinatario può verificare la firma decifrando il messaggio con la chiave pubblica del mittente e confrontando l'hash del messaggio con l'hash decifrato. Questo garantisce che il messaggio sia stato firmato dal mittente e non sia stato alterato.
  • Password hashing: per proteggere le password degli utenti. Le password non vengono memorizzate direttamente nel database, ma viene invece calcolato l'hash prima di essere memorizzate. Quando un utente accede, viene calcolato l'hash della password inserita e confrontata con l'hash memorizzato nel database. Questo protegge le password in caso di violazione del database.

Le funzioni di hash sono progettate per essere veloci da calcolare, ma difficili da invertire. Questo significa che, dato un hash, è computazionalmente difficile trovare l'input corrispondente. Inoltre, funzioni di hash diverse dovrebbero produrre output diversi anche per input simili.

Alcune proprietà desiderabili di una funzione di hash includono:

  • Deterministicità: per lo stesso input, la funzione di hash restituirà sempre lo stesso output.
  • Rapidezza: le funzioni di hash devono essere veloci da calcolare.
  • Difficoltà di inversione: è computazionalmente difficile trovare l'input corrispondente a un hash.
  • Diffusione: piccole modifiche all'input dovrebbero produrre output completamente diversi. Questo rende difficile prevedere l'output di una funzione di hash per input simili.
  • Collisione: è computazionalmente difficile trovare due input diversi che producono lo stesso hash. Perché se fosse facile trovare due input diversi che producono lo stesso hash, un attaccante potrebbe modificare un messaggio firmato senza che il destinatario se ne accorga.

Per funzioni di hash le proprietà crittografiche sono:

  • Dato un hash a n bit, la probabilità che un messaggio random produca lo stesso hash è \(1/2^n\).
  • Resistenza alla preimmagine: è computazionalmente difficile trovare un input che produce un hash specifico, cioè dato \(h\) è difficile trovare \(m\) tale che \(h = H(m)\). Dovrebbe richiedere un tempo proporzionale a \(2^n\) per una funzione di hash a n bit.
  • Resistenza alla seconda preimmagine: è computazionalmente difficile trovare un secondo input che produce lo stesso hash di un input specifico, cioè dato \(m_1\) è difficile trovare \(m_2\) tale che \(H(m_1) = H(m_2)\).
  • Resistenza alle collisioni: è computazionalmente difficile trovare due input diversi che producono lo stesso hash, cioè è difficile trovare \(m_1\) e \(m_2\) tali che \(H(m_1) = H(m_2)\). La difficoltà dovrebbe essere proporzionale a \(2^{n/2}\) per una funzione di hash a n bit.

Le funzioni di hash più comuni includono MD5, SHA-1 e SHA-256. Tuttavia, MD5 e SHA-1 sono considerate ormai obsolete e vulnerabili ad attacchi collisioni. In particolare MD5 permette collisioni in pochi secondi su un normale computer, mentre SHA-1 permette collisioni ma a costi molto più elevati. SHA-256 è una funzione di hash più sicura e resistente, che produce un hash di 256 bit. La funzione SHA-256 è attualmente considerata sicura e viene utilizzata in molte applicazioni crittografiche.

Gestione delle password

Per invertire l'hash di una password, un attaccante può utilizzare tabelle di hash precalcolate. Per esempio un attaccante si può creare una tabella di hash per le password più comuni o per tutte le possibili combinazioni di caratteri. Poi ogni volta che vuole invertire un hash, può cercare nella tabella il corrispondente hash e ottenere la password originale.

Ovviamente questo attacco costa tempo e risorse, in particolare lo spazio per memorizzare le tabelle di hash può essere molto grande. Tuttavia, esistono le tabelle di hash arcobaleno (rainbow tables) che permettono di ridurre lo spazio necessario per memorizzare i hash al costo di un aumento del tempo di ricerca nella tabella.

Per proteggere le password dagli attacchi con tabelle di hash, si può utilizzare il concetto di salt. Un salt è un valore casuale univoco che viene concatenato alla password prima di essere hashata. In questo modo, anche se due utenti hanno la stessa password, i loro hash saranno diversi a causa del salt diverso. Questo rende più difficile per un attaccante utilizzare tabelle di hash precalcolate, in quanto dovrebbe creare una tabella di hash per ogni possibile salt.

Per esempio, se un utente ha la password "password", il processo di hash sarebbe:

  • Generare un salt casuale di 6 caratteri, ad esempio "abcdef".
  • Generare l'hash della password concatenata al salt, \(hash = H(password+salt)\) dove la somma indica la concatenazione delle stringhe.
  • Memorizzare il salt e l'hash nel database.

Quando l'utente accede, il processo di verifica della password sarebbe:

  • Recuperare il salt e l'hash dal database relativo all'utente.
  • Concatenare la password inserita dall'utente al salt, \(hash2 = H(password + salt)\).
  • Verificare che \(hash2 == hash\).

In questo modo, se il database viene violato e gli hash e i salt vengono rubati, un attaccante non può utilizzare le tabelle di hash precalcolate per invertire gli hash, in quanto se un attaccante conosce l'hash di "password" con un determinato salt, non può utilizzarlo per trovare l'hash di "password"+salt. In particolare l'attaccante dovrebbe creare una tabella con tutte le password lunghe almeno 8+6=14 caratteri.

Firma digitale con chiave simmetrica: HMAC

Un codice di autenticazione del messaggio (MAC) è un codice che viene generato da una funzione di hash e una chiave segreta. Il MAC viene inviato insieme al messaggio e può essere utilizzato per verificare l'integrità e l'autenticità del messaggio. Il MAC è calcolato utilizzando la chiave segreta e il messaggio, in modo che solo chi possiede la chiave segreta possa generare un MAC valido per quel messaggio. Il destinatario quando riceve il messaggio e il suo MAC può ricalcolare il MAC utilizzando la stessa chiave segreta e verificare che il MAC ricevuto corrisponda al MAC calcolato.

Di MAC ne esistono diversi tipi, tra cui HMAC (Hash-based Message Authentication Code) che è uno dei più comuni. HMAC utilizza una funzione di hash crittografica, come SHA-256, e una chiave segreta per generare il MAC. HMAC è progettato per essere sicuro contro attacchi di forza bruta e collisioni, e viene utilizzato in molti protocolli di sicurezza, come TLS, IPsec e SSH.

Il MAC è simile alla firma digitale, ma utilizza una chiave segreta condivisa tra mittente e destinatario, mentre la firma digitale utilizza una chiave privata del mittente e una chiave pubblica del destinatario. Per capire meglio le differenze tra hash, MAC e firma digitale, consideriamo i seguenti obiettivi di sicurezza:

  • Integrità: può il destinatario verificare che il messaggio non sia stato alterato?
  • Autenticazione: può il destinatario verificare che il messaggio provenga dal mittente?
  • Non ripudio: può il mittente negare di aver inviato il messaggio?

Nella seguente tabella, vediamo come hash, MAC e firma digitale soddisfino questi obiettivi:

Obiettivo di sicurezzaHashMACFirma digitale
Integrità
AutenticazioneNo
Non ripudioNoNo
Tipo di chiaveNessunaSimmetricaAsimmetrica

Quindi i MAC sono utilizzati quando mittente e destinatario condividono una chiave segreta e vogliono garantire l'integrità e l'autenticità del messaggio. Non forniscono tuttavia la non ripudiabilità, poiché il mittente potrebbe negare di aver generato il MAC.

Invece, siccome utilizzano una chiave simmetrica condivisa, i MAC sono più veloci da calcolare rispetto alle firme digitali, ma richiedono che mittente e destinatario condividano la stessa chiave segreta. Cosa impossibile in un contesto di comunicazione pubblica dove si dovrebbe generare una chiave segreta per ogni coppia mittente-destinatario, quindi in una rete di \(n\) utenti ci sarebbero \(n*(n-1)/2\) chiavi segrete da gestire, mentre con le firme digitali basta un coppia di chiavi pubblica-privata per ogni utente, quindi \(2n\) chiavi da gestire. Per questo motivo, le firme digitali sono più adatte per la comunicazione pubblica, mentre i MAC sono più adatti per la comunicazione privata.

Un modo ERRATO di autenticare un messaggio potrebbe essere di generare una chiave segreta casuale \(K\) e fare \(MAC = H(K + messaggio)\). Questo metodo è vulnerabile ad attacchi di tipo length extension, in cui un attaccante può estendere il messaggio originale con dati arbitrari e generare un nuovo MAC valido senza conoscere la chiave segreta. Per evitare questo tipo di attacco, HMAC utilizza una costruzione più complessa che prevede l'utilizzo della chiave segreta in più passaggi.

Esempi di crittografia in sistemi real world

Per ora abbiamo visto i principi di base della crittografia e alcuni algoritmi e protocolli che la utilizzano. In questo capitolo vedremo alcuni esempi di come la crittografia viene utilizzata in sistemi reali.

  • TLS: il protocollo Transport Layer Security (TLS) è un protocollo di sicurezza che fornisce crittografia end-to-end utilizzato da ogni browser web per connettersi a un sito web in modo sicuro. TLS protegge la privacy e l'integrità dei dati trasmessi su Internet, garantendo che solo il mittente e il destinatario possano leggerli.
  • SSH: il protocollo Secure Shell (SSH) è un protocollo di rete che permette di accedere in modo sicuro a un computer remoto. SSH utilizza la crittografia asimmetrica per autenticare il server e la crittografia simmetrica per proteggere la comunicazione tra client e server. SSH è ampiamente utilizzato per connettersi a server remoti tramite una connessione sicura.
  • JWT: i JSON Web Token (JWT) sono un formato standard per rappresentare i token di sicurezza in formato JSON. I JWT vengono utilizzati per autenticare e autorizzare gli utenti in applicazioni web e API. I JWT contengono informazioni sull'utente e sono firmati digitalmente per garantire l'integrità e l'autenticità dei dati.

TLS

Il protocollo Transport Layer Security (TLS) è un protocollo di sicurezza che fornisce crittografia end-to-end per la comunicazione su una rete. TLS è il successore del protocollo Secure Sockets Layer (SSL) e viene utilizzato per proteggere la privacy e l'integrità dei dati trasmessi su Internet. TLS è ampiamente utilizzato per proteggere le comunicazioni tra client e server su Internet, ad esempio durante la navigazione su siti web, l'invio di email e il trasferimento di file.

In particolare, TLS viene utilizzato per proteggere i dati trasmessi tra un client (ad esempio un browser web) e un server (ad esempio un sito web) durante una connessione HTTPS. Quando un client si connette a un server utilizzando HTTPS, il client e il server negoziano i parametri di sicurezza, come l'algoritmo di crittografia da utilizzare e la chiave di sessione. Una volta stabiliti i parametri di sicurezza, i dati trasmessi tra client e server sono crittografati in modo che solo il mittente e il destinatario possano leggerli.

Funzionamento di TLS

TLS fornisce tre principali servizi di sicurezza:

  • Crittografia: i dati trasmessi tra client e server sono crittografati in modo che solo il mittente e il destinatario possano leggerli.
  • Autenticazione: il server può autenticare la sua identità al client, dimostrando che è effettivamente il server a cui il client si sta connettendo.
  • Integrità dei dati: i dati trasmessi sono protetti da modifiche non autorizzate durante la trasmissione.

Il funzionamento di TLS può essere suddiviso in diverse fasi:

  1. Handshake: il client e il server negoziano i parametri di sicurezza, come l'algoritmo di crittografia da utilizzare e la chiave di sessione. Durante questa fase, il server può autenticare la sua identità al client presentando un certificato digitale firmato da un'autorità di certificazione (CA).
  2. Scambio di chiavi: il client e il server scambiano le chiavi di sessione crittografiche che verranno utilizzate per cifrare e decifrare i dati trasmessi.
  3. Crittografia dei dati: i dati trasmessi tra client e server sono crittografati utilizzando le chiavi di sessione condivise.
  4. Integrità dei dati: i dati trasmessi sono protetti da modifiche non autorizzate utilizzando funzioni di hash e firme digitali.

Certificati digitali

I certificati digitali sono utilizzati in TLS per autenticare l'identità del server al client. Un certificato digitale è un documento elettronico che contiene informazioni sull'identità del server, come il nome del dominio, l'indirizzo IP e la chiave pubblica del server. Il certificato è firmato digitalmente da un'autorità di certificazione (CA) di fiducia, che attesta che il certificato è valido e che il server è effettivamente quello che afferma di essere.

Quando un client si connette a un server utilizzando TLS, il server invia il suo certificato digitale al client durante la fase di handshake. Il client può verificare l'autenticità del certificato verificando la firma digitale del certificato con la chiave pubblica della CA. Se il certificato è valido, il client può fidarsi dell'identità del server e procedere con la comunicazione sicura.

Questo prevede che il client abbia una lista di CA di fiducia, che contiene le chiavi pubbliche delle CA che il client ritiene affidabili. Se il certificato del server è firmato da una CA presente nella lista di fiducia del client, il client accetta il certificato come valido. Questo meccanismo garantisce che il client possa verificare l'identità del server e proteggere la comunicazione da possibili attacchi Man-in-the-Middle.

JWT

I JWT (JSON Web Token) sono un formato aperto e standardizzato per rappresentare in modo sicuro le informazioni tra due parti. I JWT sono costituiti da tre parti separate da punti (.): intestazione, payload e firma. Queste tre parti sono codificate in Base64 e separate da punti per formare il token JWT completo.

I JWT sono utilizzati per salvare informazioni come l'identità dell'utente autenticato e le autorizzazioni associate a quel token. I JWT vengono generati dal server e inviati al client, che li memorizza e li invia al server con ogni richiesta. Il server può quindi verificare la firma del token per garantire che il token sia valido e che le informazioni al suo interno siano autentiche e non siano state alterate.

I JWT offrono diversi vantaggi rispetto ad altri metodi di autenticazione, tra cui:

  • Stateless: i JWT sono autocontenuti e contengono tutte le informazioni necessarie per autenticare un utente. Questo significa che il server non ha bisogno di memorizzare lo stato dell'utente tra le richieste, rendendo il sistema più scalabile.
  • Sicurezza: i JWT possono essere firmati digitalmente per garantire che le informazioni al loro interno siano autentiche e non siano state alterate. Questo protegge i token da attacchi come l'iniezione di token o la falsificazione.
  • Flessibilità: i JWT possono contenere qualsiasi informazione in formato JSON, consentendo di personalizzare i token per le esigenze specifiche dell'applicazione.
  • Interoperabilità: i JWT sono un formato standardizzato e supportato da molti framework e librerie, consentendo di utilizzarli in diverse applicazioni e ambienti.

Un esempio di token JWT potrebbe essere il seguente:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

In questo esempio, il token JWT è composto da tre parti separate da punti:

  • Intestazione: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 che contiene l'algoritmo di firma utilizzato e il tipo di token. In questo caso, l'algoritmo di firma è HS256 (HMAC con SHA-256) e il tipo di token è JWT.
  • Payload: eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ che contiene le informazioni dell'utente, come l'ID utente, il nome utente e la data di creazione del token. In questo caso il payload contiene:
    • ID utente: 1234567890
    • Nome utente: John Doe
    • Data di creazione: 1516239022
  • Firma: SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c che viene generata utilizzando la chiave segreta del server e viene utilizzata per verificare che il token sia autentico e non sia stato alterato.

L'intestazione e il payload contengono informazioni in formato JSON, come l'algoritmo di firma utilizzato e le informazioni dell'utente. La firma è generata utilizzando la chiave segreta del server e viene utilizzata per verificare che il token sia autentico e non sia stato alterato.

Per generare un token JWT, il server può seguire i seguenti passaggi:

  1. Creare un payload JSON contenente le informazioni dell'utente da includere nel token.
  2. Creare un'intestazione JSON specificando l'algoritmo di autenticazione, ad esempio HS256 per HMAC con SHA-256 oppure RS256 per RSA con SHA-256.
  3. Codificare l'intestazione e il payload in Base64.
  4. Firmare il token utilizzando la chiave segreta del server.
  5. Codificare la firma in Base64 e concatenarla all'intestazione e al payload separati da punti.

SSH

SSH (Secure Shell) è un protocollo di rete che permette di accedere in modo sicuro a un computer remoto. SSH utilizza la crittografia asimmetrica per autenticare il server e la crittografia simmetrica per proteggere la comunicazione tra client e server. Inoltre, SSH supporta l'inoltro di porte, la compressione dei dati e l'inoltro di agenti di autenticazione.

Le principali componenti di sicurezza di SSH includono:

  • Autenticazione del server: il server invia il suo certificato digitale al client durante la fase di handshake. Alla prima connessione, il client deve verificare l'autenticità del certificato del server e memorizzarlo in modo sicuro per le connessioni successive. Alle connessioni successive, il client verifica che il certificato del server corrisponda a quello memorizzato. Questo meccanismo garantisce che il client si stia connettendo al server corretto e non a un server malevolo che sta eseguendo un attacco Man-in-the-Middle.
  • Autenticazione del client: il client può autenticarsi al server utilizzando la password, la chiave pubblica o altri metodi di autenticazione supportati dal server. L'autenticazione del client è opzionale e può essere configurata dal server.
  • Crittografia dei dati: i dati trasmessi tra client e server sono crittografati utilizzando la crittografia simmetrica. La chiave di sessione viene negoziata durante il processo di handshake e utilizzata per criptare e decriptare i dati trasmessi. Viene anche controllata l'integrità e l'autenticità dei dati.

L'autenticazione del client in SSH può avvenire in diversi modi, i due più comuni sono:

  • Password: il client inserisce la password per autenticarsi al server. Questo è il metodo di autenticazione più comune, ma è anche il meno sicuro, poiché le password possono essere soggette a attacchi di forza bruta o di dizionario.
  • Chiave pubblica: il client genera una coppia di chiavi pubblica e privata e invia la chiave pubblica al server. Il server memorizza la chiave pubblica del client e la utilizza per autenticare il client durante le connessioni successive. Questo metodo è più sicuro delle password, poiché richiede la conoscenza della chiave privata per autenticarsi.

Chiavi SSH

Le chiavi SSH possono sfruttare diversi algoritmi di crittografia, tra cui RSA, DSA ed ECDSA. Le chiavi SSH sono generalmente memorizzate nei file id_rsa (chiave privata) e id_rsa.pub (chiave pubblica) nella directory .ssh dell'utente. Le chiavi pubblica vengono salvate nel server remoto nel file authorized_keys per consentire l'autenticazione dei client.

Esistono diversi tipi di chiavi SSH, tra cui:

  • Chiavi RSA: utilizzano l'algoritmo RSA per l'autenticazione. Le chiavi RSA sono comunemente utilizzate e supportate da molti server SSH.
  • Chiavi DSA: utilizzano l'algoritmo DSA per l'autenticazione. Le chiavi DSA sono meno comuni rispetto alle chiavi RSA.
  • Chiavi ECDSA: utilizzano l'algoritmo ECDSA (Elliptic Curve Digital Signature Algorithm) per l'autenticazione. Le chiavi ECDSA sono più recenti e offrono una maggiore sicurezza rispetto alle chiavi RSA e DSA.
  • Chiavi ED25519: utilizzano l'algoritmo EdDSA (Edwards-curve Digital Signature Algorithm) per l'autenticazione. Le chiavi ED25519 sono ancora più recenti e offrono una maggiore sicurezza rispetto alle chiavi ECDSA.

I file che contengono la chiave privata avranno il nome id_rsa per RSA, id_dsa per DSA, id_ecdsa per ECDSA e id_ed25519 per ED25519. I file che contengono la chiave pubblica avranno il nome id_rsa.pub per RSA, id_dsa.pub per DSA, id_ecdsa.pub per ECDSA e id_ed25519.pub per ED25519.

Sono consigliabili RSA e ED25519 per la maggiore sicurezza e supporto da parte dei server SSH moderni. In particolare ED25519 è preferibile per la sua maggiore sicurezza e prestazioni rispetto a RSA. Le chiavi RSA a 1024 bit sono considerate obsolete e poco sicure, mentre le chiavi RSA a 2048 bit sono ancora considerate sicure, ma è preferibile utilizzare chiavi più lunghe per una maggiore sicurezza. Le chiavi pubbliche ED25519 sono molto più corte rispetto alle chiavi RSA, il che le rende più facili da trasmettere e memorizzare e hanno una sicurezza paragonabile a quella di RSA con ~ 3000 bit.