鍵セット

Tink は Keyset を使用して、鍵のローテーションを有効にします。鍵セットは形式上、空でない鍵のリスト1 で、そのうちの 1 つの鍵が主キーとして指定されます(たとえば、新しい平文の署名と暗号化に使用される鍵)。また、キーセット内のキーは、一意の ID2 とキーのステータスを取得します。これにより、キーセットから削除することなくキーを無効にできます。

キーセットは、ユーザーが(クラス KeysetHandle を介して)キーにアクセスするための主要な方法です。これにより、すべてのユーザーに一度に複数のキーを処理するコードを指定できます。暗号を使用するほとんどのユーザーにとって、複数の鍵を処理することが必要です。鍵を変更できる必要があります(古い鍵が漏洩するなど)。また、コードが実行されるマシンとすべての暗号テキストにアトミックな「次の鍵への切り替え」がグローバルかつ瞬時に適用されることはほとんどありません。そのため、あるキーから次のキーに変更したときに機能するコードを記述する必要があります。

例: AEAD

AEAD プリミティブ用の複数の鍵を含む AEAD 鍵セットについて考えてみましょう。前述のように、各キーは 2 つの関数( \(\mathrm{Enc}\) と \(\mathrm{Dec}\))を一意に指定します。鍵セットでは、2 つの新しい関数も指定されるようになりました。 \(\mathrm{Enc}\) と \(\mathrm{Dec}\) - \(\mathrm{Enc}\) は単に鍵セットの主キーの関数と等しい \(\mathrm{Enc}\) で、関数はすべての鍵を使用して \(\mathrm{Dec}\) 復号しようとします(このパフォーマンスの向上については以下をご覧ください)。

興味深いことに、キーセットは完全なキーであり、使用される関数 \(\mathrm{Enc}\) と\(\mathrm{Dec}\) が完全に説明されています。つまり、ユーザーは KeysetHandle を入力として受け取るクラスを作成できるため、クラスにはオブジェクトの詳しい説明 \(\mathrm{Enc}\) と \(\mathrm{Dec}\) 適切に機能させる必要があるという考えを表現できます。これによりユーザーは、それを伝える API を作成できます。このクラスを使用するには、暗号プリミティブの説明を提供する必要があります。

鍵のローテーション

まず KMS から鍵セットを取得してから AEAD オブジェクトを作成し、このオブジェクトを使用して暗号テキストの暗号化と復号を行うプログラムを作成する Tink ユーザーについて考えてみましょう。

このようなユーザーは、鍵のローテーションに向けて自動的に準備されます。また、現在の選択が基準を満たさなくなった場合はアルゴリズムを切り替えることもできます。

ただし、このような鍵のローテーションを実装する場合は、やや注意が必要です。まず、KMS が新しい鍵を鍵セットに追加する必要があります(ただし、まだメインの鍵として設定しないでください)。次に、この鍵セットを使用するすべてのバイナリが鍵セット内の最新の鍵を持つように、新しい鍵セットをすべてのバイナリにロールアウトする必要があります。その場合にのみ、新しい鍵を主キーにして、生成された鍵セットをその鍵セットを使用してすべてのバイナリに配布します。

暗号テキストの鍵識別子

もう一度 AEAD 鍵セットの例を考えてみましょう。単純に暗号テキストを復号すると、Tink は鍵セット内のすべての鍵で復号を試みる必要があります。鍵セットの暗号化に使用された鍵を確認する方法はありません。これにより、パフォーマンスのオーバーヘッドが大きくなる可能性があります。

このため、Tink では、ID から派生した 5 バイトの文字列を暗号テキストの先頭に付加できます。上記の「完全鍵」の原則に従い、この接頭辞は鍵の一部であり、この鍵で派生したすべての暗号テキストには、この接頭辞が必要です。ユーザーは、鍵を作成するときに、このような接頭辞を使用するのか、または接頭辞のない暗号テキスト形式を使用するのかを選択できます。

鍵が鍵セット内にある場合、Tink は鍵が鍵セット内にある ID からこのタグを計算します。キーセット内で ID が一意2であるということは、タグが一意であることを意味します。したがって、タグ付けされた鍵のみを使用する場合は、1 つの鍵で復号する場合と比べてパフォーマンスは低下しません。Tink は復号時にいずれかの鍵を試すだけで済みます。

ただし、タグは鍵の一部であるため、特定の ID が 1 つある場合にのみ鍵を鍵セットに含めることもできます。このことは、さまざまな言語で鍵オブジェクトの実装を記述する場合になんらかの影響を及ぼします。


  1. Tink の一部では、引き続き Keyset がセットとして扱われます。ただし、これは変更する必要があります。その理由は、一般的に順序が重要であるためです。たとえば、Aead による鍵のローテーションの一般的なライフサイクルを考えてみましょう。まず、新しい鍵が鍵セットに追加されます。この鍵はまだプライマリに設定されていませんが、アクティブになっています。この新しい鍵セットは、すべてのバイナリに展開されます。すべてのバイナリが新しい鍵を認識すると、鍵がメインになります(この時点でのみ、この鍵を使用して安全になります)。この 2 つ目のステップでは、鍵のローテーションが最後に追加された鍵を認識している必要があります。 

  2. Google 内部ライブラリとの互換性を確保するため、Tink では、ID が繰り返されるキーセットを設定できます。このサポートは今後削除される予定です。