Passa ai contenuti principali

SSH: un esempio di crittografia applicata

SSH (o Secure Shell) è il protocollo che da diversi anni ha preso il posto di Telnet e che consente di amministrare in sicurezza macchine remote da riga di comando. Sebbene SSH sia largamente utilizzato, non sempre sono noti i meccanismi che ne governano il funzionamento. Obiettivo di quest'articolo è pertanto quello di raccontare SSH "sotto il cofano". Questo offrirà anche l'occasione di illustrare alcune fra le principali tecniche di crittografia. Ambiente di riferimento sarà, come di consueto, Linux.

Breve introduzione alla crittografia

Come noto, la crittografia è la tecnica che, nei casi in cui sia richiesta riservatezza, consente di rendere un messaggio comprensibile esclusivamente al legittimo destinatario. Questo può ottenersi attraverso opportune trasformazioni che rendano lo stesso testo accessibile solo a chi sia in grado di decodificarlo.

Un metodo estremamente semplice di codifica potrebbe essere, solo a titolo didattico, quello di trasporre di un numero prefissato di posizioni sull'alfabeto le lettere del messaggio (nel mondo TLC qualcosa di analogo potrebbe ottenersi slittando circolarmente di un numero convenuto di posizione i bit che compongono il file del messaggio). Il destinatario, a conoscenza del criterio di codifica, potrebbe allora ricostruire il messaggio originario semplicemente eseguendo l'operazione di trasposizione inversa; per tutti gli altri il messaggio risulterebbe incomprensibile.

Per quanto elementare, un simile sistema di codifica mette però in evidenza un aspetto importante: la segretezza del messaggio è in questo caso affidata all'algoritmo col quale lo stesso viene codificato; di conseguenza, più elaborato sarà l'algoritmo di codifica, minore sarà la probabilità che chi dovesse venire in possesso del messaggio senza autorizzazione possa anche servirsene.

Vero è che, per quanto complessi possano concepirsi gli algoritmi di codifica, un simile sistema risulterà comunque di modesta utilità pratica. Si pensi ad esempio al contesto delle telecomunicazioni: ogni qual volta un algoritmo venisse violato, si porrebbe la necessità di implementarne uno nuovo con costi di sviluppo prevedibilmente onerosi. Peraltro, così facendo, sarebbero esclusi a priori i sistemi open source!

Crittografia simmetrica con chiave privata

Consideriamo ora un altro esempio. Questa volta, dato un testo in chiaro, si immagini di generare una stringa, che per semplicità considereremo della medesima lunghezza del testo. Nel gergo crittografico stringhe di questo tipo prendono il nome di "chiavi". Volendo di proposito semplificare qui le cose, il testo codificato potrebbe essere il risultato dello XOR bit a bit di testo e chiave. In questo caso, solo chi conosce la chiave è in grado di risalire al testo originario. Risulta evidente quindi che in questo scenario la sicurezza risiede nella chiave e non più nell'algoritmo di cifratura. Anzi in un simile contesto non c'è più ragione di tener segreto il metodo di codifica: è sufficiente non rivelare la chiave.

Per diversi anni, questo della chiave è stato il principale sistema di codifica crittografica e ancora oggi riveste un'importanza fondamentale come sarà chiaro a breve. Ovviamente gli odierni algoritmi di cifratura (fra i principali ricordiamo Data Encryption Standard e Advanced Encryption Standard), anche se pubblici, sono notevolmente più complessi di quello appena visto, ma il principio resta invariato: la sicurezza risiede nella chiave, nella sua complessità e nella sua segretezza. Questo impone quindi che la chiave non debba essere rivelata dal proprietario a nessuno al di fuori del destinatario del messaggio: non a caso si parla di "chiave privata" o "chiave simmetrica".

Quest'ultimo aspetto, specialmente in ambito telecomunicazioni, costituisce un ostacolo non trascurabile. Difatti, come poter distribuire in modo sicuro una chiave "privata" fra due macchine connesse mediante una rete per definizione insicura?

Crittografia asimmetrica con chiavi pubblica/privata

