Sei sulla pagina 1di 15

FUNZIONI HASH 4

Funzioni non invertibili, dato un input di dimensione arbitraria, restituisce un’impronta digitale di
lunghezza predefinita strettamente correlata con i dati in ingresso. Il risultato, di una funzione hash,
trad. mix, è il digest, la cui traduzione è digerire e spiega perfettamente quello che accade.
Per il nostro scopo saranno utilizzate le funzioni hash crittografiche, un sottoinsieme, alle quali
corrispondono proprietà più forti.

1- PROPRIETA’
A- Dato un messaggio 𝑥, il suo digest ℎ(𝑥) può essere calcolato molto
velocemente. I possibili messaggi sono teoricamente infiniti, la lunghezza
del digest è minore di quella del messaggio, quindi funzione suriettiva.

B- Dato un digest 𝑦, è computazionalmente


intrattabile trovare un messaggio 𝑥 tale che
ℎ(𝑥) = 𝑦. Questo significa che ℎ(𝑥) è una
funzione unidirezionale, one-way function, cioè
resistente all’inversione, pre-image resistence.

C- Fissato 𝑥1 , è computazionalmente intrattabile


trovare 𝑥2 ≠ 𝑥1 ∶ ℎ(𝑥2 ) = ℎ(𝑥1 ). In tal caso la
funzione ℎ è debolmente resistente alle collisioni,
second pre-image resistance.

D- È computazionalmente intrattabile trovare due


messaggi diversi, 𝑥1 e 𝑥2 ∶ ℎ(𝑥2 ) = ℎ(𝑥1 ).
Allora, ℎ(𝑥) è fortemente resistente alle
collisioni, collision resistance.

2- ORACOLO CASUALE
Introdotto per dare un’idea di funzione hash ideale.
- Chiunque può dare un input all’oracolo, che produce
un output di lunghezza fissa.
- Se l’input è già stato fornito, l’oracolo fornisce in
output sempre lo stesso valore.
- Se l’input non è mai stato fornito, l’oracolo restituisce
un valore scelto in modo casuale.
L’implementazione è il problema, non tanto per la casualità, poiché in commercio ci sono
generatori pseudo-casuali validi, il vero problema è ricordarsi coppie input-output, in primis, ma
come conseguenza si ha che all’aumentare di queste coppie si ha una progressiva perdita di
1
velocità perché l’algoritmo deve passare a rassegna queste coppie finché o non trova quella
corrispondente oppure arrivando in fondo ne genera e memorizza una nuova.
L’unica soluzione è passare dal casuale al deterministico, cioè memorizzando soltanto
l’algoritmo che dato un input fornisca un output come se fosse estratto a caso, per questo motivo
si è pieni di funzioni hash.

3- FUNZIONI HASH NOTE


A- Secure Hash Algorithm, SHA
SHA-0, 1993.
SHA-1, progettato da NSA e standardizzato dal NIST nel 1995.
SHA-2, famiglia che supporta lunghezze multiple (SHA-224, SHA-256, SHA-384 e SHA-
512), progettato da NSA e standardizzato dal NIST nel 2001.
SHA-3, basato sul candidato Keccak, standardizzato dal NIST nel 2015.

B- Message Digest, MD
MD4, 1990
MD5, 1992, progettato da Ron Rivest.

C- HAVAL-128, 1992

D- RIPEMD, l’acronimo è qualcosa d’impossibile da ricordare, 1995 in poi.


Nacque come alternativa europea ad altre funzioni hash di provenienza americana come
MD4 e MD5.

Per molte di queste, sono state evidenziate debolezze, o possibili collisioni di facile
individuazione, quando ciò avviene, il sistema non è più sicuro da utilizzare.
La caratteristica più importante è la dimensione in bit del digest, oggigiorno 128 bit non bastano
più, almeno 256.

Tutte le funzioni hash lavorano per round dove si concatenano più operazioni a livello macchina
(and, or, xor, rotazioni di vettori, permutazioni, …), per rendere il tutto più veloce e più
ingarbugliato l’output, aumento della proprietà di diffusione.

