AEAD 暗号化のコンセプト

GoogleSQL for BigQuery は、関連データを伴う認証付き暗号化(AEAD)による暗号化をサポートしています。

このトピックでは、GoogleSQL での AEAD 暗号化の背後にあるコンセプトについて説明します。GoogleSQL でサポートされているさまざまな AEAD 暗号化関数の説明については、AEAD 暗号化関数をご覧ください。

AEAD 暗号化の目的

BigQuery では、データを保護するために保存データに暗号化を使用します。さらに、顧客管理の暗号鍵(CMEK)もサポートしているため、特定の暗号鍵を使用してテーブルを暗号化できます。ただし、場合によっては、テーブルに含まれる個々の値を暗号化する必要があります。

たとえば、すべての顧客のデータを共通の 1 つのテーブルで保持し、それぞれに異なる鍵を使用して各顧客のデータを暗号化しなければならない場合があります。その場合、データが複数のテーブルに分散されていれば、「暗号削除」を行うことができます。暗号消去(別名、暗号シュレディング)とは、暗号鍵を削除し、その暗号鍵を使って暗号化されたデータを判読不能にするプロセスを指します。

AEAD 暗号化関数を使用すると、暗号化と復号に使用する鍵からなる鍵セットを作成し、これらの鍵を使用してテーブル内の個々の値を暗号化および復号できます。また、鍵セットに含まれる鍵のローテーションを行うこともできます。

鍵セット

鍵セットは、1 つのプライマリ暗号鍵とそれ以外のセカンダリ暗号鍵からなる暗号鍵の集合です。各鍵には、暗号化アルゴリズムまたは復号アルゴリズムと、その鍵の状態(有効、無効、または破棄)がエンコードされます。破棄されない鍵の場合は、鍵のバイト自体もエンコードされます。プライマリ暗号鍵により、平文の入力テキストを暗号化する方法が決まります。プライマリ暗号鍵が無効状態になることはありません。セカンダリ暗号鍵は復号専用であり、有効または無効な状態のいずれかになります。鍵セットを使用して暗号化されたデータは、その鍵セットを使用して復号できます。

GoogleSQL の鍵セットは、シリアル化された google.crypto.tink.Keyset プロトコル バッファとして BYTES で表現されます。

次の例では、3 つの鍵からなる AEAD 鍵セットが JSON 文字列として表現されています。

{
  "primaryKeyId": 569259624,
  "key": [
    {
      "keyData": {
        "typeUrl": "type.googleapis.com/google.crypto.tink.AesGcmKey",
        "value": "GiDPhTp5gIhfnDb6jfKOT4SmNoriIJc7ah8uRvrCpdNihA==",
        "keyMaterialType": "SYMMETRIC"
      },
      "status": "ENABLED",
      "keyId": 569259624,
      "outputPrefixType": "TINK"
    },
    {
      "keyData": {
        "typeUrl": "type.googleapis.com/google.crypto.tink.AesGcmKey",
        "value": "GiBp6aU2cFbVfTh9dTQ1F0fqM+sGHXc56RDPryjAnzTe2A==",
        "keyMaterialType": "SYMMETRIC"
      },
      "status": "DISABLED",
      "keyId": 852264701,
      "outputPrefixType": "TINK"
    },
    {
      "status": "DESTROYED",
      "keyId": 237910588,
      "outputPrefixType": "TINK"
    }
  ]
}

上記の例では、プライマリ暗号鍵は ID が 569259624 に設定された、JSON 文字列の最初にリストされている鍵です。セカンダリ暗号鍵は 2 つあります。一方は ID 852264701 の無効状態にされた鍵、もう一方は ID 237910588 の破棄状態にされた鍵です。AEAD 暗号化関数で、この鍵セットを使用して暗号化すると、暗号文にはプライマリ暗号鍵の ID 569259624 がエンコードされます。

AEAD 関数でこの鍵セットを使用して復号するときは、暗号文にエンコードされた鍵 ID に基づいて、該当する復号鍵が選択されます。上記の例で、ID が 852264701 または 237910588 のいずれかの鍵を使用して復号しようとすると、エラーが発生します。ID 852264701 の鍵は無効化されていて、ID 237910588 の鍵は破棄されているためです。ID 852264701 の鍵を有効な状態に復元すると、この鍵を復号鍵として使用できるようになります。

鍵の種類により、その鍵で使用する暗号化モードが決まります。

同じ鍵セットを使用して複数の平文を暗号化すると、通常は平文ごとに異なる暗号テキストの値が返されます。OpenSSL が提供する擬似乱数ジェネレータを使用して選択された、それぞれに異なる初期化ベクトル(IV)が暗号化に使用されるためです。

ラップされた鍵セット

鍵セットを安全に管理する必要がある場合、または信頼できないチャネルを介して送信する必要がある場合は、ラップされた鍵セットの使用を検討してください。未加工の鍵セットをラップする場合、このプロセスは Cloud KMS 鍵を使用してそれを暗号化します。

ラップされた鍵セットを使用すると、鍵セットデータを公開することなく、データを暗号化および復号できます。フィールド レベルのデータへのアクセスを制限する別の方法があるかもしれませんが、ラップされた鍵セットは、未加工の鍵セットよりも安全な鍵セット管理メカニズムを提供します。

鍵セットと同様に、ラップされた鍵セットは定期的にローテーションできます。ラップされた鍵セットは AEAD エンベロープ暗号化関数で使用されます。

ラップされた鍵セットの例と関数の一部を以下に示します。

AES

