Riutilizzo dello stato HMAC per più messaggi

4

Ho una chiave segreta k e messaggio m . Invio m || HMAC(m, k) a un'altra parte, che può verificare l'integrità di m, supponendo che sappia k .

Supponiamo di avere più messaggi m1 , m2 e così via. Quale delle seguenti due costruzioni è meglio da una prospettiva di sicurezza generale:

m1 || HMAC(m1, k) || m2 || HMAC(m1 || m2, k) || ...

o

m1 || HMAC(m1, k) || m2 || HMAC(m2, k) || ...

Ovviamente, non ho bisogno di concatenare effettivamente m1 || m2 per generare HMAC(m1 || m2, k) . Continuo semplicemente a utilizzare lo stato dell'HMAC man mano che vengono firmati sempre più messaggi. Quindi la prima modalità operativa è in realtà più efficiente e ciò che preferirei usare. Nel secondo caso, devo resettare lo stato HMAC prima del prossimo messaggio.

Per quanto riguarda il ricevitore, la prima volta che l'autenticazione del messaggio fallisce, è la fine della conversazione. Quindi non guadagno nulla avendo un HMAC valido per m2 se m1 non può essere autenticato.

Una delle costruzioni è intrinsecamente più sicura dell'altra? La prima modalità di funzionamento potrebbe far trapelare qualsiasi informazione sulla chiave (in teoria)?

    
posta VokinLoksar 06.10.2012 - 17:48
fonte

2 risposte

4

Dipende molto dalla funzione di sicurezza che vuoi raggiungere. Ogni coppia " m , HMAC ( k , m )" fornisce l'integrità nel seguente senso: l'avversario non sarà in grado di falsificare una coppia dichiarato valido dal destinatario, che il mittente non ha calcolato in primo luogo.

Potresti volere delle proprietà aggiuntive, però. Ad esempio, hai una sequenza di messaggi e vuoi evitare che l'avversario lo modifichi, ovvero trascinando del tutto i messaggi o inserendo duplicati di quelli vecchi o riordinandoli. Questa è una preoccupazione valida e solitamente viene indirizzata con un numero di sequenza . Cioè, ogni messaggio viene inviato come " m , HMAC ( k , s || m )" dove s è un numero di sequenza di dimensioni fisse (ad esempio codificato su 64 bit), a partire da 0 per il primo messaggio e poi incrementato a ogni messaggio (con un numero di sequenza a 64 bit, si ha un po 'di spazio - non lo farà ricomincia da 0 a "molto tempo"). Ecco come si fa in SSL , ad esempio (ogni "record" SSL ha il suo proprio MAC e il calcolo MAC include il numero di sequenza). Nota che il numero di sequenza è implicito: è usato nel calcolo MAC, ma non deve essere trasmesso sul filo, quindi non aumenta la dimensione di ciò che deve essere trasmesso.

Sono possibili altre costruzioni, come l'uso del precedente valore HMAC (si invia " m , HMAC ( k , z || m ) "dove z è l'output HMAC inviato con il messaggio precedente). La tua proposta funziona anche, ma solo perché il MAC è in realtà HMAC, che è robusto e che consente di afferrare il suo stato interno relativamente facilmente (anche se alcune implementazioni potrebbero non renderlo facile). Infatti, molti algoritmi MAC richiedono un non ripetibile IV e non raggiungerebbero una sicurezza adeguata con il tuo metodo. Questo è il motivo per cui ti consiglio di utilizzare i numeri di sequenza, poiché questo è un metodo standard ben studiato che ha il vantaggio di essere applicato più facilmente ad altri algoritmi MAC (e l'agilità dell'algoritmo è una bella funzionalità avere).

(La capacità di HMAC di funzionare in modalità IV-less è la caratteristica che lo rende il migliore algoritmo MAC generico.Se si ha comunque un IV, perché i messaggi non sono solo MACed ma anche crittografati, quindi sono preferiti gli crittografia autenticata .

    
risposta data 06.10.2012 - 19:35
fonte
3

L'approccio che stai chiedendo è anche noto come attacco di estensione della lunghezza , e gli HMAC sono esplicitamente non suscettibili a questi tipi di attacchi.

Dato HMAC(K, m) = H((K ⊕ opad) ∥ H((K ⊕ ipad) ∥ m)) , il meglio che puoi fare è precomputare

Ko  = K ⊕ opad
Ki  = K ⊕ ipad
m'0 = Ki ∥ m0
m'i = m'i-1 ∥ mi

HMAC(K, mi) = H(Ko ∥ H(m'i))

che in realtà non ti salva nulla tranne alcuni XOR e appendi. Stai ancora calcolando due hash per messaggio, che è la parte computazionalmente costosa. Inoltre, devi farlo su quantità di dati in costante aumento. Anche la verifica MAC è parimenti influenzata.

Una cosa che ho notato nella tua descrizione è che stai semplicemente concatenando messaggi successivi e i loro MAC. A meno che le lunghezze dei messaggi non siano corrette, dovresti fare qualcosa del tipo

LEN(m0) ∥ m0 ∥ HMAC(K, m0) ∥ LEN(m1) ∥ m1 ∥ HMAC(K, m1) ∥ ...

dove la lunghezza è memorizzata con una codifica non ambigua a dimensione fissa (ad es. numero intero a 64 bit senza segno nell'ordine big-endian).

Aggiornamento: "Meglio da una prospettiva di sicurezza generale" dipende interamente dalle esigenze del tuo sistema. Se richiede ogni messaggio successivo ad essere autenticato dal messaggio precedente, allora HMAC(H, mi) non è adatto. Se ogni messaggio può essere verificato in sicurezza indipendentemente da qualsiasi altro messaggio, non c'è motivo di utilizzare qualcosa di più complicato di HMAC(H, mi) .

    
risposta data 06.10.2012 - 18:27
fonte

Leggi altre domande sui tag