Set di chiavi

Tink utilizza i set di chiavi per abilitare la rotazione delle chiavi. Un set di chiavi è formalmente un elenco non vuoto1 di chiavi in cui una chiave è designata come primaria (la chiave utilizzata, ad esempio, per firmare e criptare nuovi testi non crittografato). Inoltre, le chiavi in un set di chiavi ricevono un ID univoco2 e uno stato della chiave che consente di disabilitare le chiavi senza rimuoverle da un set.

I set di chiavi rappresentano il metodo principale con cui gli utenti possono accedere alle chiavi (tramite la classe KeysetHandle). In questo modo, ogni utente dispone di codice per gestire più chiavi contemporaneamente. Per la maggior parte degli utenti della crittografia, gestire più chiavi è una necessità: deve essere possibile modificare le chiavi (ad esempio le vecchie chiavi potrebbero essere divulgate) e non esiste quasi mai un passaggio atomico alla chiave successiva che può essere applicato alle macchine su cui viene eseguito il codice e a tutti i testi criptati, a livello globale e in un istante. Di conseguenza, l'utente deve scrivere codice che funziona quando si passa da una chiave a quella successiva.

Esempio: AEAD

Prendiamo come esempio un set di chiavi AEAD, che contiene più chiavi per la primitiva AEAD. Come spiegato in precedenza, ogni chiave specifica in modo univoco due funzioni: \(\mathrm{Enc}\) e \(\mathrm{Dec}\). Il set di chiavi ora specifica anche due nuove funzioni: \(\mathrm{Enc}\) e \(\mathrm{Dec}\) - \(\mathrm{Enc}\) è uguale a quella \(\mathrm{Enc}\) della chiave primaria del set di chiavi, mentre la funzione \(\mathrm{Dec}\) prova a decriptare con tutte le chiavi, attraversandole in qualche ordine (vedi di seguito come Tink migliora le prestazioni di questa funzione).

È interessante notare che i set di chiavi sono chiavi completi: rappresentano una descrizione completa delle funzioni \(\mathrm{Enc}\) e \(\mathrm{Dec}\) utilizzate. Ciò significa che gli utenti possono scrivere una classe che prende come input un KeysetHandle, esprimendo l'idea che la classe abbia bisogno di una descrizione completa degli oggetti \(\mathrm{Enc}\) e \(\mathrm{Dec}\) per funzionare correttamente. Ciò consente all'utente di scrivere API che comunicano che: per utilizzare questa classe è necessario fornire la descrizione di una primitiva crittografica.

Rotazione chiave

Prendiamo ad esempio un utente Tink che scrive un programma che prima ottiene un set di chiavi da un KMS, poi crea un oggetto AEAD da questo set di chiavi e, infine, utilizza questo oggetto per criptare e decriptare i testi criptati.

Un utente di questo tipo è pronto automaticamente per la rotazione della chiave e può cambiare algoritmo nel caso in cui la scelta corrente non soddisfi più lo standard.

Tuttavia, quando si implementa la rotazione di una chiave, è necessario fare un po' di attenzione: in primo luogo, il KMS deve aggiungere una nuova chiave al set di chiavi (ma non ancora impostarla come primaria). Quindi, il nuovo set di chiavi deve essere implementato per tutti i programmi binari, in modo che ogni programma binario che utilizza il set di chiavi contenga la chiave più recente. Solo allora la nuova chiave deve essere impostata come primaria e il set di chiavi risultante viene nuovamente distribuito a tutti i programmi binari che utilizzano il set di chiavi.

Identificatori chiave nei testi criptati

Considera di nuovo l'esempio di un set di chiavi AEAD. Se eseguita in modo ingenuo, la decrittografia di un testo crittografato richiede che Tink provi a decriptare con tutte le chiavi nel set di chiavi, in quanto non è possibile sapere quale chiave è stata utilizzata per criptare il set di chiavi. Ciò può causare un overhead elevato delle prestazioni.

Per questo motivo, Tink consente di anteporre ai testi criptati una stringa di 5 byte derivata dall'ID. Secondo la filosofia "Chiavi complete" sopra riportata, questo prefisso fa parte della chiave e tutti i testi crittografati derivati da questa chiave devono avere questo prefisso. Quando gli utenti creano le chiavi, possono scegliere se la chiave deve utilizzare questo prefisso o se deve essere utilizzato un formato di testo crittografato senza.

Quando una chiave si trova in un set di chiavi, Tink calcola questo tag dall'ID della chiave che si trova nel set di chiavi. Il fatto che gli ID siano univoci2 all'interno di un set di chiavi implica che i tag siano univoci. Di conseguenza, se vengono utilizzate solo chiavi con tag, non si verifica alcuna perdita di prestazioni rispetto alla decrittografia con una singola chiave: Tink deve provare solo una delle chiavi durante la decriptazione.

Tuttavia, poiché il tag fa parte della chiave, ciò implica anche che la chiave può trovarsi in un set di chiavi solo se ha un ID specifico. Ciò ha alcune implicazioni nella descrizione dell'implementazione degli oggetti chiave in lingue diverse.


  1. Alcune parti di Tink considerano ancora i set di chiavi come un insieme. Tuttavia, questo deve essere modificato. Il motivo è che l'ordine è in linea di massima importante: ad esempio, considera il ciclo di vita tipico di una rotazione di chiavi con Aead. Innanzitutto, viene aggiunta una nuova chiave a un set di chiavi. Questa chiave non è ancora impostata come principale, ma è attiva. Questo nuovo set di chiavi è stato implementato per tutti i programmi binari. Una volta che tutti i programmi binari conoscono la nuova chiave, la chiave diventa primaria (solo a questo punto l'utilizzo della chiave è sicuro). In questo secondo passaggio, la rotazione della chiave deve conoscere l'ultima chiave aggiunta. 

  2. Per garantire la compatibilità con una libreria interna di Google, Tink consente di avere set di chiavi in cui gli ID vengono ripetuti. Questo supporto verrà rimosso in futuro.