2
4- ESEMPI DI FUNZIONI NON-QUASI HASH
❖ ESEMPIO DI FUNZIONE NON HASH
Presa ℎ(𝑚) = 𝑚 (𝑚𝑜𝑑 𝑛) una funzione hash, questa mappa un messaggio di lunghezza
arbitraria 𝑚, in un intero compreso tra 0 e (𝑛 − 1).
Soddisfatta le suriettività ma:
- Dato 𝑦, e posto 𝑚 = 𝑦, risulta ℎ(𝑚) = 𝑦.
- Se 𝑚1 ≡ 𝑚2 (𝑚𝑜𝑑 𝑛), allora ℎ(𝑚1 ) = ℎ(𝑚2 ).

❖ ESEMPIO DI FUNZIONE QUASI HASH


𝑝−1
Preso un primo grande 𝑝, tale che anche 𝑞 = sia primo, e due radici primitive per 𝑝: 𝛼,
2
𝛽. Per la loro definizione, esiste un 𝑎 ∶ 𝛼 𝑎 ≡ 𝛽.

Definisco la funzione suriettiva così, prendo gli


interi modulo 𝑞 2 e li mappo su quelli modulo 𝑝,
𝑝 𝑝2
ciò funziona perché 𝑞 ≅ → 𝑞2 ≅ , per cui
2 4
𝑝2
essendo 𝑝 molto grande, ≫ 𝑝.
4

Si scrive il messaggio come, 𝑚 = 𝑥0 + 𝑥1 𝑞 e si calcola il digest ℎ(𝑚) = 𝛼 𝑥0 𝛽 𝑥1 (𝑚𝑜𝑑 𝑝).


Si può dimostrare che ℎ(𝑚) possiede una bella proprietà:
Proposizione
Se si conoscono due messaggi (𝑚, 𝑚′ ) che collidono, cioè che ℎ(𝑚) = ℎ(𝑚′ ), allora si può
determinare facilmente il logaritmo discreto 𝐿𝛼 (𝛽) = 𝑎.
Cioè se si trovano facilmente messaggi che collidono, si risolvono facilmente logaritmi
discreti. Quest’ultimo invece è noto essere un problema computazionalmente difficile,
pertanto non è possibile trovare facilmente tali messaggi. Il problema, lentezza assurda, per
calcolare un hash tocca fare ℎ(𝑚) = 𝛼 𝑥0 𝛽 𝑥1 (𝑚𝑜𝑑 𝑝).

3
❖ ESEMPIO DI FUNZIONE NON HASH
Il messaggio 𝑚, di lunghezza 𝐿, viene suddiviso in blocchi di 𝑛 bit ciascuno:
𝑚 = [𝑚11 , 𝑚12 , … , 𝑚1𝑛 , 𝑚21 , 𝑚22 , … , 𝑚2𝑛 , 𝑚𝑙1 , 𝑚𝑙2 , … , 𝑚𝑙𝑛 ]
Il digest è ottenuto calcolando lo XOR di tutti i bit alle stesse posizioni relative:

ℎ(𝑚) non ha i requisiti per essere una funzione hash, poiché è facile trovare due messaggi
che hanno lo stesso digest. Il modo con cui si limita questo problema è introdurre set di
operazioni elementari e svariati round di calcolo, prima di arrivare al digest.

5- FUNZIONE DI COMPRESSIONE UNIDIREZIONALE


Trasforma due input di lunghezza fissa in un output di lunghezza fissa, da
quest’ultimo è computazionalmente difficile ricavare gli-l’input.
Diverse dai normali algoritmi di compressione dati, che invece possono
essere invertiti esattamente, cioè senza perdita di dati, o
approssimativamente, con perdita.

6- FUNZIONI ITERATIVE O SCHEMA DI MERKLE-DAMGARD


Si spezza il messaggio in blocchi:
𝑀 = [𝑀1 , 𝑀2 , 𝑀3 , … ]

S’invoca iterativamente una funzione di


compressione unidirezionale 𝐹, che fa
evolvere uno stato rappresentato da un
Chaining Value (CV), l’ultimo
rappresenta il digest effettivo del processo.

IV, Initialization Vector.

Esempi di utilizzo: MD5, SHA-1, SHA-2, …

4
❖ PROBLEMI
1- MULTICOLLISIONI
La natura iterativa delle
funzioni hash ne riduce la
robustezza.
Due blocchi di input che
producono lo stesso CV
generano una collisione,
indipendente dai blocchi
successivi.