A partire dagli anni '70 sono stati studiati particolari algoritmi (fra tutti spicca RSA che prende il nome dai suoi inventori Rivest, Shamir e Adleman) noti come sistemi "a chiave pubblica", "a coppia di chiavi pubblica e privata", "a chiave asimmetrica" e simili. L'idea che distingue questi nuovi algoritmi è quella secondo cui il messaggio che viene codificato con una certa chiave può essere decodificato esclusivamente con un'altra chiave data e viceversa. La prima fra queste due chiavi viene detta "pubblica" e può essere liberamente distribuita; la seconda viene invece indicata come "privata" e non deve essere svelata ad alcuno (neanche al destinatario del messaggio). La chiave privata è l'unica col potere di decifrare il messaggio codificato mediante chiave pubblica e l'unica chiave in grado di decifrare un messaggio cifrato con chiave privata èì la corrispondente chiave pubblica.

Esaminiamo dunque il seguente scenario: il computer PC_A vuole inviare via rete un messaggio riservato al computer PC_B. PC_A e PC_B sono dotati entrambi di una coppia di chiavi pubblica/privata.
  1. PC_B invia a PC_A la sua chiave pubblica;
  2. PC_A utilizza la chiave pubblica di PC_B per codificare il messaggio;
  3. PC_A invia il messaggio (codificato) a PC_B;
  4. PC_B decodifica il messaggio ricevuto da PC_A mediante la propria chiave privata;
I punti di vulnerabilità vanno cercati negli scambi via rete fra PC_A e PC_B. Ma, a ben vedere, non se ne trovano. Difatti:
  • al punto 1 la chiave trasmessa è pubblica, quindi liberamente redistribuibile: chi ne dovesse entrare abusivamente in possesso non potrebbe comunque servirsene per decodificare il messaggio;
  • al punto 3 il male intenzionato che dovesse intercettare il messaggio cifrato non saprebbe come decifrarlo, poiché non in possesso della chiave (privata) per farlo.

La crittografia a chiavi pubblica/privata supera quindi il problema della distribuzione delle chiavi su mezzo insicuro e per questo offre una modalità più sicura rispetto a quella della crittografia simmetrica nello scambio di messaggi riservati.

Sussiste tuttavia ancora un ostacolo: se confrontati con quelli a chiave privata, gli algoritmi a chiave pubblica sono computazionalmente più complessi, di conseguenza più onerosi in termini di tempi di risposta. Questo è il motivo per cui usualmente viene adottato un compromesso fra i due sistemi e spesso gli algoritmi a chiave pubblica vengono utilizzati per condividere fra i due interlocutori la chiave privata che viene poi utilizzata per cifrare simmetricamente i messaggi.

D'altra parte la singolare proprietà della coppia di chiavi pubblica/privata ben si presta all'implementazione di altre funzioni crittografiche come sarà chiaro a breve.

Funzioni crittografiche di hash

Un altro argomento rilevante in crittografia è rappresentato delle funzioni di hash. In generale, quelle di hash sono funzioni matematiche non invertibili in grado di produrre una stringa di lunghezza predefinita a partire da una stringa di lunghezza arbitraria. Una funzione crittografica di hash è nello specifico una funzione di hash le cui proprietà la rendono particolarmente idonea per gli scopi della crittografia. Difatti:

  • data una funzione crittografica di hash non è possibile che due messaggi differenti, anche molto simili, producano lo stesso risultato;
  • lo stesso messaggio processato con la stessa funzione crittografica di hash produce sempre lo stesso risultato;
  • anche conosscendo la funzione crittografica di hash che lo ha generato, è estremamente difficile - al limite dell'impossibile - risalire dal risultato al messaggio che lo ha generato;
  • l'implementazione delle funzioni di hash è agevole ed il calcolo risulta estremamente rapido.
In crittografia le funzioni di hash possono essere ad esempio utilizzate per certificare che due interlocutori che ottengono lo stesso valore di hash mediante la stessa funzione, sono effettivamente in possesso del medesimo documento.

Fra le varie, la MD5 è una funzione hash crittografica (Ronald Rivest, 1991) che accetta in input una stringa di lunghezza arbitraria e, molto velocemente, ne produce in output un'altra da 128 bit. Si vedrà a breve il suo ruolo in SSH.

La firma digitale

