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
-
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 ↩
-
Hoang, Shen, 2020. Sicurezza della crittografia in streaming nella libreria Tink di Google. https://eprint.iacr.org/2020/1019 ↩
-
RFC 5869. Funzione di derivazione delle chiavi di estrazione ed espansione (HKDF) basata su HMAC. https://www.rfc-editor.org/rfc/rfc5869 ↩
-
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 ↩