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 non soddisfano nessuna 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 di cui 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 criptiamo \(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.

Decrittografia

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 prevedibili tramite 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