Supponiamo di trovare 𝑡 coppie di blocchi (𝑚𝑗 , 𝑚𝑗′ ) che producono lo stesso CV, ℎ𝑗
quindi la funzione di compressione 𝑓(ℎ𝑗 , 𝑚𝑗 ) = 𝑓(ℎ𝑗 , 𝑚𝑗′ ). Ne segue che tutte le 2𝑡
possibili combinazioni di tali coppie producono necessariamente lo stesso digest:

Esempio
Quanti messaggi posso
costruire che collidono tra di
loro in questo schema?
4:
[𝑚1 , 𝑚2 ]
[𝑚1′ , 𝑚2 ]
[𝑚1 , 𝑚2′ ]
[𝑚1′ , 𝑚2′ ]

5
2- ATTACCHI BASATI SU ESTENSIONE DEL MESSAGGIO
Tipo di attacchi secondo cui Eve usa ℎ(𝑚1 ) e la lunghezza di 𝑚1 per calcolare
ℎ(𝑚1 ||𝑚2 ), con 𝑚1 ||𝑚2 versione estesa di 𝑚1 , sostanzialmente dopo 𝑚1 è attaccato
𝑚2 , con quest’ultimo scelto da Eve, senza conoscere 𝑚1 .

Supponiamo che Eve conosca ℎ(𝑚1 ) = SHA-1(𝑚1 || 𝑝1 || 𝑙1 ), e conosca la lunghezza


totale 𝑙 di (𝑚1 || 𝑝1 || 𝑙1 ), dove:
- 𝑚1 , messaggio originale sconosciuto ad Eve;
- 𝑝1, lunghezza del padding;
- 𝑙1, lunghezza di 𝑚1 espressa con 64 bit.
Eve può calcolare ℎ(𝑚1 ||𝑚2 ) = SHA-1(𝑚1 || 𝑝1 || 𝑙1 || 𝑚2 || 𝑝2 || 𝑙2 ) dando in input
(𝑚2 || 𝑝2 || 𝑙 ′ ), con 𝑙 ′ = 𝑙2 + 𝑙, ad una istanza di SHA-1 che parta da un CV iniziale
coincidente con ℎ(𝑚1 ).

Se una funzione hash basata su Merkle-Damgard venisse utilizzata per autenticare un


messaggio tramite una costruzione del tipo ℎ(𝑚 || 𝑠), con:
- 𝑠, chiave segreta;
- Lunghezza di 𝑚 e 𝑠 note.
Un attaccante potrebbe includere informazioni aggiuntive alla fine di 𝑚 e produrre un
hash valido senza conoscere 𝑠.
Per utilizzare lo schema Merkle-Damgard, per garantire sia l’integrità che
l’autenticazione di messaggi, bisogna utilizzare costruzioni più robuste della semplice
concatenazione, come HMAC, Hash-based Message Authentication Code, per resistere
agli attaccanti basati su estensione del messaggio, sostanzialmente si eseguono due cicli
hash prima di spedire il messaggio. Questo risulta però una pezza al problema.

Questi due motivi, le principali cause che hanno portato l’abbandono dell’approccio
Merkle-Damgard a favore dell’algoritmo Keccak, facente uso SHA-3.

6
7- SHA-1
Il messaggio 𝑚 viene riempito con un 1 ed una serie di 0 affinché abbia lunghezza pari ad un
multiplo di 512, meno gli ultimi 64 bit che vengono riempiti con la rappresentazione binaria
della lunghezza del messaggio, poi suddiviso in un insieme di blocchi di lunghezza fissa, 512
bit:
𝑚 = [𝑚1 , 𝑚2 , 𝑚3 , … , 𝑚𝐿 ]
Data, una funzione di compressione, ℎ′ ed un valore iniziale, 𝑋0, non segreto poiché scritto
nello standard, l’output per ciascun blocco è calcolato come:
𝑋𝑗 = ℎ′ (𝑋𝑗−1 , 𝑚𝑗 ) con 0 < 𝑗 ≤ 𝐿, per cui il digest del messaggio coincide con 𝑋𝐿 .
Operazioni usate:

Viene definito il contatore di round, 𝑡 : 0 ≤ 𝑡 ≤ 79, quindi 80 round.

❖ INGREDIENTI

