Passa al contenuto principale

10. Considerazioni sulla sicurezza

Questa sezione contiene ulteriori considerazioni sulla sicurezza relative ai meccanismi di hashing verso le curve descritti in questo documento.

10.1. Proprietà delle codifiche

Ciascun tipo di codifica (Sezione 3) accetta una stringa di byte arbitraria e la mappa a un punto sulla curva campionato da una distribuzione che dipende dal tipo di codifica. È importante notare che l'uso di una codifica non uniforme o la valutazione diretta di una delle mappature della Sezione 6 produce un output facilmente distinguibile da un punto casuale uniforme. Le applicazioni che utilizzano una codifica non uniforme DOVREBBERO analizzare attentamente le implicazioni sulla sicurezza della non uniformità. Se la codifica richiesta non è chiara, le applicazioni DOVREBBERO utilizzare una codifica uniforme.

Entrambe le codifiche fornite nella Sezione 3 possono produrre l'elemento identità del gruppo G. La probabilità che una delle due funzioni di codifica produca l'elemento identità è di circa 1/r per un input casuale, il che è trascurabile per curve ellittiche crittograficamente utili. Inoltre, è computazionalmente impossibile trovare un input per una delle due funzioni di codifica il cui corrispondente output sia l'elemento identità. (Entrambe queste proprietà valgono quando le funzioni di codifica sono istanziate con una funzione hash_to_field che segue tutte le linee guida della Sezione 5). I protocolli che utilizzano queste funzioni di codifica NON DOVREBBERO aggiungere casi speciali per rilevare e "correggere" l'elemento identità.

Quando la funzione hash_to_curve (Sezione 3) è istanziata con una funzione hash_to_field indifferenziabile da un random oracle (Sezione 5), la funzione risultante è indifferenziabile da un random oracle ([MRH04] [BCIMRT10] [FFSTV13] [LBB19] [H20]). In molti casi, tale funzione può essere utilizzata in sicurezza nei protocolli crittografici la cui analisi di sicurezza presuppone un random oracle che produce punti uniformemente casuali su una curva ellittica. Come discusso da Ristenpart et al. in [RSS11], tuttavia, non tutte le prove di sicurezza che si basano su random oracle rimangono valide quando tali oracle vengono sostituiti da funzionalità indifferenziabili. Questa limitazione deve essere considerata nell'analizzare la sicurezza dei protocolli che si basano sulla funzione hash_to_curve.

10.2. Hashing di password

