AEAD per streaming AES-GCM-HKDF

Questo documento definisce formalmente la funzione matematica rappresentata dalle chiavi di streaming AES-GCM-HKDF, codificate in formato proto cometype.googleapis.com/google.crypto.tink.AesGcmHkdfStreamingKey.

Questa crittografia si basa liberamente su HRRV151. Per l'analisi della sicurezza, facciamo riferimento allo standard HS202.

Chiave e parametri

Le chiavi sono descritte dalle seguenti parti (tutte le dimensioni in questo documento sono in byte):

  • \(\mathrm{KeyValue}\), una stringa di byte.
  • \(\mathrm{CiphertextSegmentSize} \in \{1, 2, \ldots, 2^{31}-1\}\).
  • \(\mathrm{DerivedKeySize} \in \{16, 32\}\).
  • \(\mathrm{HkdfHashType} \in \{\mathrm{SHA1}, \mathrm{SHA256}, \mathrm{SHA512}\}\).

Le chiavi valide soddisfano inoltre le seguenti proprietà:

  • \(\mathrm{len}(\mathrm{KeyValue}) \geq \mathrm{DerivedKeySize}\).
  • \(\mathrm{CiphertextSegmentSize} > \mathrm{DerivedKeySize} + 24\) (è uguale a \(\mathrm{len}(\mathrm{Header}) + 16\) , come spiegato di seguito).

Le chiavi che non soddisfano nessuna di queste proprietà vengono rifiutate da Tink quando vengono analizzate o quando viene creato l'elemento primitivo corrispondente.

Funzione di crittografia

Per criptare un messaggio \(\mathrm{Msg}\) con i dati associati\(\mathrm{AssociatedData}\), creiamo un'intestazione, dividiamo il messaggio in segmenti, criptamo ogni segmento e concatenamo i segmenti criptati.

Crea l'intestazione

Scegliamo una stringa casuale uniforme \(\mathrm{Salt}\) di lunghezza\(\mathrm{DerivedKeySize}\) e una stringa casuale uniforme \(\mathrm{NoncePrefix}\)di lunghezza 7.

Impostiamo quindi \(\mathrm{Header} := \mathrm{len}(\mathrm{Header}) \| \mathrm{Salt} \| \mathrm{NoncePrefix}\), dove la lunghezza dell'intestazione è codificata come singolo byte. Tieni presente che \(\mathrm{len}(\mathrm{Header}) \in \{24, 40\}\).

Successivamente, utilizziamo HKDF3 con la funzione hash data da \(\mathrm{HkdfHashType}\) e gli input \(\mathrm{ikm} := \mathrm{KeyValue}\), \(\mathrm{salt} := \mathrm{Salt}\)e \(\mathrm{info} := \mathrm{AssociatedData}\), con la lunghezza \(\mathrm{DerivedKeySize}\)dell'output. Il risultato è chiamato \(\mathrm{DerivedKey}\).

Suddividere il messaggio

Il messaggio \(\mathrm{Msg}\) viene poi suddiviso in parti: \(\mathrm{Msg} = M_0 \| M_1 \| \cdots \| M_{n-1}\).

La loro lunghezza viene scelta in modo da soddisfare i seguenti requisiti:

  • \(\mathrm{len}(M_0) \in \{0,\ldots, \mathrm{CiphertextSegmentSize} - \mathrm{len}(\mathrm{Header}) - \mathrm{16}\}\).
  • Se \(n>1\), allora \(\mathrm{len}(M_1), \ldots, \mathrm{len}(M_{n-1}) \in \{1,\ldots, \mathrm{CiphertextSegmentSize} - \mathrm{16}\}\).
  • Se \(n>1\), \(\mathrm{len}(M_{0}), \ldots, \mathrm{len}(M_{n-2})\) deve avere una lunghezza massima in base ai vincoli riportati sopra.

\(n\) può essere al massimo \(2^{32}\). In caso contrario, la crittografia non va a buon fine.