7
❖ FASI PRINCIPALI
1- Ogni blocco 𝑚𝑗 viene espanso da 512 a 2560 bit, sempre nell’ottica di aumentare la
diffusione, in questo modo:
- 𝑚𝑗 = [𝑊0 , 𝑊1 , … , 𝑊15 ], con 𝑊𝑖 blocco di 32 bit, perché i processori all’epoca di
SHA-1 lavoravano a 32 bit, oggi a 64.
- 𝑊𝑡 = (𝑊𝑡−3 ⊕ 𝑊𝑡−8 ⊕ 𝑊𝑡−14 ⊕ 𝑊𝑡−16 ) ← 1, per 𝑡 = 16, … ,79, blocchi inventati,
servono per mischiare meglio, mi fermo a 79 poiché ogni blocchetto lo userò dal
round 16 al 79, quelli primi li ho già.

2- La variabile di stato 𝑋 di 160 bit viene divisa in blocchi di 32 bit ciascuno:


𝑋 = [𝐴, 𝐵, 𝐶, 𝐷, 𝐸].

3- Per ogni blocco di input 𝑚𝑗 , essi vengono aggiornati tramite 80 round che utilizzano i
blocchi 𝑊0 , … , 𝑊79 ottenuti da 𝑚𝑗 .

4- Il valore iniziale è dato da:


𝐴 = 𝐻0
𝐵 = 𝐻1
𝐶 = 𝐻2
𝐷 = 𝐻3
𝐸 = 𝐻4

5- Per 𝑡 = 0, … ,79:
𝑇 = (𝐴 ← 5) + 𝑓𝑡 (𝐵, 𝐶, 𝐷) + 𝐸 + 𝑊𝑡 + 𝐾𝑡
𝐸=𝐷
𝐷=𝐶
𝐶 = (𝐵 ← 30)
𝐵=𝐴
𝐴=𝑇

6- L’output, ottenuto al termine degli 80 round, è l’aggiornamento dello stato iniziale:


𝐻0 = 𝐴 + 𝐻0
𝐻1 = 𝐵 + 𝐻1
𝐻2 = 𝐶 + 𝐻2
𝐻3 = 𝐷 + 𝐻3
𝐻4 = 𝐸 + 𝐻4

8
9
8- SHA-2
Per contrastare le criticità di SHA-1 senza stravolgere l’impalcatura, le modifiche apportate
sono:
- Introdotte due diverse funzioni di compressione:
𝑆𝐻𝐴 − {224, 256} ∶ 𝑛 = 256 = 8 𝑥 32 𝑒 𝑚 = 512 = 16 𝑥 32
𝑆𝐻𝐴 − {384, 512} ∶ 𝑛 = 512 = 8 𝑥 64 𝑒 𝑚 = 1024 = 16 𝑥 64
La prima comprime da 512 → 256 𝑏𝑖𝑡, la seconda da 1024 → 512 𝑏𝑖𝑡, quindi entrambe
1
con fattore di compressione , però la prima lavora su blocchi di 32 𝑏𝑖𝑡, la seconda lavora
2
su 64, entrambe riducono i blocchi di partenza da 16 → 8.
La prima funzione di compressione è utilizzata in SHA-256, quindi con un digest di
256 𝑏𝑖𝑡 o una sua versione troncata a 224 𝑏𝑖𝑡, SHA-224, mentre la seconda in SHA-512,
oppure la sua versione tronca, SHA-384.
- Espansione non lineare dei messaggi, grazie a percorsi di mescolamento dei dati più
robusti.
- Ancora basato su Merkle-Damgard.

9- SHA-3
Costruzione a spugna.

Due funzioni di stato inizializzate a


0:
- 𝑟 𝑏𝑖𝑡, funzione outer perché
s’interfaccia con l’esterno;
- 𝑐 𝑏𝑖𝑡, funzione inner perché
rimane interna al sistema, è il
parametro di sicurezza perché
evita i problemi riscontrati con l’approccio di Merkle-Damgard.

Due le fasi:
A- ASSORBIMENTO
L’input, a blocchi, viene sommato modulo due con la funzione di stato outer. Entra nella
funzione 𝑓, la quale non è più di compressione ma di permutazione a 𝑏 = 𝑟 + 𝑐 𝑏𝑖𝑡, dove ha
inizio l’incasinamento per cui un po’ della parte outer diventa inner e viceversa, e così via,
finché non finiscono i blocchi del messaggio di input. A questo punto la spugna è piena di
dati mescolati, suddivisi in 𝑟 + 𝑐 𝑏𝑖𝑡.

