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 come type.googleapis.com/google.crypto.tink.AesGcmHkdfStreamingKey.

Questa crittografia è basata su HRRV151. Per l'analisi della sicurezza, fai riferimento a HS202.

Chiave e parametri

Le chiavi sono descritte nelle 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\) (equivale a \(\mathrm{len}(\mathrm{Header}) + 16\) come spiegato più avanti).

Le chiavi che violano una di queste proprietà vengono rifiutate da Tink, quando la chiave viene analizzata o quando viene creata la primitiva corrispondente.

Funzione di crittografia

Per criptare un messaggio \(\mathrm{Msg}\) con i dati associati\(\mathrm{AssociatedData}\), creiamo un'intestazione, suddividiamo il messaggio in segmenti, criptiamo ciascun segmento e concateniamo i segmenti criptati.

Crea l'intestazione

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

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

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

Dividi il messaggio

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

Le durate vengono scelte per soddisfare:

  • \(\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 descritti sopra.

\(n\) potrebbe 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}\) è pari a 4 byte nella codifica big-endian e il byte $b$ è 0x00 se $i < n-1$ e 0x01 in caso contrario.

Quindi eseguiamo la crittografia \(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 sono concatenati come \(\mathrm{Header} \| C_0 \| \cdots \| C_{n-1}\), che è il testo crittografato finale.

Decriptazione

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

Le API possono (e in genere lo fanno) consentire un accesso casuale o l'accesso all'inizio di un file senza ispezionare la fine del file. Questa operazione è intenzionale, poiché è possibile decriptare \(M_i\) da \(C_i\), senza decriptare tutti i blocchi di testo crittografato 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 utente malintenzionato a troncare efficacemente i file.

Serializzazione e analisi delle chiavi

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

Per analizzare una chiave, invertiamo il processo riportato sopra (come di consueto durante l'analisi dei proto). Il campo key_material_type viene ignorato. Il valore di output_prefix_type può essere ignorato. In alternativa, le chiavi che hanno output_prefix_type diverso da RAW possono essere rifiutate. Le chiavi con version diverso da 0 devono essere rifiutate.

Problemi noti

Le implementazioni della funzione di crittografia di cui sopra non sono sicure con i fork. Consulta la sezione Sicurezza delle forche.

Riferimenti


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

  2. Hoang, Shen, 2020. Security of Streaming Encryption nella libreria Tink di Google. https://eprint.iacr.org/2020/1019 

  3. RFC 5869. Key Derivation Function (HKDF) basata su HMAC. https://www.rfc-editor.org/rfc/rfc5869 

  4. NIST SP 800-38D. Raccomandazione per le modalità operative della crittografia a blocchi: Galois/Counter Mode (GCM) e GMAC. https://csrc.nist.gov/pubs/sp/800/38/d/final