Attacchi side-channel: quando basta ascoltare l’hardware
La diffusione capillare dei computer nelle società moderne è oramai un concetto a cui siamo abituati. Siamo però meno abituati a pensare a quanto la crittografia accompagni i dispositivi che utilizziamo tutti i giorni.
Quando apriamo la macchina con delle chiavi wireless, quando effettuiamo un pagamento elettronico o quando inseriamo una tessera dopo aver acquistato un decoder per la televisione, interagiamo con un circuito elettrico che svolge un calcolo di tipo crittografico per noi.
Proprio su questi dispositivi è nata una delle più bizzarre e particolari categorie di attacchi informatici: gli attacchi side-channel.
Facciamo ora un esempio che ci permetterà di capire meglio il contesto in cui questi attacchi hanno luogo. Pensiamo a quando apriamo la nostra auto con il telecomando, cosa accade realmente?
Nel migliore degli scenari (purtroppo non sempre) è coinvolto un algoritmo di crittografia: la chiave, infatti, dovrebbe mandare un messaggio “apri” univoco alla nostra auto.
In caso di messaggio non cifrato, un malintenzionato potrebbe intercettare l’invio del segnale e clonare così le nostre chiavi; se invece il nostro dispositivo è in grado di cifrare il messaggio, una volta che premiamo il tasto “apri”, il segnale cifrato viene inviato alla macchina che lo decifra consentendo l’apertura dell’auto.
Cifrare un segnale vuol dire renderlo illeggibile, e quindi inutilizzabile, nonostante la possibilità che sia intercettato.
Un computer che cifra un messaggio lo rende ineleggibile eseguendo un complesso calcolo matematico che dipende da una chiave, che sarà poi riutilizzata in fase di decifratura per far tornare leggibile il messaggio. Ovviamente, è garantito il fatto che possedendo il messaggio cifrato non sia possibile né risalire alla chiave né tantomeno al messaggio reale. Nel caso delle chiavi della macchina, la chiave crittografica è salvata nella memoria elettronica del dispositivo e dell’auto.
Un processo simile viene utilizzato anche ogni volta che facciamo un pagamento utilizzando una carta di credito o di debito: senza andare ad approfondire il meccanismo, ci basta sapere che, in quel caso, la chiave è salvata sul chip, solitamente di colore dorato, che poi eseguirà il calcolo crittografico.
A questo punto è chiaro che la sicurezza di questi dispositivi si basa sulla segretezza della chiave che, ovviamente, essendo salvata elettronicamente, non è facile da recuperare. Tutto quello che noi possiamo rilevare sono solo i messaggi cifrati emessi quando questi dispositivi sono utilizzati.
Proprio in questo scenario nascono gli attacchi side-channel che si limitano ad “ascoltare” questi circuiti mentre lavorano.
Attacchi side-channel
Possiamo definire side-channel quella categoria di attacchi che si basano sulle informazioni ottenute dall’implementazione di uno schema di crittografia, anziché sulle sue debolezze matematiche. Prendiamo ad esempio un processore che sta eseguendo un certo algoritmo di crittografia: esso riceve dei dati in input, fa una serie di calcoli e, alla fine, restituisce un risultato. Per fare questo impiegherà un certo tempo e andrà a consumare una certa potenza elettrica.
Ora immaginiamo di utilizzare lo stesso algoritmo sulla stessa macchina ma con dei dati in input diversi. Il tempo impiegato e la potenza consumata sarà la stessa? In condizioni normali la risposta è no.
A questo punto, supponendo che il tempo e la potenza consumata sono univoci per dato di input, possiamo dedurre che, misurando questi dati, sia possibile ricavare il dato di partenza.
Tempo, potenza consumata, emissione elettromagnetica e persino il suono che emette un processore, uniti a delle analisi di tipo statistico, sono informazioni che gli attacchi side-channel possono sfruttare per risalire ai dati che un algoritmo sta processando. Quando si parla di crittografia per dati in input si intendono ovviamente le chiavi crittografiche, che devono rimanere segrete.
Semplice esempio
Per capire come sia possibile fare ciò prendiamo un semplice esempio.
Ipotizziamo un circuito che esegue una cifratura utilizzando RSA (uno degli schemi di cifratura più usati), come nel caso delle carte di credito.
Una chiave privata RSA è solitamente composta da 1024 o 2048 bit, cioè “cifre” che possono assumere valore 0 o 1. In condizioni normali, quando viene eseguita una cifratura di RSA vengono eseguiti diversi calcoli matematici, considerando un bit della chiave alla volta. La particolarità è che i calcoli eseguiti sono differenti a seconda che il singolo bit sia 1 o 0. Ora, supponendo di poter misurare la potenza consumata o l’emissione elettromagnetica e di poter osservare la traccia su un oscilloscopio, vedremmo qualcosa di simile all’immagine sottostante.
Come si può osservare a occhio nudo, se il bit della chiave è a 1 l’algoritmo esegue le funzioni S (Square) e M (Multiply), se il bit è a 0 esegue solo S.
Eseguendo un codice diverso si ha una notevole differenza della potenza consumata che è visibile sulla traccia e, di conseguenza, è possibile andare a ricostruire tutta la chiave segreta.
Quindi, ipoteticamente, basterebbe modificare uno strumento di pagamento elettronico in modo che possa misurare la potenza consumata per poter effettivamente clonare una carta di credito (senza ovviamente considerare eventuali PIN di sicurezza). L’esempio appena fatto, anche se molto semplice, descrive l’essenza di un attacco side channel.
Ovviamente la situazione reale è ben più complessa di quanto appena descritto, ma è anche vero che, ad oggi, alle misure ottenibili dagli strumenti vengono affiancati modelli e calcoli statistici che permettono, in quasi tutti i casi e con tutti gli schemi di cifratura, di ottenere le chiavi private.
Remediation
Per far fronte a questi attacchi la cosa migliore consiste nell’implementare algoritmi di crittografia prestando attenzione al codice e per poter resistere agli attacchi basati sul tempo è necessario creare algoritmi la cui esecuzione sia indipendente dai dati in input.
Questi ultimi vengono chiamati algoritmi a tempo costante e vanno creati usando delle particolari tecniche di coding che spesso richiedono un grande sforzo da parte dei programmatori. La grande difficoltà, inoltre, è mantenere un buon livello di efficienza.
Contro gli attacchi che si basano sul consumo di potenza, come è ovvio pensare, bisogna programmare algoritmi il cui consumo di risorse sia indipendente dai dati in input. Per fare questo esistono delle tecniche chiamate masking. Ci sono vari modi per mascherare il consumo delle varie operazioni e, spesso, questi stessi portano ad un peggioramento dell’efficienza dell’algoritmo. A scopo esemplificativo, di seguito, viene riportata la più semplice ma efficace tecnica di masking.
Questa tecnica si basa sul mischiare i dati in input con del materiale randomico: effettuare i calcoli e, prima di produrre il risultato, eliminare i dati randomici. In questo modo la potenza consumata sarà sempre casuale perché lo saranno anche i dati su cui lavora l’algoritmo.
Una domanda che viene spontanea è: ma è davvero possibile rimuovere i dati randomici alla fine del calcolo? La risposta è sì, ma la tecnica utilizzata dipende per singolo caso. Spesso, in alcuni tipi di hardware è complesso creare dei dati casuali: in quei casi esistono altre tecniche per portare ad un consumo di potenza casuale.
L’insieme di implementazione a tempo costante e tecniche di masking permettono una buona o, in alcuni casi, perfetta protezione contro gli attacchi side-channel. Il problema, però, è che queste remediation vanno applicate in fase di sviluppo e di design matematico dell’algoritmo e, oltre a richiedere delle competenze molto specifiche da parte dei programmatori, è necessario applicarle senza andare a sacrificare troppo le performance.