10
B- SPREMITURA
Serve a produrre il digest. Quest’ultimo non ha dimensione finita poiché ricostruito un po’
per volta a partire da pezzi presi dalla variabile di stato outer, esempio di Extendable
Output Function, XOF. Il meccanismo non termina i dati una volta ottenuto il primo
digest, si potrebbe continuare, un po’ come rifare il caffè riutilizzando la stessa cialda. Più
spremi, più hai lungo il digest.

❖ VANTAGGI RISPETTO A MERKLE-DAMGARD


- Operazioni più semplici, solo permutazioni e somme binarie.
- Parte dello stato, 𝑐 𝑏𝑖𝑡 ogni 𝑟, non viene restituito in output, il che impedisce attacchi
basati su estensione del messaggio.

- La lunghezza del messaggio può essere variata, implementando nativamente una XOF.

10- COSA FARCI CON LE FUNZIONI HASH CRITTOGRAFICHE


❖ INTEGRITA’ – AUTENTICAZIONE DEI DATI
Il digest ℎ(𝑚) viene inviato insieme al dato 𝑚 ∶ [𝑚, ℎ(𝑚)]. Il destinatario riceve una coppia
[𝑀, 𝐻] e controlla se 𝐻 = ℎ(𝑀), in tal caso può assumere che 𝑀 = 𝑚, ovvero che i dati
ricevuti siano integri.
Attenzione!! protegge solo da errori accidentali (interferenze, perdita di pacchetti, …) in
quanto il digest del messaggio non è più coerente con lo stesso, se ci dovesse essere un
attaccante man in the middle, non avrei alcuna protezione, perché potrebbe modificare il
messaggio, o parte di esso, e modificare anche il digest.

Ai fini della sola verifica d’integrità, un codice rivelatore d’errore, ad esempio il CRC32 che
è una funzione hash non crittografica svolge lo stesso compito di una crittografica.

❖ CIFRATURA
Usata analogamente ad un generatore di numeri pseudocasuali al fine di costruire una
funzione di cifratura. Si usa una modalità operativa analoga all’Output Feedback Mode,
OFM, per cifrari a blocchi. Praticamente, vengono generati tramite la funzione hash, dei bit
pseudo-casuali, che dipendono da una chiave segreta e che vengono sommati modulo due
con i bit del testo in chiaro, ottenendo quello cifrato. La stessa cosa viene fatta poi per
decifrare. Serve una chiave segreta 𝐾𝐴𝐵 pre-condivisa tra Alice e Bob.

Alice calcola il digest della chiave e ne considera il primo byte, 𝑥1 = 𝐿8 (ℎ(𝐾𝐴𝐵 )), questo è il
key stream utilizzato per cifrare una parte del testo in chiaro.
Il primo byte del testo in chiaro 𝑝1, viene poi cifrato come, 𝑐1 = 𝑝1 ⊕ 𝑥1 ; lo stile è sempre
quello del one-time pad, cioè preso un pezzo del messaggio in chiaro, uno di flusso pseudo-

11
casuale, sommati insieme modulo due, ottieni un pezzo del messaggio cifrato, in questo caso
però il flusso pseudo-casuale lo genero con una funzione hash crittografica.
Analogamente ad OFB, si usa la concatenazione per generare il byte successivo, usa per la
cifratura di 𝑝2 :

- 𝑥2 = 𝐿8 (ℎ(𝐾𝐴𝐵 || 𝑥1 ))
- 𝑐2 = 𝑝2 ⊕ 𝑥2 .
In generale,

𝑥𝑗 = 𝐿8 (ℎ(𝐾𝐴𝐵 || 𝑥𝑗−1 )) e 𝑐𝑗 = 𝑝𝑗 ⊕ 𝑥𝑗 .

Per evitare che due messaggi uguali vengono cifrati con lo stesso keystream, si usa 𝑥0 come
vettore di inizializzazione, generato casualmente da Alice e mandato in chiaro a Bob tale per
cui 𝑥1 = 𝐿8 (ℎ(𝐾𝐴𝐵 || 𝑥0 )).
Bob ha 𝐾𝐴𝐵 ed 𝑥0 e ricostruisce il messaggio in chiaro così:
𝑥1 = 𝐿8 (ℎ(𝐾𝐴𝐵 || 𝑥0 ))
𝑝1 = 𝑐1 ⊕ 𝑥1
𝑥2 = 𝐿8 (ℎ(𝐾𝐴𝐵 || 𝑥1 ))
𝑝2 = 𝑐2 ⊕ 𝑥2