La firma digitale è lo strumento che consente di "firmare" elettronicamente dei documenti che, in tal modo, acquistano valore legale, venendo ad essere garantite:
  • autenticità, ovvero certezza sull'identità dell'autore,
  • integrità, vale a dire sicurezza del fatto che il documento non sia stato modificato nel transito da mittente a destinatario,
  • non ripudio in quanto chi ha firmato il documento mediante firma elettronica non può successivamente disconoscerlo.
La firma digitale si fonda sull'uso congiunto di funzioni di hash e crittografia asimmetrica. Il procedimento è lineare:
  1. L'autore calcola l'hash del documento. Questa deve essere di 256 bit e prende il nome di "impronta digitale del documento".
  2. L'autore codifica l'impronta del documento mediante la propria chiave privata. Ottiene così la firma digitale.
  3. Sempre l'autore invia documento e firma digitale al destinatario.
  4. Il destinatario, ricevuti documento e firma, decodifica la firma mediante la chiave pubblica dell'autore ricavando così l'impronta del documento.
  5. Il destinatario, attraverso la stessa funzione di hash già utilizzata dall'autore, calcola a sua volta l'impronta partendo dal documento ricevuto.
  6. Finalmente il destinatario confronta le due impronte e solo nel caso in cui queste coincidono potrà ritenere valido il documento ricevuto.
É immediato verificare che un documento che superi l'esame della firma digitale rispetta le tre caratteristiche descritte inizialmente.

I certificati digitali

Nonostante il grado di sicurezza introdotto dalle tecniche crittografiche fin qui descritte, esiste ancora un punto di vulnerabilità: come garantire, ad esempio, che l'autore di un documento o la controparte di una conversazione siano effettivamente chi dichiarano di essere? A ben vedere, difatti, fra i due attori di una comunicazione potrebbe porsi abusivamente un terzo (il famigerato e temuto man in the middle) che, spacciandosi per interlocutore ora dell'uno ora dell'altro, potrebbe fraudolentemente intercettare e alterare la comunicazione in proprio favore.

Per proteggere gli utenti da pericoli di questo tipo sono stati introdotti i certificati digitali. Un certificato digitale è in particolare un documento elettronico attraverso il quale un ente, riconosciuto come fidato dalle parti in causa che prende il nome di Certification Authority (o CA), garantisce l'associazione univoca fra un soggetto (persona fisica, persona giuridica o servizio) ed una chiave pubblica.

Per aumentare ulteriormente il grado di sicurezza la validità di un certificato è di norma limitata nel tempo. Inoltre, la compromissione della chiave privata o eventuali cambiamenti nella relazione soggetto-chiave pubblica comportano la revoca o la sospensione dello stesso certificato. La verifica di un certificato è peraltro alla portata di tutti dal momento che le Certification Authority sono tenute a mantenrere aggiornati i registri pubblici dei certificati digitali emessi, revocati o sospesi (Certification Revocation List o CRL).

L'insieme di macchine, processi e software (distribuito) che consentono alle Certification Authority di esercitare il proprio ruolo prende il nome di Public Key Infrastructure (o PKI).

La crittografia di SSH

Le scelte implementative adottate in SSH rappresentano un interessante esempio di crittografia applicata.

L'algoritmo Diffie-Hellman

Furono Whitfield Diffie e Martin Hellman nel 1976 (ancor prima della formalizzazione di sistemi a chiave pubblica) gli autori di un algoritmo che consentiva lo scambio di una chiave privata su di un mezzo insicuro e che ancora oggi è alla base del funzionamento di SSH. Al fine di non appesantire la trattazione con calcoli matematici complessi, se ne presenta qui una versione semplificata, in grado comunque di rendere l'idea della sua efficacia.

Siano PC_A e PC_B due computer, connessi attraverso una rete, che intendano scambiarsi messaggi riservati:
  1. PC_A genera due numeri interi positivi, e di "elevato" (il senso sarà chiaro a breve) valore: N e A
  2. PC_B genera l'intero positivo B di valore anch'esso "elevato"
  3. PC_A invia a PC_B i valori N e N^A
  4. PC_B, ricevuto N, calcola N^B e lo invia a PC_A
  5. PC_A calcola K = (N^B)^A = N^(A*B)
  6. PC_B calcola K = (N^A)^B = N^(A*B)
  7. PC_A e PC_B usano K come chiave simmetrica per cifrare/decifrare i messaggi.
