Time-based One-time Password: come funziona la TOTP?
Gli utenti della rete devono spesso inserire password, ad esempio per accedere a una piattaforma social, effettuare acquisti online o usare l’online banking. Le password servono a proteggere i dati sensibili da accessi indesiderati. Nell’utilizzarle spesso, molti utenti trascurano un aspetto importante: le password deboli possono essere craccate dai professionisti nel giro di pochi secondi. Altri invece non custodiscono con cura le proprie password, offrendo una porta d’accesso ai criminali informatici. Non sono poi da sottovalutare le vulnerabilità dei servizi a cui l’utente accede: se le password non vengono custodite al sicuro, i dati di migliaia di utenti sono in pericolo.
Una possibilità per ridurre tale rischio è l’autenticazione a due fattori o l’autenticazione multi-fattore. Invece di usare un’unica password, è previsto l’inserimento di almeno un’altra chiave di autenticazione. L’utente riceve tale password sullo smartphone o attraverso un token hardware, utilizzando un fattore aggiuntivo unico e valido solo per poco tempo: così viene generata una cosiddetta Time-based One-time Password. Ecco come funziona.
A cosa serve una TOTP?
Le password abituali, quelle che forse scegliete anche voi, hanno uno svantaggio: se qualcun altro le conosce, la vostra sicurezza non è più garantita. Una soluzione sarebbe quella di cambiarle spesso, ma anche gli utenti esemplari non lo fanno di certo ogni ora. Ecco che allora viene in aiuto la TOTP: una password valida solo per un breve lasso di tempo dopo il quale scade. Nel 2011 l’Internet Engineering Task Force (IETF) ha pubblicato l’algoritmo della Time-based One-time Password nell’RFC 6238 per poter garantire più sicurezza su Internet.
Le password monouso sono particolarmente popolari nell’ambito dell’autenticazione multi-fattore. Gli utenti utilizzano la propria password personale per l’accesso al servizio online, ma in aggiunta viene generata una password a tempo per quello specifico processo di accesso. L’utente riceve tale password tramite app o attraverso un dispositivo predisposto (token).
La password scade nel momento in cui viene utilizzata una volta o se non viene utilizzata per un determinato periodo di tempo. Per i criminali quindi sarà molto difficile scoprire questo secondo fattore: anche se conoscessero la password avrebbero infatti poche possibilità di scoprire anche la TOTP, ovvero non avrebbero il tempo materiale per craccarla.
Come funziona l’algoritmo della Time-based One-time Password?
La base della TOTP è una funzione hash, ovvero un processo crittografico. Da una password segreta e una marcatura temporale viene generata una sequenza di segni cifrata. La password è conosciuta dall’utente e dal server. L’indicazione temporale è rappresentata in Tempo Unix.
Il Tempo Unix è un valore in secondi calcolato rispetto al 1° gennaio 1970.
La TOTP è una versione più sviluppata della HOTP, che sta per “HMAC-based One-time Password”. Anche la TOTP si basa sul metodo HMAC e sull’operazione hash. Sia il dispositivo dell’utente che il server generano un valore hash da una password segreta in combinazione con numeratore. Entrambi i valori sono identici, perciò l’autenticazione funziona.
La stessa funzione hash non è fissa: si accede ad esempio allo SHA-1 (o a Google Authenticator), che genera un valore hash con una lunghezza di 160 bit. Per semplificare le cose questo valore viene abbreviato tramite una funzione di compressione. Alla fine si ha un numero a sei cifre che l’utente può inserire facilmente per accedere al servizio online.
La password segreta è ancorata al token nel dispositivo e spesso lo stesso utente non lo sa. Nel caso in cui non fosse così, la SecretKey deve essere conservata in un luogo sicuro, meglio se offline ed eventualmente anche stampata e conservata in sicurezza. Se si perde questa password non è più possibile accedere al servizio.
L’HOTP si basa su un contatore per la seconda parte della funzione, separando il server e l’utente l’uno dall’altro. Il problema è che la password generata è valida fin quando non viene utilizzata. La TOTP ha invece una validità limitata: il suo codice può essere utilizzato solo entro un lasso di tempo stabilito. Come funziona?
Tre sono le formule importanti per l’algoritmo della Time-based-One-time Password:
TOTP = HOTP(SecretKey,CurrentTime)
Questa facile formula stabilisce solamente che la TOTP è un processo HOTP con due parametri, la SecretKey e il CurrentTime.
- SecretKey: è una password generata casualmente, conosciuta sia al server che al client
- CurrentTime: orario attuale in Tempo Unix
L’indicazione temporale cambia ogni secondo e tale tempo non basta per trasmettere il codice all’applicazione. Un secondo più tardi la TOTP non sarebbe più valida, in quanto il server ha già generato un nuovo valore hash. Per questo si ricorre a un’altra formula:
CurrentTime = floor((unixtime(now) – unixtime(T0))/T1)
Viene definito quindi il parametro CurrentTime:
- unixtime(now): orario attuale in Tempo Unix
- unixtime(T0): Tempo Unix al momento T0, si calcola nella maggior parte dei casi partendo dalla mezzanotte del 1/1/1970 (= 0)
- T1: l’intervallo di tempo nel quale la TOTP deve essere valida, solitamente 30 secondi
- floor: funzione di arrotondamento, per arrotondare il valore calcolato ad un numero intero
Teoricamente può essere scelto anche un altro valore per T0 che non sia 0. La cosa importante è che client e server scelgano lo stesso valore.
Il risultato cambia a intervalli a causa di divisione e arrotondamento.
Infine il valore hash generato viene abbreviato per essere più user-friendly:
Result = TOTPmod10d
Il calcolo Modulo genera una somma di controllo:
- mod 10: Modulo con divisore 10
- d: numero di cifre che la TOTP dovrebbe avere
Si potenzia quindi la base 10 con quelle cifre che il codice dovrebbe avere, si divide la TOTP con questo valore e si estrae il resto.
Calcolo della TOTP in un esempio
Supponiamo che si voglia generare una TOTP con una validità di 30 secondi. È possibile già calcolare il CurrentTime e capire anche come si garantisce la durata della validità. Supponiamo che l’unixtime(now) sia 1548322860, il 24/01/2019 alle ore 10:41. Dividendo questo valore diviso 30 il risultato è 51.610.762. Essendo già un numero intero, non bisogna fare l’arrotondamento del risultato. Se si imposta l’orario 15 secondi più tardi (quindi 1.548.322.875), dopo la divisione si ottiene il risultato di 51.610.762,5, che arrotondato diventa 51.610.762. Quindi il CurrentTime rimane invariato. Nella seguente tabella si può notare come il valore cambia solo posticipando di 30 secondi:
unixtime(now) | unixtime(now)/30 | floor(unixtime(now)/30) |
---|---|---|
1548322857 | 51610761,9000 | 51610761 |
1548322858 | 51610761,9333 | 51610761 |
1548322859 | 51610761,9667 | 51610761 |
1548322860 | 51610762,0000 | 51610762 |
1548322861 | 51610762,0333 | 51610762 |
1548322862 | 51610762,0667 | 51610762 |
1548322863 | 51610762,1000 | 51610762 |
1548322864 | 51610762,1333 | 51610762 |
1548322865 | 51610762,1667 | 51610762 |
1548322866 | 51610762,2000 | 51610762 |
1548322867 | 51610762,2333 | 51610762 |
1548322868 | 51610762,2667 | 51610762 |
1548322869 | 51610762,3000 | 51610762 |
1548322870 | 51610762,3333 | 51610762 |
1548322871 | 51610762,3667 | 51610762 |
1548322872 | 51610762,4000 | 51610762 |
1548322873 | 51610762,4333 | 51610762 |
1548322874 | 51610762,4667 | 51610762 |
1548322875 | 51610762,5000 | 51610762 |
1548322876 | 51610762,5333 | 51610762 |
1548322877 | 51610762,5667 | 51610762 |
1548322878 | 51610762,6000 | 51610762 |
1548322879 | 51610762,6333 | 51610762 |
1548322880 | 51610762,6667 | 51610762 |
1548322881 | 51610762,7000 | 51610762 |
1548322882 | 51610762,7333 | 51610762 |
1548322883 | 51610762,7667 | 51610762 |
1548322884 | 51610762,8000 | 51610762 |
1548322885 | 51610762,8333 | 51610762 |
1548322886 | 51610762,8667 | 51610762 |
1548322887 | 51610762,9000 | 51610762 |
1548322888 | 51610762,9333 | 51610762 |
1548322889 | 51610762,9667 | 51610762 |
1548322890 | 51610763,0000 | 51610763 |
1548322891 | 51610763,0333 | 51610763 |
È quindi stato stabilito il CurrentTime (51610762). La SecretKey è creata da un generatore di password: >cHSB_UQ#O5m;~b
L’HMAC genera insieme allo SHA-1 un valore hash da password e orario (nella scrittura esadecimale): c0 62 37 94 dd 37 7a 3a f0 91 22 08 1f 21 6f 9b 17 4b 17 45. Questo valore lungo 160 bit cioè 20 byte viene ridotto a 31 bit con la cosiddetta Dynamic Truncation. Per farlo vengono presi in considerazione gli ultimi 4 bit, cioè il numero 0x5, che anche nella scrittura decimale viene scritto 5. Questo rappresenta il valore offset della Dynamic Truncation e significa che dal byte con l’indice 5 (iniziando a contare da sinistra con 0) vengono estratti quattro byte: 0x377a3af0. In questo caso il valore inizia già con un bit che sta su 0. Se però non dovesse essere così, si cambia. Il valore da 31 bit sarà: 0x377a3af0, cioè 930757360.
Per ridurre il codice da nove a sei cifre si utilizza un’operazione Modulo e si aggiungono all’occorrenza degli zeri sulla sinistra: 930757360 mod (106) = 757360. Questa è quindi la TOTP, valida 30 secondi. In combinazione con un altro fattore si ottiene un processo di accesso abbastanza sicuro.