11- PARADOSSO DEL COMPLEANNO


Risultato puramente statistico che risulta un problema per le funzioni hash a causa della loro
suriettività per cui due o più messaggi producono lo stesso digest, l’unica soluzione è rendere
l’insieme dei digest un po’ più grande in modo che la ricerca delle collisioni risulti
computazionalmente difficile.

❖ ESEMPI
- Scelta una persona in un gruppo di 23, qual è la probabilità che almeno un’altra
persona nel gruppo festeggi il compleanno nel suo stesso giorno?
1 22
1 − (1 − ) = 5.9%
365
- Dato un gruppo di 23 persone, qual è la probabilità che almeno due, qualsiasi, di essi
festeggino il compleanno lo stesso giorno?
1 2 22
1 − (1 − ) (1 − ) … (1 − ) = 50.7%
365 365 365

12
❖ APPLICATO ALLE FUNZIONI HASH
Cercare una collisione avendo fissato uno dei due messaggi collidenti è faticoso mentre
cercarne una coppia a caso è molto più facile, per questo nelle proprietà delle funzioni hash
crittografiche si è parlato di second pre-image resistance e collision resistance.

Generalizzazione del paradosso del compleanno


Dato un gruppo di 𝑁 elementi, con 𝑁 elevato, ed 𝑟 scelte casuali con ripetizione di
tali elementi, la probabilità che almeno una scelta venga effettuata due volte è circa:
𝑟2

1−𝑒 2𝑁

𝑟2
Se 2𝑁 = ln 2 → 𝑟 = 1.1774√𝑁 ≅ √𝑁, la probabilità che vi sia almeno una scelta
coincidente è del 50%.

Generalizzazione del paradosso del compleanno alle funzioni hash


Dato un gruppo di 𝑁 elementi, con 𝑁 grande, e due gruppi 𝑟 di scelte casuali con
ripetizione di tali elementi, la probabilità che almeno una scelta del primo gruppo
𝑟2
coincida con una del secondo è circa pari a (1 − 𝑒 −𝜆 ) con 𝜆 = .
𝑁

La probabilità che ci siano 𝑖 scelte coincidenti tra il primo gruppo ed il secondo è


𝜆𝑖 𝑒 −𝜆
invece circa pari a ( ).
𝑖!

Se 𝑟 è dell’ordine di √𝑁, allora la probabilità di avere almeno una scelta coincidente


è del 50% circa.
Ad esempio, se 𝑁 = 365 e 𝑟 = 30, la probabilità di avere almeno una coincidenza è
pari al 91.5%.

❖ ATTACCO DEL COMPLEANNO ALLE FUNZIONI HASH


- Sia 𝑓(𝑥) una funzione hash con digest lungo 𝐿 𝑏𝑖𝑡.
Se l’attaccante fissa 𝑥1 e cerca 𝑥2 ∶ 𝑓(𝑥1 ) = 𝑓(𝑥2 ), deve provare 2𝐿 valori per 𝑥2 , però
la probabilità che ne trovi almeno due è del 100%.
Se invece compila due liste:
𝐿
- La prima di ≅ √2𝐿 = 22 possibili valori per 𝑥1 ;
𝐿
- La seconda di ≅ √2𝐿 = 22 possibili valori di 𝑥2 .

E cerca entro tali liste due valori 𝑥1 , 𝑥2 ∶ 𝑓(𝑥1 ) = 𝑓(𝑥2 ) ha probabilità di successo di
circa il 50%, in tal caso l’attacco è considerato di successo. La probabilità di successo si
è dimezzata rispetto all’attacco a forza bruta ma anche il numero di prove da fare sono
state dimezzate e questo fa la differenza.
𝐿
Pertanto, la complessità dell’attacco ed il livello di sicurezza scende da 𝐿 𝑏𝑖𝑡 a 2 𝑏𝑖𝑡, per
questo motivo oggigiorno usiamo cifrari simmetrici con chiavi da 128 𝑏𝑖𝑡 ma funzioni
13
hash che tirano fuori digest di almeno 256 𝑏𝑖𝑡, questo perché un digest di 128 𝑏𝑖𝑡 non
basta più, troppo facile la ricerca di collisioni con il paradosso del compleanno.

- Se 𝑝 è un numero grande, si può calcolare il logaritmo discreto 𝐿𝛼 (𝛽), ovvero risolvere