Quando si esegue l'hashing di password utilizzando una qualsiasi funzione descritta in questo documento, un avversario che apprende l'output della funzione di hash (o potenzialmente qualsiasi valore intermedio, ad esempio l'output di hash_to_field) potrebbe essere in grado di eseguire un attacco a dizionario. Per mitigare tali attacchi, si raccomanda di eseguire prima una funzione di derivazione della chiave più costosa (ad esempio, PBKDF2 [RFC8017], scrypt [RFC7914] o Argon2 [RFC9106]) sulla password e quindi di eseguire l'hashing dell'output di tale funzione sulla curva ellittica di destinazione. Per la resistenza alle collisioni, l'hash sottostante alla funzione di derivazione della chiave deve essere scelto secondo le linee guida elencate nella Sezione 5.3.1.

10.3. Requisiti di tempo costante

Le implementazioni a tempo costante di tutte le funzioni in questo documento sono FORTEMENTE RACCOMANDATE per tutti gli usi, al fine di evitare fughe di informazioni attraverso canali laterali. È particolarmente importante utilizzare un'implementazione a tempo costante quando gli input di una codifica sono valori segreti; in tali casi, le implementazioni a tempo costante sono RICHIESTE per la sicurezza contro gli attacchi temporali (ad esempio, [VR20]). Quando sono richieste implementazioni a tempo costante, tutte le operazioni di base e le funzioni di utilità devono essere implementate a tempo costante, come discusso nella Sezione 4. In alcune applicazioni (ad esempio, sistemi embedded), le fughe attraverso altri canali laterali (ad esempio, canali laterali energetici o elettromagnetici) possono essere rilevanti. La difesa contro tali fughe esula dallo scopo di questo documento, poiché la natura della fuga e la difesa appropriata dipendono dall'applicazione.

10.4. encode_to_curve: Distribuzione dell'output e indifferenziabilità

La funzione encode_to_curve (Sezione 3) restituisce punti campionati da una distribuzione che è statisticamente lontana dall'uniformità. Questa distribuzione è limitata approssimativamente come segue: innanzitutto, include almeno un ottavo dei punti di G e, in secondo luogo, la probabilità dei punti nella distribuzione varia al massimo di un fattore quattro. Questi limiti valgono quando encode_to_curve è istanziata con una qualsiasi delle funzioni map_to_curve della Sezione 6.

I limiti sopra indicati derivano da diversi lavori in letteratura. Nello specifico:

  • Shallue e van de Woestijne [SW06] e Fouque e Tibouchi [FT12] derivano limiti sulla mappatura Shallue-van de Woestijne (Sezione 6.6.1).

  • Fouque e Tibouchi [FT10] e Tibouchi [T14] derivano limiti per la mappatura SWU semplificata (Sezioni 6.6.2 e 6.6.3).

  • Bernstein et al. [BHKL13] derivano limiti per la mappatura Elligator 2 (Sezioni 6.7.1 e 6.8.2).

L'indifferenziabilità di encode_to_curve segue da un argomento simile a quello fornito da Brier et al. [BCIMRT10]; ne delineiamo brevemente l'argomento come segue. Si consideri un random oracle ideale Hc() che campioni dalla distribuzione indotta dalla funzione map_to_curve chiamata da encode_to_curve, e si supponga per semplicità che la curva ellittica di destinazione abbia cofattore 1 (un argomento simile si applica per cofattori diversi dall'unità). L'indifferenziabilità viene verificata se è possibile simulare in modo efficiente il random oracle "interno" in encode_to_curve, ovvero hash_to_field. Il simulatore funziona come segue: su una nuova query msg, il simulatore interroga Hc(msg) e riceve un punto P nell'immagine di map_to_curve (se msg è identico a una query precedente, il simulatore restituisce semplicemente il valore che ha dato in risposta a tale query). Il simulatore calcola quindi le possibili pre-immagini di P sotto map_to_curve, ovvero gli elementi u di F tali che map_to_curve(u) == P (Tibouchi [T14] mostra che ciò può essere fatto in modo efficiente per le mappature Shallue-van de Woestijne e SWU semplificata, e Bernstein et al. mostrano lo stesso per Elligator 2). Il simulatore seleziona una di queste pre-immagini a caso e restituisce tale valore come output simulato del random oracle "interno". Per ipotesi, Hc() campiona dalla distribuzione indotta da map_to_curve su un elemento di input di F uniformemente casuale, quindi tale valore è uniformemente casuale e induce il corretto punto P quando fatto passare attraverso map_to_curve.

10.5. Sicurezza di hash_to_field

La funzione hash_to_field, definita nella Sezione 5, è indifferenziabile da un random oracle [MRH04] quando expand_message (Sezione 5.3) è modellato come un random oracle. Poiché le prove di indifferenziabilità sono componibili, ciò è vero anche quando expand_message è dimostrato indifferenziabile da un random oracle rispetto a una primitiva sottostante modellata come un random oracle. Seguendo le linee guida nella Sezione 5.3, entrambe le varianti di expand_message definite in tale sezione soddisfano questo requisito (vedere anche la Sezione 10.6).

Delineiamo molto brevemente l'argomento dell'indifferenziabilità per hash_to_field. Si noti che ogni intero mod p che hash_to_field restituisce (cioè ogni elemento della rappresentazione vettoriale di F) è membro di una classe di equivalenza di circa 2^k interi di lunghezza log2(p) + k bit, i quali sono tutti uguali modulo p. Per ogni intero mod p che hash_to_field restituisce, il simulatore campiona casualmente un membro di tale classe di equivalenza e produce la stringa di byte restituita da I2OSP. (Si noti che questo è essenzialmente l'inverso della procedura hash_to_field).

10.6. Sicurezza di expand_message_xmd

La funzione expand_message_xmd, definita nella Sezione 5.3.1, è indifferenziabile da un random oracle [MRH04] quando viene soddisfatta una delle seguenti condizioni:

  1. H è indifferenziabile da un random oracle,

  2. H è una funzione di hash basata su spugna la cui funzione interna è modellata come una trasformazione casuale o una permutazione casuale [BDPV08], oppure

  3. H è una funzione di hash Merkle-Damgaard la cui funzione di compressione è modellata come un random oracle [CDMP05].

Per i casi (1) e (2), l'indifferenziabilità di expand_message_xmd segue direttamente dall'indifferenziabilità di H.

Per il caso (3), ovvero quando H è una funzione di hash Merkle-Damgaard, l'indifferenziabilità segue da [CDMP05], Teorema 5. In particolare, expand_message_xmd calcola b_0 facendo precedere il messaggio da un blocco di zeri più informazioni ausiliarie (lunghezza, contatore e DST). Quindi, ciascuno dei blocchi di output b_i, i >= 1 in expand_message_xmd è il risultato dell'invocazione di H su una codifica univoca e priva di prefisso di b_0. Ciò è vero, innanzitutto perché la lunghezza dell'input di tutte queste invocazioni è uguale e fissata dalla scelta di H e DST, e in secondo luogo perché ciascuno di questi input possiede un suffisso univoco (a causa dell'inclusione del byte contatore I2OSP(i, 1)).

La differenza essenziale tra la costruzione discussa in [CDMP05] ed expand_message_xmd è che quest'ultima esegue l'hashing di un contatore aggiunto a strxor(b_0, b_(i - 1)) (passaggio 10 della Sezione 5.3.1) anziché a b_0. Questo approccio aumenta la distanza di Hamming tra gli input di diverse invocazioni di H, riducendo la probabilità che le non idealità in H influenzino la distribuzione dei valori b_i.

Notiamo che expand_message_xmd può essere utilizzata per istanziare una funzionalità indifferenziabile per scopi generali con output a lunghezza variabile basata su qualsiasi funzione di hash che soddisfi uno dei criteri sopra indicati. Le applicazioni che utilizzano expand_message_xmd al di fuori di hash_to_field dovrebbero garantire la separazione di dominio scegliendo un valore distinto per DST.

10.7. Separazione di dominio per varianti di expand_message

Come discusso nella Sezione 2.2.5, lo scopo della separazione di dominio è garantire che le analisi di sicurezza dei protocolli crittografici che interrogano più random oracle indipendenti rimangano valide anche se tutti questi random oracle sono istanziati sulla base di una singola funzione sottostante H.

Le varianti di expand_message in questo documento (Sezione 5.3) assicurano la separazione di dominio aggiungendo un tag di separazione di dominio codificato senza suffisso DST_prime a tutte le stringhe sottoposte ad hashing da H, un hash sottostante o una funzione a output estensibile. (Si prevede che altre varianti di expand_message che seguono le linee guida della Sezione 5.3.4 si comportino in modo simile, ma queste dovrebbero essere analizzate caso per caso). Per sicurezza, le applicazioni che utilizzano la stessa funzione H al di fuori di expand_message dovrebbero imporre una separazione di dominio tra tali usi di H ed expand_message, e dovrebbero separare tutti questi dagli usi di H in altre applicazioni.

Questa sezione suggerisce quattro metodi per imporre la separazione di dominio dalle varianti di expand_message, spiega come ciascun metodo realizza la separazione di dominio ed elenca le situazioni in cui ciascuno è appropriato. Questi metodi condividono una struttura di alto livello: il progettista dell'applicazione fissa un tag DST_ext distinto da DST_prime e integra le chiamate a H con DST_ext. Ogni metodo integra le chiamate a H in modo diverso e ciascuno può imporre requisiti aggiuntivi su DST_ext.

Questi metodi possono essere utilizzati per istanziare più funzioni separate per dominio (ad esempio, H1 e H2) selezionando valori DST_ext distinti per ciascuna (ad esempio, DST_ext1, DST_ext2).

  1. (Separazione di dominio solo per suffisso). Questo metodo è utile quando si separano per dominio le invocazioni di H da expand_message_xmd o expand_message_xof. Non è appropriato per separare per dominio expand_message da HMAC-H [RFC2104]; a tale scopo, vedere il metodo 4.

    Per istanziare una funzione Hso separata per dominio solo per suffisso, calcolare:

    Hso(msg) = H(msg || DST_ext)

    DST_ext dovrebbe essere codificato senza suffisso (ad esempio, aggiungendo un byte che codifica la lunghezza di DST_ext) per rendere impraticabile la ricerca di coppie (msg, DST_ext) distinte che producono lo stesso valore di hash.

    Questo metodo assicura la separazione di dominio perché tutte le invocazioni distinte di H hanno suffissi distinti, poiché DST_ext è distinto da DST_prime.

  2. (Separazione di dominio prefisso-suffisso). Questo metodo può essere utilizzato negli stessi casi del metodo solo per suffisso.

    Per istanziare una funzione Hps separata per dominio prefisso-suffisso, calcolare:

    Hps(msg) = H(DST_ext || msg || I2OSP(0, 1))

    DST_ext dovrebbe essere codificato senza prefisso (ad esempio, aggiungendo un prefisso di un byte che codifica la lunghezza di DST_ext) per rendere impraticabile la ricerca di coppie (msg, DST_ext) distinte che producono lo stesso valore di hash.

    Questo metodo assicura la separazione di dominio perché l'aggiunta del byte I2OSP(0, 1) garantisce che gli input di H all'interno di Hps siano distinti da quelli all'interno di expand_message. Nello specifico, l'ultimo byte di DST_prime codifica la lunghezza di DST, che deve essere diversa da zero (Sezione 3.1, requisito 2), e DST_prime è sempre aggiunto alle invocazioni di H all'interno di expand_message.

  3. (Separazione di dominio solo per prefisso). Questo metodo è utile solo per separare per dominio le invocazioni di H da expand_message_xmd. Non consente la separazione di dominio per expand_message_xof o HMAC-H.

    Per istanziare una funzione Hpo separata per dominio solo per prefisso, calcolare:

    Hpo(msg) = H(DST_ext || msg)

    Affinché questo metodo assicuri la separazione di dominio, DST_ext dovrebbe essere lunga almeno b bit, dove b è il numero di bit prodotti dalla funzione di hash H. Inoltre, almeno uno dei primi b bit deve essere diverso da zero. Infine, DST_ext dovrebbe essere codificata senza prefisso (ad esempio, aggiungendo un prefisso di un byte che codifica la lunghezza di DST_ext) per rendere impraticabile la ricerca di coppie (msg, DST_ext) distinte che producono lo stesso valore di hash.

    Questo metodo assicura la separazione di dominio nel modo seguente. Innanzitutto, poiché DST_ext contiene almeno un bit non nullo tra i suoi primi b bit, è garantito che sia distinta dal valore Z_pad (Sezione 5.3.1, passaggio 4), il che assicura che tutti gli input di H siano distinti dall'input utilizzato per generare b_0 in expand_message_xmd. In secondo luogo, poiché DST_ext è lunga almeno b bit, è quasi certamente distinta dai valori b_0 e strxor(b_0, b_(i - 1)), e di conseguenza tutti gli input di H sono distinti dagli input utilizzati per generare b_i, i >= 1, con un'alta probabilità.

  4. (Separazione di dominio XMD-HMAC). Questo metodo è utile per separare per dominio le invocazioni di H all'interno di HMAC-H (ovvero HMAC [RFC2104] istanziato con la funzione di hash H) da expand_message_xmd. Si applica anche a HKDF-H (ovvero HKDF [RFC5869] istanziato con la funzione di hash H), come discusso di seguito.

    Nello specifico, questo metodo si applica quando HMAC-H viene utilizzato con una chiave non segreta per istanziare un random oracle basato su una funzione di hash H (si noti che expand_message_xmd può essere utilizzata anche a tale scopo; vedere la Sezione 10.6). Quando si utilizza HMAC-H con una chiave segreta ad alta entropia, la separazione di dominio non è necessaria; vedere la discussione di seguito.

    Per scegliere una chiave HMAC non segreta DST_key che assicuri la separazione di dominio rispetto ad expand_message_xmd, calcolare:

    DST_key_preimage = "DERIVE-HMAC-KEY-" || DST_ext || I2OSP(0, 1) DST_key = H(DST_key_preimage)

    Quindi, per istanziare il random oracle Hro utilizzando HMAC-H, calcolare:

    Hro(msg) = HMAC-H(DST_key, msg)

    L'ultimo byte zero in DST_key_preimage garantisce che questo valore sia distinto dagli input di H all'interno di expand_message_xmd (poiché tutti questi input hanno il suffisso DST_prime, che non può terminare con un byte zero come discusso sopra). Ciò assicura la separazione di dominio poiché, con probabilità schiacciante, tutti gli input di H all'interno di HMAC-H che utilizzano la chiave DST_key hanno prefissi distinti dai valori Z_pad, b_0 e strxor(b_0, b_(i - 1)) all'interno di expand_message_xmd.

    Per gli utilizzi di HMAC-H che istanziano un random oracle privato fissando una chiave segreta ad alta entropia, la separazione di dominio rispetto ad expand_message_xmd non è necessaria. Infatti, similmente al caso sopra indicato, tutti gli input di H all'interno di HMAC-H che utilizzano tale chiave segreta hanno quasi certamente prefissi distinti da tutti gli input di H all'interno di expand_message_xmd.

    Infine, questo metodo può essere utilizzato con HKDF-H [RFC5869] fissando l'input salt di HKDF-Extract a DST_key, calcolata come sopra. Ciò assicura la separazione di dominio per HKDF-Extract con lo stesso argomento di HMAC-H che utilizza DST_key. Inoltre, assumendo che il materiale della chiave di input (IKM) fornito a HKDF-Extract possieda un'entropia sufficientemente alta (diciamo, proporzionata al parametro di sicurezza), la fase HKDF-Expand è separata per dominio con lo stesso argomento di HMAC-H con una chiave segreta ad alta entropia (poiché una chiave pseudocasuale è esattamente questo).

10.8. Livelli di sicurezza di destinazione

Ogni suite crittografica specifica un livello di sicurezza di destinazione (in bit) per la curva sottostante. Questo parametro garantisce che la corrispondente istanziazione di hash_to_field sia conservativa e corretta. Sottolineiamo che questo parametro è solo un limite superiore del livello di sicurezza della curva e non è né una garanzia né un'approvazione della sua idoneità per una data applicazione. I progressi matematici e crittografici possono ridurre il livello di sicurezza effettivo di qualsiasi curva.