AEAD 暗号化関数では Advanced Encryption Standard(AES)暗号化が使用されます。AES 暗号化は、入力としての平文とあわせて暗号鍵を取り、暗号化したバイトのシーケンスを出力として返します。このバイトのシーケンスは、暗号化に使用されたのと同じ鍵を使用して復号できます。AES が使用するブロックサイズは 16 バイトです。つまり、平文は 16 バイトのブロックのシーケンスとして扱われます。暗号テキストには、暗号化に使用された鍵を示す、Tink 固有の接頭辞が含まれます。AES 暗号化では複数のブロック暗号モードがサポートされています。

ブロック暗号モード

AEAD 暗号化関数でサポートされているブロック暗号モードには、GCM と CBC の 2 つがあります。

GCM

Galois/Counter Mode(GCM)は、AES 暗号化モードの 1 つです。このモードの関数は、ブロックに連番を付けてから、各ブロック番号に初期化ベクトル(IV)を結合します。初期化ベクトルとは、平文データをランダム化するベースとなるランダム値または疑似ランダム値です。次に、関数は結合されたブロック番号と IV を AES に従って暗号化します。この暗号化された結果に対してビット排他論理和(XOR)演算を行って、暗号テキストを生成します。GCM モードでは 128 ビットまたは 256 ビットの暗号鍵が使用されます。

CBC モード

CBC では、平文の各ブロックを直前の暗号テキスト ブロックに対して XOR 演算を行ってブロックを「チェーン化」した後、そのチェーンを暗号化します。CBC モードで使用する暗号鍵の長さは、128 ビット、192 ビット、256 ビットのいずれかです。CBC では初期ブロックとして 16 バイトの初期化ベクトルを使用します。この初期ブロックと最初の平文ブロックに対して XOR 演算を行います。

CBC モードはデータの完全性がないため、暗号の意味における AEAD スキームではありません。つまり、暗号化されたデータに対する悪意のある変更は検出されず、データの機密性も損なわれます。したがって、従来の理由から必要な場合を除き、CBC は推奨されません。

追加データ

AEAD 暗号化関数では、additional_data 引数の使用がサポートされています。この引数は Associated Data(AD)または追加認証データとも呼ばれます。暗号テキストを復号できるのは、暗号化に使用したものと同じ追加データが復号にも提供されている場合のみです。したがって、追加データを使用して、暗号テキストをコンテキストにバインドできます。

たとえば、特定のお客様のデータを暗号化するときに、additional_dataCAST(customer_id AS STRING) を出力できます。これにより、データを復号する際に、そのデータが想定された customer_id を使用して暗号化されたことを確認できます。暗号化に使われたのと同じ additional_data 値でなければ復号できないためです。詳細については、RFC 5116 をご覧ください。

復号

AEAD.ENCRYPT の出力は暗号テキスト BYTES です。この暗号テキストは、AEAD.DECRYPT_STRING 関数または AEAD.DECRYPT_BYTES 関数で復号できます。これらの関数では、暗号化に使用された鍵を含む鍵セットを使用する必要があります。その鍵は 'ENABLED' 状態でなければなりません。また、暗号化に使われたのと同じ additional_data を使用する必要もあります。

鍵セットが復号に使用されるときは、暗号テキストにエンコードされた鍵 ID に基づいて、該当する復号鍵が選択されます。

AEAD.DECRYPT_STRING は平文の文字列を出力する一方、AEAD.DECRYPT_BYTES は平文 BYTES を出力します。AEAD.DECRYPT_STRING は文字列値がエンコードされた暗号テキストを復号できます。AEAD.DECRYPT_BYTESBYTES 値がエンコードされた暗号テキストを復号できます。このいずれかの関数を使用して、誤ったデータ型がエンコードされた暗号テキストを復号すると(たとえば、AEAD.DECRYPT_STRING を使用して BYTES 値がエンコードされた暗号テキストを復号するなど)、動作が不定になり、エラーが発生する可能性があります。

鍵のローテーション

暗号鍵をローテーションする主な目的は、所定の鍵で暗号化されたデータの量を減らし、攻撃者が鍵を不正使用した場合にアクセス可能なデータを少なくすることです。

鍵セットのローテーションには、次の処理が必要です。

  1. すべての鍵セット内に新しいプライマリ暗号鍵を作成します。
  2. すべての暗号化データを復号してから再び暗号化します。

最初の処理には KEYS.ROTATE_KEYSET 関数または KEYS.ROTATE_WRAPPED_KEYSET を使用します。この関数は鍵セットに新しいプライマリ暗号鍵を追加し、古いプライマリ暗号鍵をセカンダリ暗号鍵に変更します。

Cloud KMS 鍵

GoogleSQL では、データをさらに保護するために、Cloud KMS の鍵を使用する AEAD 暗号化関数がサポートされています。この追加の保護レイヤにより、データ暗号鍵(DEK)が鍵暗号鍵(KEK)で暗号化されます。KEK は Cloud Key Management Service に安全に保存され、Cloud KMS の権限とロールを使用して管理される対称暗号鍵セットです。

クエリの実行時に、KEYS.KEYSET_CHAIN 関数を使用して、KEK の KMS リソースパスと、ラップされた DEK の暗号テキストを指定します。BigQuery が Cloud KMS を呼び出して DEK をラップ解除し、その鍵を使用してクエリのデータを復号します。ラップ解除された DEK のバージョンは、クエリの期間中のみメモリに保存され、その後破棄されます。

詳細については、Cloud KMS 鍵を使用した SQL の列レベルの暗号化をご覧ください。