𝛼 𝑥 = 𝛽 (𝑚𝑜𝑑 𝑝), con alta probabilità, tramite un attacco che sfrutta il paradosso del
compleanno.

- Si costruisce una lista contenente i valori 𝛼 𝑘 (𝑚𝑜𝑑 𝑝) per circa √𝑝 valori di 𝑘


scelti a caso.

- Si costruisce una lista contenente i valori 𝛽𝛼 −𝑙 (𝑚𝑜𝑑 𝑝) per circa √𝑝 valori di 𝑙


scelti a caso.
Se un elemento della prima lista coincide con uno della seconda:
𝛼 𝑘 ≡ 𝛽𝛼 −𝑙 ↔ 𝛼 𝑘+𝑙 ≡ 𝛽

Il modo con cui si corre ai ripari è facendo in modo che le due liste, che un possibile
attaccante possa creare, siano troppo lunghe per poter fare in un tempo ragionevole un
attacco.

12- HASH E FIRMA DIGITALE


Le primitive di firma digitale usate direttamente sul messaggio producono una firma lunga
almeno quanto il messaggio, ciò rende inutilizzabile per scopi pratici.
Una soluzione a questo problema consiste nel calcolare la firma digitale non sul messaggio ma
su un hash digest del messaggio, questo approccio prende il nome di hash-and-sign.

❖ PROCEDIMENTO
Si sceglie una funzione hash, ℎ e la si pubblica.
Alice calcola l’hash digest del messaggio, ℎ(𝑚), che è molto più corto di 𝑚 ed ha lunghezza
fissa, pertanto è più agevole da firmare.
Alice firma il digest e rende pubblica la coppia (𝑚, ℎ(𝑚)).
Bob calcola ℎ(𝑚) e ne verifica la firma.

14
Se Eve volesse usare la firma intercettata per un altro messaggio, 𝑚′ , servirebbe che
ℎ(𝑚′ ) = ℎ(𝑚). Serve quindi trovare una collisione della funzione hash, mentre se non si
fosse usata la funzione hash, il problema sarebbe molto più difficile da risolvere per Eve
perché si dovrebbe avere 𝑠𝑖𝑔(𝑚′ ) = 𝑠𝑖𝑔(𝑚) e questa cosa è vera soltanto se 𝑚′ = 𝑚.

❖ ATTACCO DEL COMPLEANNO


Supponiamo che Alice sia disponibile a firmare il digest lungo 128 𝑏𝑖𝑡 di un documento che
le viene sottoposto.
La probabilità che un altro documento abbia lo stesso digest è pari a 2−128, ovvero molto
bassa; pertanto, Alice si direbbe ragionevolmente sicura che la sua firma non possa essere
utilizzata per un altro documento.
In realtà Eve, nella scelta del messaggio legittimo da far firmare ad Alice non ne prende uno
a caso solo ma ne considera tanti che Alice è disposta a firmare
A questo punto, supponiamo che Eve riesca ad individuare 64 possibili modifiche da
apportare al documento di partenza senza che ne cambi il senso, ottenendo così 264
documenti diversi aventi lo stesso significato e ne memorizza i corrispondenti digest.
Allo stesso modo produce 264 documenti fraudolenti, tutti con lo stesso significato ma
formalmente differenti e ne calcola i digest.
Tale situazione è riconducibile al paradosso del compleanno per il caso di gruppo di 𝑟 = 264
elementi scelti tra 𝑁 = 2128 possibili.
Eve fa firmare ad Alice il digest del documento legittimo 𝑚𝑗 .
Eve estrapola la firma da 𝑚𝑗 e la applica al documento fake 𝑓𝑘 .

La probabilità che vi sia una collisione tra il primo e secondo gruppo è pari a (1 − 𝑒 −𝜆 ), con
𝑟2
𝜆= = 1, ovvero circa pari al 63%.
𝑁

Pertanto, compilando due liste di 264 elementi ciascuna, Eve facilmente trova una versione
del documento originale che ha lo stesso digest di una versione del documento fraudolento.
Per avere adeguata sicurezza bisogna aumentare il valore di 𝑁, ovvero la lunghezza del
digest, raddoppiarlo tutte le volte che c’è il rischio di un attacco del compleanno. Questo il
motivo per cui un digest a 128 bit non è sufficiente.
15

Potrebbero piacerti anche