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
-
Hoang, Reyhanitabar, Rogaway, Vizar, 2015. Crittografia autenticata online e resistenza all'uso improprio da riutilizzo nonce. CRIPTO 2015. https://eprint.iacr.org/2015/189 ↩
-
Hoang, Shen, 2020. Security of Streaming Encryption nella libreria Tink di Google. https://eprint.iacr.org/2020/1019 ↩
-
RFC 5869. Key Derivation Function (HKDF) basata su HMAC. https://www.rfc-editor.org/rfc/rfc5869 ↩
-
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 ↩