Cripta i blocchi

Per criptare il segmento \(M_i\), calcoliamo \(\mathrm{IV}_i := \mathrm{NoncePrefix} \| \mathrm{i} \| b\), dove \(\mathrm{i}\) è 4 byte in codifica big-endian e il byte $b$ è 0x00 se $i < n-1$ e 0x01 in caso contrario.

Poi crittografiamo \(M_i\) utilizzando AES-GCM4, dove la chiave è\(\mathrm{DerivedKey}\), il vettore di inizializzazione è \(\mathrm{IV}_i\)e i dati associati sono la stringa vuota. \(C_i\) è il risultato di questa crittografia (ovvero la concatenazione di \(C\) e \(T\) nella sezione 5.2.1.2 del riferimento AES-GCM collegato).

Concatena i segmenti criptati

Infine, tutti i segmenti vengono concatenati come \(\mathrm{Header} \| C_0 \| \cdots \| C_{n-1}\), che è il testo cifrato finale.

Decriptazione

La decriptazione inverte la crittografia. Utilizziamo l'intestazione per ottenere\(\mathrm{NoncePrefix}\)e decriptare singolarmente ogni segmento di testo cifrato.

Le API possono (e in genere lo fanno) consentire l'accesso casuale o l'accesso all'inizio di un file senza ispezionare la fine del file. Questo è intenzionale, poiché è possibile decriptare \(M_i\) da \(C_i\)senza decriptare tutti i blocchi di testo cifrato precedenti e rimanenti.

Tuttavia, le API devono fare attenzione a non consentire agli utenti di confondere gli errori di fine file e di decrittografia: in entrambi i casi l'API probabilmente deve restituire un errore e ignorare la differenza può portare un avversario a essere in grado di troncare efficacemente i file.

Serializzazione e analisi delle chiavi

Per serializzare una chiave nel formato "Tink Proto", mappiamo prima i parametri nel modo ovvio nel proto fornito in aes_gcm_hkdf_streaming.proto. Il campo version deve essere impostato su 0. Lo serializziamo quindi utilizzando la normale serializzazione di proto e incorporiamo la stringa risultante nel valore del campo di un proto KeyData. Abbiamo impostato il campo type_url su type.googleapis.com/google.crypto.tink.AesGcmHkdfStreamingKey. Impostiamo quindi key_material_type su SYMMETRIC e lo incorporiamo in un set di chiavi. Di solito impostiamo output_prefix_type su RAW. L'eccezione è che se la chiave è stata analizzata con un valore diverso impostato per output_prefix_type, Tink può scrivere RAW o il valore precedente.

Per analizzare una chiave, invertiamo la procedura descritta sopra (come di consueto per l'analisi di proto). Il campo key_material_type viene ignorato. Il valore di output_prefix_type può essere ignorato oppure le chiavi conoutput_prefix_type diverso da RAW possono essere rifiutate. Le chiavi con un valore version diverso da 0 devono essere rifiutate.

Problemi noti

Le implementazioni della funzione di crittografia riportata sopra non dovrebbero essere sicure per i fork. Consulta Sicurezza del fork.

Riferimenti


  1. Hoang, Reyhanitabar, Rogaway, Vizar, 2015. Crittografia autenticata online e la sua resistenza all'uso improprio del riutilizzo del nonce. CRYPTO 2015. https://eprint.iacr.org/2015/189 

  2. Hoang, Shen, 2020. Sicurezza della crittografia in streaming nella libreria Tink di Google. https://eprint.iacr.org/2020/1019 

  3. RFC 5869. Funzione di derivazione delle chiavi di estrazione ed espansione (HKDF) basata su HMAC. https://www.rfc-editor.org/rfc/rfc5869 

  4. NIST SP 800-38D. Consiglio per le modalità di funzionamento delle crittografie a blocchi: Galileo/Counter Mode (GCM) e GMAC. https://csrc.nist.gov/pubs/sp/800/38/d/final