鍵セット

Tink は Keyset を使用して鍵のローテーションを有効にします。正式には、鍵セットは、1 つの鍵がプライマリ(新しい平文の署名と暗号化に使用される鍵など)として指定された、空ではない鍵のリスト1 です。また、キーセット内の鍵には一意の ID 2 と鍵のステータスが割り当てられます。これにより、鍵セットから鍵を削除せずに鍵を無効にできます。

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

例: AEAD

AEAD プリミティブの複数の鍵を含む AEAD キーセットについて考えてみましょう。前述のように、各キーは \(\mathrm{Enc}\) と \(\mathrm{Dec}\)の 2 つの関数を一意に指定します。キーセットには、 \(\mathrm{Enc}\) と \(\mathrm{Dec}\) の 2 つの新しい関数も指定されます。 \(\mathrm{Enc}\) はキーセットのプライマリ キーの関数 \(\mathrm{Enc}\) に等しく、 \(\mathrm{Dec}\) 関数はすべてのキーで復号を試みて、キーを順番に処理します(Tink がこのパフォーマンスを改善する方法については、下記をご覧ください)。

鍵セットは完全な鍵です。つまり、使用される関数 \(\mathrm{Enc}\) と\(\mathrm{Dec}\) の完全な記述です。つまり、ユーザーは KeysetHandle を入力として受け取るクラスを記述できます。これは、クラスがオブジェクトの完全な記述 \(\mathrm{Enc}\) と \(\mathrm{Dec}\) を必要とすることを表します。これにより、ユーザーは、このクラスを使用するには暗号プリミティブの説明を提供する必要があることを伝える API を作成できます。

鍵のローテーション

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

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

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

暗号文内の鍵識別子

AEAD キーセットの例をもう一度見てみましょう。ナイーブに暗号テキストを復号する場合、キーセットの暗号化に使用された鍵を把握する方法がないため、Tink はキーセット内のすべての鍵で復号を試みる必要があります。これにより、大きなパフォーマンス オーバーヘッドが発生する可能性があります。

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

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

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


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

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