Non deve sfuggire che nei punti da 1 a 6 fra i due computer vengono scambiati i soli valori N, N^A e N^B. Viceversa, A e B non vengono mai distribuiti, rimanendo noti esclusivamente a PC_A il primo, e a PC_B il secondo.

Si consideri anche che un eventuale hacker che, avendo intercettato i messaggi codificati, volesse decifrarli, dovrebbe essere in grado di ricostruire la chiave K=N^(A*B). In linea di massima questo è possibile: come visto, lo stesso hacker potrebbe aver "sniffato" sulla rete N, N^A e N^B e, risolvendo due logaritmi in base N potrebbe ora risalire ad A e B e calcolare K.

Vero è, d'altra parte, che il calcolo di un logaritmo non è di soluzione immediata. E lo è ancor meno se i valori in gioco sono sufficientemente alti. Su questo si fonda l'efficacia dell'algoritmo di Diffie-Helmann: scegliendo A, B ed N sufficientemente grandi, il tempo impiegato per individuare la chiave K sarà sicuramente maggiore di quello occupato dalla comunicazione fra i due computer. A questo si aggiunga che la terna di numeri A, B, N viene rinnovata ad ogni nuova sessione di trasmissione.

Autenticazione in SSH

Una volta reso sicuro il canale di trasmissione mediante lo scambio Diffie-Hellman della chiave di cifratura fra i due interlocutori, è possibile procedere all'autenticazione della macchina locale presso il computer remoto.

La soluzione certamente più conosciuta è quella dell'autenticazione mediante nome e password dell'utente col quale si intende accedere alla macchina remota. In questo caso, a meno di altre misure di sicurezza (es. firewall), chiunque sia in grado di esibire un'utenza e la relativa password valide presso l'host remoto, ha accesso alla stesso.

Esiste però un metodo alternativo, certamente più sicuro, che, sfruttando MD5 e chiave pubblica, opera un controllo per molti aspetti simile a quello della firma elettronica.

Iniziamo dunque col definire:

PC_A: l'host locale
PC_B: la macchina remota alla quale si intende accedere da PC_A
SSHd_A: il processo client SSH che gira su PC_A
SSHd_B: il processo server SSH su PC_B
User_B: l'utente di PC_B col quale si intende accedere a PC_B
K: la chiave di sessione condivisa mediante algoritmo Diffie-Hellman/td>
Pri_K_A: la chiave privata di PC_A
Pub_K_A: la chiave pubblica di PC_A

Questo il processo di autenticazione SSH con chiavi pubblica/privata:
  1. Se non già presente, Pub_K_A viene copiata all'interno del file authorized_keys nella directory /home dell'utente User_B in PC_B.
  2. SSHd_A inoltra a SSHd_B la richiesta di connessione specificando di voler accedere a PC_B come User_B.
  3. A fronte della richiesta di accesso da SSHd_A, SSHd_B controlla se nel file authorized_keys esiste la chiave Pub_K_A.
  4. Se SSHd_B trova la chiave Pub_K_A in authorized_keys genera un numero casuale N e utilizza Pub_K_A per crittografarlo prima di inviarlo a SSHd_A. Questo al fine di verificare la reale identità di PC_A, ovvero per sincerarsi che PC_A sia in possesso della chiave pivata Pri_K_A.
  5. Solo se PC_A possiede realmente la chiave pivata Pri_K_A, SSHd_A è in grado di decodificare il messaggio ricevuto da SSHd_B mediante Pri_K_A e di ricavare N.
  6. SSHd_A combina allora N con la chiave condivisa K, calcola l'hash MD5 del numero NK così ottenuto e invia il risultato a SSHd_B.
  7. SSHd_B esegue il medesimo calcolo con i dati in suo possesso, confronta il proprio risultato con quello ricevuto da SSHd_A e, solo se i due valori coincidono, PC_A viene autenticato.


SSH in Linux

Di seguito le istruzioni in ambiente Linux per configurare SSH in modo di poter sfruttare l'autenticazione mediante crittografia asimmetrica.

