Schlüsselsätze

Tink verwendet Keysets, um die Schlüsselrotation zu aktivieren. Formal ist ein Keyset eine nicht leere Liste1 von Schlüsseln, in denen ein Schlüssel als primär festgelegt ist (der Schlüssel, der beispielsweise zum Signieren und Verschlüsseln neuer Klartexte verwendet wird). Darüber hinaus erhalten Schlüssel in einem Schlüsselsatz eine eindeutige ID2 und einen Schlüsselstatus, mit dem Schlüssel deaktiviert werden können, ohne sie aus einem Schlüsselsatz zu entfernen.

Schlüsselsätze sind die Hauptmethode, über die Nutzer auf Schlüssel zugreifen können (über die Klasse KeysetHandle). Dadurch wird sichergestellt, dass jeder Nutzer Code hat, um mehrere Schlüssel gleichzeitig zu verarbeiten. Für die meisten Nutzer von Kryptografie ist die Verarbeitung mehrerer Schlüssel eine Notwendigkeit: Schlüssel müssen geändert werden können (alte Schlüssel können beispielsweise geleakt werden) und es gibt fast nie einen atomaren "Wechsel zum nächsten Schlüssel", der auf die Maschinen angewendet werden kann, auf denen der Code ausgeführt wird, und alle Geheimtexte, global und in Sekundenschnelle. Daher muss der Nutzer Code schreiben, der funktioniert, wenn einer von einem Schlüssel zum nächsten wechselt.

Beispiel: AEAD

Angenommen, ein AEAD-Schlüsselsatz enthält mehrere Schlüssel für das AEAD-Primitive. Wie bereits erläutert, werden mit jedem Schlüssel zwei Funktionen eindeutig festgelegt: \(\mathrm{Enc}\) und \(\mathrm{Dec}\). Der Schlüsselsatz spezifiziert jetzt auch zwei neue Funktionen: \(\mathrm{Enc}\) und \(\mathrm{Dec}\) - \(\mathrm{Enc}\) entspricht einfach der Funktion \(\mathrm{Enc}\) des Primärschlüssels des Schlüsselsatzes, während die Funktion versucht, \(\mathrm{Dec}\) mit allen Schlüsseln zu entschlüsseln, und geht sie in einer bestimmten Reihenfolge durch (siehe unten, wie Tink die Leistung verbessert).

Interessanterweise handelt es sich bei Keysets um vollständige Schlüssel: Sie stellen eine vollständige Beschreibung der verwendeten Funktionen \(\mathrm{Enc}\) und\(\mathrm{Dec}\) dar. Das bedeutet, dass Nutzer eine Klasse schreiben können, die als Eingabe ein KeysetHandle annimmt, um zu verdeutlichen, dass die Klasse eine vollständige Beschreibung der Objekte \(\mathrm{Enc}\) benötigt und \(\mathrm{Dec}\) wie sie ordnungsgemäß funktioniert. Dadurch können Nutzer APIs schreiben, die Folgendes kommunizieren: Um diese Klasse verwenden zu können, müssen Sie mir die Beschreibung eines kryptografischen Primitives zur Verfügung stellen.

Schlüsselrotation

Stellen Sie sich einen Tink-Nutzer vor, der ein Programm schreibt, das zuerst ein Keyset von einem KMS abruft, dann ein AEAD-Objekt aus diesem Keyset erstellt und dieses Objekt schließlich zum Verschlüsseln und Entschlüsseln von Geheimtexten verwendet.

Ein solcher Nutzer ist automatisch auf die Schlüsselrotation und den Wechsel der Algorithmen vorbereitet, falls seine aktuelle Auswahl nicht mehr dem Standard entspricht.

Bei der Implementierung einer solchen Schlüsselrotation muss jedoch mit etwas Vorsicht vorgegangen werden: Zuerst sollte der KMS einen neuen Schlüssel zum Keyset hinzufügen (aber noch nicht als primären Schlüssel festlegen). Anschließend muss das neue Keyset für alle Binärprogramme bereitgestellt werden, sodass jedes Binärprogramm, das diesen Keyset verwendet, den neuesten Schlüssel im Keyset hat. Nur dann sollte der neue Schlüssel als primärer Schlüssel festgelegt werden und das resultierende Keyset wird mithilfe des Keysets wieder an alle Binärprogramme verteilt.

Schlüsselkennungen in Geheimtexten

Nehmen wir wieder das Beispiel eines AEAD-Schlüsselsatzes. Wenn dies ohne Umstände geschieht, muss Tink versuchen, einen Geheimtext mit allen Schlüsseln im Schlüsselsatz zu entschlüsseln, da nicht festgestellt werden kann, welcher Schlüssel zum Verschlüsseln des Schlüsselsatzes verwendet wurde. Dies kann zu einem hohen Leistungsaufwand führen.

Aus diesem Grund ist es in Tink möglich, Geheimtexten einen 5-Byte-String voranzustellen, der von der ID abgeleitet ist. Gemäß der oben beschriebenen Philosophie der vollständigen Schlüssel ist dieses Präfix Teil des Schlüssels. Alle Geheimtexte, die jemals mit diesem Schlüssel abgeleitet wurden, sollten dieses Präfix haben. Wenn Nutzer Schlüssel erstellen, können sie auswählen, ob der Schlüssel ein solches Präfix verwenden soll oder ob ein Geheimtextformat ohne dieses Präfix verwendet werden soll.

Wenn sich ein Schlüssel in einem Keyset befindet, berechnet Tink dieses Tag anhand der ID, die der Schlüssel im Keyset hat. Die Tatsache, dass die IDs innerhalb eines Schlüsselsatzes eindeutig sind2, deutet darauf hin, dass die Tags eindeutig sind. Wenn also nur getaggte Schlüssel verwendet werden, gibt es gegenüber der Entschlüsselung mit einem einzigen Schlüssel keinen Leistungsverlust: Tink muss beim Entschlüsseln nur einen der Schlüssel ausprobieren.

Da das Tag jedoch Teil des Schlüssels ist, bedeutet dies auch, dass der Schlüssel nur dann in einem Keyset enthalten sein kann, wenn er eine bestimmte ID hat. Dies hat einige Auswirkungen auf die Implementierung von Schlüsselobjekten in verschiedenen Sprachen.


  1. Einige Teile von Tink behandeln Keysets immer noch als Set. Dies sollte jedoch geändert werden. Der Grund dafür ist, dass die Reihenfolge im Allgemeinen wichtig ist. Betrachten Sie beispielsweise den typischen Lebenszyklus einer Schlüsselrotation mit Aead. Zuerst wird einem Keyset ein neuer Schlüssel hinzugefügt. Dieser Schlüssel wurde noch nicht als primärer Schlüssel festgelegt, sondern aktiv. Dieser neue Schlüsselsatz wird für alle Binärprogramme eingeführt. Sobald alle Binärprogramme den neuen Schlüssel kennen, wird der Schlüssel als primärer Schlüssel festgelegt (nur die Verwendung dieses Schlüssels ist zu diesem Zeitpunkt sicher). In diesem zweiten Schritt muss der Schlüsselrotation der zuletzt hinzugefügte Schlüssel bekannt sein. 

  2. Zur Kompatibilität mit einer internen Bibliothek von Google ermöglicht Tink die Verwendung von Keysets, in denen IDs wiederholt werden. Diese Unterstützung wird in Zukunft entfernt.