Set di chiavi

Tink utilizza i set di chiavi per attivare la rotazione delle chiavi. Formalmente, un insieme di chiavi è un elenco1 non vuoto di chiavi in cui una chiave è designata come primaria (la chiave utilizzata, ad esempio, per firmare e criptare i nuovi testi in chiaro). Inoltre, le chiavi in un insieme di chiavi ricevono un ID univoco2 e uno stato che consente di disattivarle senza rimuoverle da un insieme di chiavi.

I set di chiavi sono il modo principale in cui gli utenti possono accedere alle chiavi (tramite la classeKeysetHandle). In questo modo, ogni utente ha il codice per gestire più chiavi contemporaneamente. Per la maggior parte degli utenti della crittografia, la gestione di più chiavi è una necessità: deve essere possibile cambiare le chiavi (le chiavi vecchie possono essere divulgate, ad esempio) e non esiste quasi mai un "passa alla chiave successiva" atomico che può essere applicato alle macchine su cui viene eseguito il codice e a tutti i testi cifrati, globalmente e in un istante. Di conseguenza, l'utente deve scrivere codice che funzioni quando si passa da una chiave all'altra.

Esempio: AEAD

Prendi in considerazione un insieme 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}\) and \(\mathrm{Dec}\). Il set di chiavi ora specifica anche due nuove funzioni: \(\mathrm{Enc}\) e \(\mathrm{Dec}\) - \(\mathrm{Enc}\) è semplicemente uguale alla funzione \(\mathrm{Enc}\) della chiave principale del set di chiavi, mentre la funzione \(\mathrm{Dec}\) tenta di decriptare con tutte le chiavi, esaminandole in un determinato ordine (vedi di seguito per scoprire in che modo Tink migliora le prestazioni di questa operazione).

È interessante notare che i set di chiavi sono chiavi complete: si tratta di 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 ha bisogno di una descrizione completa degli oggetti \(\mathrm{Enc}\) e \(\mathrm{Dec}\) per funzionare correttamente. In questo modo, l'utente può scrivere API che comunicano che, per utilizzare questa classe, è necessario fornire la descrizione di una primitiva crittografica.

Rotazione chiave

Considera un utente di Tink che scrive un programma che prima ottiene un insieme di chiavi da un KMS, poi crea un oggetto AEAD da questo insieme di chiavi e infine utilizza questo oggetto per criptare e decriptare i testi cifrati.

Un utente di questo tipo è preparato automaticamente alla rotazione delle chiavi e al passaggio tra algoritmi nel caso in cui la sua scelta attuale non soddisfi più lo standard.

Tuttavia, è necessario prestare un po' di attenzione durante l'implementazione di questa rotazione delle chiavi: innanzitutto, il KMS deve aggiungere una nuova chiave al set di chiavi (ma non deve ancora impostarla come principale). Poi, il nuovo set di chiavi deve essere implementato in tutti i file binari, in modo che ogni file binario che utilizza questo set di chiavi abbia la chiave più recente al suo interno. Solo a questo punto la nuova chiave deve essere impostata come principale e il set di chiavi risultante deve essere distribuito di nuovo a tutti i binari che lo utilizzano.

Identificatori delle chiavi nelle crittografie

Considera di nuovo l'esempio di un set di chiavi AEAD. Se eseguita in modo ingenuo, la decrittografia di un testo cifrato richiede a Tink di provare 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 elevato overhead delle prestazioni.

Per questo motivo, Tink consente di anteporre alle crittografie una stringa di 5 byte ricavata dall'ID. Seguendo la filosofia delle "Chiavi complete" riportata sopra, questo prefisso è parte della chiave, e tutte le crittografie mai derivate con questa chiave devono avere questo prefisso. Quando gli utenti creano le chiavi, possono scegliere se devono utilizzare un prefisso di questo tipo o se devono utilizzare un formato di testo cifrato senza prefisso.

Quando una chiave è in un insieme di chiavi, Tink calcola questo tag dall'ID della chiave nell'insieme di chiavi. Il fatto che gli ID siano univoci2 all'interno di un insieme di chiavi implica che i tag siano univoci. Pertanto, 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 decrittografia.

Tuttavia, poiché il tag fa parte della chiave, ciò implica anche che la chiave può essere in un insieme di chiavi solo se ha un ID specifico. Ciò ha alcune implicazioni quando si descrive l'implementazione degli oggetti chiave in lingue diverse.


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

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