Per generare una coppia di chiavi pubblica-privata è sufficiente anche solo eseguire:
$ ssh-keygen
e accettare le condizioni proposte come default: le chiavi pubblica e privata per il proprio utente vengono salvate nei file ~/.ssh/id_rsa.pub e ~/.ssh/id.rsa.

Lo step successivo è ora quello di condividere la chiave pubblica con l'utente col quale si intende accedere alla macchina remota. A tal fine:
$ ssh-copy-id <remote_user_name>@remote_host[:<port>]
Da ora in poi il nostro utente potrà accedere dalla stessa macchina locale alla macchina remota senza neanche la necessità di digitare la password dell'utente remoto (viceversa, avendo precedentemente specificato una password per le chiavi, ora la stessa verrà richiesta a ogni nuova connessione):
$ ssh <remote_user_name>@<remote_host>[:<port>]
Ovviamente ssh-keygen consente un livello di dettaglio maggiore. Fra le possibili opzioni, ad esempio:

-b <bits>
consente di specificare il numero di bit per la chiave privata nel range [768 - 2048] (di default 2048 bit)
-t
permette di indicare il tipo di chiave (RSA, DSA, ECDSA, ed25519)

È anche importante osservare che gli effetti così ottenuti si estendono anche al protocollo SFTP (Secure File Transfert Protocol) e al comando SCP (Secure Copy. Questo deriva dal fatto che sia SFTP, sia SCP, anch'essi inclusi nello stesso pacchetto OpenSSH, sfruttano SSH per implementare un servizio FTP sicuro l'uno, e la copia di file fra host remoti l'altro:
$ sftp <remote_user_name>@<remote_host>[:<port>]
$ scp <remote_user_name>@<remote_host>:<remote_destination_path>

Approfondimenti

Crittografia simmetrica
Crittografia asimmetrica
Funzione crittografica di hash
MD5
Firma digitale
Certificato digitale
Scambio di chiavi Diffie-Hellman
ssh-keygen - Linux man page

Commenti

Post popolari in questo blog

Introduzione alle reti 3 - Switch tecnologies

In questa sezione verranno esaminate le Virtual LAN, prima espressione della tecnologia LAN Switching.    Virtual Local Area Network (VLAN) Come già detto, uno dei punti di forza di uno switch risiede nella possibilità di creare sotto-reti a basso costo. Le VLAN ( Virtual Local Area Network ) , in particolare,  rappresentano la risposta a quelle situazioni nelle quali, pur non disponendo di grandi risorse, si renda comunque necessario tener distinti due o più ambiti della stessa rete, o, come è usuale dire, suddividere in più parti un dominio di broadcast.  L'esempio tipico è quello di una (piccola) impresa che abbia necessità di tener separati sulla rete i propri device in base alle attività produttive. La rete potrebbe allora pensarsi composta di tante VLAN quante sono le attività aziendali, ciascuna VLAN potendo contenere al proprio interno l'hw destinato ad ogni specifica attività. Dal punto di vista sistemistico, una  VLAN  è costituita da un sottoinsiem

Switch Commands - istruzioni Cisco HP Extreme "in a nutshell"

Indirizzamento IP

Obiettivo di questo articolo, senza pretesa di esaurire l'argomento, è quello di presentare in modo chiaro e comprensibile un argomento alle volte ostico: l'indirizzamento IP.  Questo, fra l'altro, consentirà di affrontare, anche agli utenti meno esperti, operazioni semplici quali   la configurazione di una scheda di rete con maggiore consapevolezza. Gli indirizzi IP Come noto, con IP  ci si riferisce ad uno dei protocolli di comunicazione di rete più affermati nel mondo delle telecomunicazioni:  Internet Protocol .   Un indirizzo IP è, in particolare, un codice binario che identifica univocamente un dispositivo di rete (una scheda ethernet, la porta di uno switch o di un router, etc.) all'interno di una rete di computer.  Di primaria importanza, nell'ambito dell'indirizzamento, è la lunghezza degli indirizzi, ovvero il numero di bit utilizzati per rappresentare un indirizzo di rete. Questo, evidentemente, perché con n bit sarà possibile ind