Abbiamo il grande tema e problema della generazione di dati random. Nel mondo informatico moderno che cosa vuol dire andare ad avere dati random? Nell’ambito della crittografia ha interesse particolare. In crittografia è connesso al fatto di non predicibilità, oltre che questione statistica. Questa è estremamente importante. Partiamo da una assunzione: noi progettiamo software e i computer sono per natura deterministici. La parte di non predicibilità la vogliamo prendere dal mondo reale, tipicamente visivo e fisico. Sul mondo fisico però abbiamo alcuni eventi che sono davvero random e altri che sono decisamente più predicibili. Noi cerchiamo di collegare il computer ad un mondo fisico che è fatto in questa maniera, quindi elementi random o elementi difficili da prevedere. Un sistema informatico in un ambiente completamente software non potrebbe essere mai random davvero. Nella crittografia la misura di quanto è random un evento la misuriamo con entropia. Questa definisce il numero di possibilità e combinazioni in cui ci potremmo trovare ad avere a che fare. In particolare dobbiamo distinguere numeri random di chiavi crittografiche e numeri davvero random. Sappiamo che una chiave crittografica sicura è sicura se ogni bit ha probabilità di scelta 50% sui ogni singolo bit. L’entropia con dimensione 128 bit è definita come entropia di 128 bit. Attenzione che potremmo avere una chiave random che però è scelta da un algoritmo deterministico che parte da un singolo bit, questo ci porta ad avere un livello di entropia di un singolo bit. Le password non posso assumerla per random davvero, c’è sempre un certo tipo di struttura. Questo vale anche per i pin e qui per altro ho ancora meno possibilità di scelta perché tratto solamente i numeri. L’idea di questa lezione sarebbe andare a vedere come generare chiave crittografica che sia sicura e quindi che ci sia sempre la questioni dei bit random 50%.
Il nostro sistema operativo ha accesso a diverse periferiche hardware reali: tastiere, mouse, interrupt che arrivano da diverse periferiche. Oltre a queste oggi abbiamo componenti hardware: TRNG true random number generator. Di fatto solo device fisici che internamente sfruttano quei processi fisici che accennavo prima. Ci sono dei fenomeni legati a correnti passive di componenti elettronici o altre questioni elettriche che possiamo andare a sfruttare per andare ad ottenere dati random: https://www.intel.com/content/www/us/en/developer/articles/guide/intel-digital-random-number-generator-drng-software-implementation-guide.html
In passato si usavano delle chiavette che erano preposte a questo tipo di attività. Questi dispositivi dedicati sono chiamati fonti di rumore. Nei sistemi operativi moderni queste operazioni vengono processate senza andare mai ad usare una singola fonte. A noi non interessa la specifica fonte die dati random quanto che siano credibili. Il SO mixa tante fonti e poi da un flusso di dati che possiamo assumere come effettivamente random. internamente al sistema ho un’area di memoria che preserva una certa quantità di dati random, che possono essere andati ad usare in qualsiasi momento. Storicamente soprattutto nei sistemi hardware non dotati di TRNG abbiamo pochi dati random a disposizione e cala tanto meno andiamo a interagire con il sistema. Si è cercato di avere un insieme di dati random, ma viene anche fornito uno pseudo random number generator a livello di kernel. Cioè il kernel ha un generatore pseudo random per andare a usare valori pseudo random, un po’ come se fosse uno stream cipher che parte da una chiave piccola per andare a generare una chiave molto grande. A seconda dei contesti in genere si usa sempre roba pseudo random di base. Si va a usare Kernel PRNG perché si pensa possa essere più sicuro, perché magari se ho dati random generati da CPU ma non sono sicuro che sia stato manomesso è un casino. Diciamo che alla fine potrebbe essere molto più sicuro.

Nella modellazione di attacchi nel mondo reale troviamo attaccanti che si collegano ad un certo istante di tempo. Se un attaccante accede al momento di output di dati pseudo random possiamo identificare due garanzie:
C’è stata una lette di gestione di dati pseudo random a livello di kernel e a livello di spazio utente. C’è una vulnerabilità del 2008 legata al fatto che fino ad un certo periodo il software di generazione pseudo random: openssl era re implementato da zero a livello di libreria stessa. Openssl aveva un suo generatore pseudo random. Il problema è che: questi spesso hanno portato ad avere problemi e fragilità, vulnerabilità per cui ad oggi è meglio che ci pensi sempre il kernel a fornire i dati random. Openssl prendeva pochi bit e generava grandi chiavi! Ma in realtà il numero di bit random era piccolissimo! Qui qualcuno facendo un analisi ad ampio spettro ha scoperto che c’erano tantissime chiavi duplicate. Il numero di chiavi differenti erano davvero poche. Questo era dovuto ad una vulnerabilità interna al generatore pseudo random di openssl. Visto che ciascuna libreria a livello utente ognuna faccia errori, è meglio andare direttamente a livello di kernel. prima si assumeva che il kernel era una merda. Abbiamo anche una considerazione da fare rispetto alle fork: questa copia tutto quanto lo stato del processo ed una vulnerabilità nota è che due processi forkati dallo stesso processo generano dati pseudorandom uguali perché internamente si parte dallo stesso stato per generare dati pseudo random. Ci si raccomanda di ri-aggiornare lo stato del generatore pseudorandom non appena fai una fork altrimenti stai generando dati pseudorandom uguale. Se usiamo un generatore a livello di kernel non abbiamo la fork e non possiamo avere questo tipo di problema. Questa problematica l’abbiamo trovata anche in altri contesti come quello delle virtual machine. Si osservava che snapshot di macchine virtuali clonati e respwnati avessero la generazione di dati pseudo random perfettamente identici. Si notava in macchine virtuali che appena avviate certe macchine virtuali sembrava di avere chiavi openssl tutte quante uguali. Ad oggi il sistema sa del problema e ogni macchine virtuali viene re-inizializzato con nuovi dati random reali.
Un altro entropia è la bassa entropia nelle prime fasi di un sistema. Magari un sistema si avvia per la prima volta e non ha dati random, perché il sistema magari è vergine e quindi non ha ancora abbastanza dati realmente random. A questo punto potrebbe convenire andare ad usare qualche software, come fonte esterna che ci vengono in soccorso.
In python abbiamo un bellissimo modulo che si chiama numb, … in quasi tutti i linguaggi abbiamo un problema di randomicità. Pensa solamente alla libreria random in python che non va bene per la sicurezza. Per usarla in python sarebbe meglio usare il package os con solamente urandom
from os import urandom
Questo urandom è una funzione che va ad accedere a generatori pseudorandom del sistema operativo. In python se voi farti dati radnom non andare su random ma vai su urandom del tuo os. Abbiamo anche una periferica random (/dev/random) che sono dati effettivamente random prima di essere dati ad un inizializzatore pseudo random. L’unica cosa è che random è considerata una fonte bloccante, per cui se finisco i dati devo aspettare di averne altri per tornare a funzionare. /Dev/urandom invece ti da sempre qualcosa. Nella realtà questa situazione si trova un sacco di informazioni e opinioni in rete. Negli ultimi dieci anni a questa parte comunque ci sono state un sacco di modifiche e potrei trovare una o l’altra implementazione davvero a seconda dei singoli hardware e dell’user space.
In python system randoms in base al sistema operativo posso andare ad python il cui interprete cerca di capire il sistema migliore. Tendenzialmente sarebbe bene usare questo, perché astrae per il programmatore il sistema operativo da andare ad usare.