ClickHouse/docs/ja/sql-reference/functions/encryption-functions.md
2024-11-18 11:58:58 +09:00

15 KiB
Raw Blame History

slug sidebar_position sidebar_label
/ja/sql-reference/functions/encryption-functions 70 暗号化

これらの関数は、AESAdvanced Encryption Standardアルゴリズムを使用してデータの暗号化および復号化を実装します。

キーの長さは暗号化モードに依存します。-128-モードは16バイト、-196-モードは24バイト、-256-モードは32バイトの長さです。

初期化ベクトルの長さは常に16バイトです余分なバイトは無視されます

これらの関数はClickHouse 21.1までは動作が遅いことに注意してください。

encrypt

この関数は以下のモードでデータを暗号化します:

  • aes-128-ecb, aes-192-ecb, aes-256-ecb
  • aes-128-cbc, aes-192-cbc, aes-256-cbc
  • aes-128-ofb, aes-192-ofb, aes-256-ofb
  • aes-128-gcm, aes-192-gcm, aes-256-gcm
  • aes-128-ctr, aes-192-ctr, aes-256-ctr

構文

encrypt('mode', 'plaintext', 'key' [, iv, aad])

引数

  • mode — 暗号化モード。String
  • plaintext — 暗号化されるべきテキスト。String
  • key — 暗号化キー。String
  • iv — 初期化ベクトル。-gcmモードで必要、他のモードではオプション。String
  • aad — 追加の認証データ。暗号化はされませんが、復号化に影響します。-gcmモードでのみ動作し、他のモードでは例外をスローします。String

戻り値

  • 暗号文バイナリ文字列。String

このテーブルを作成します:

クエリ:

CREATE TABLE encryption_test
(
    `comment` String,
    `secret` String
)
ENGINE = Memory;

データを挿入しますキーやIVをデータベースに保存することは暗号化の概念を損なうため避けてください、また'ヒント'を保存するのも安全ではなく、ここでは説明のためだけに使われます):

クエリ:

INSERT INTO encryption_test VALUES('aes-256-ofb no IV', encrypt('aes-256-ofb', 'Secret', '12345678910121314151617181920212')),\
('aes-256-ofb no IV, different key', encrypt('aes-256-ofb', 'Secret', 'keykeykeykeykeykeykeykeykeykeyke')),\
('aes-256-ofb with IV', encrypt('aes-256-ofb', 'Secret', '12345678910121314151617181920212', 'iviviviviviviviv')),\
('aes-256-cbc no IV', encrypt('aes-256-cbc', 'Secret', '12345678910121314151617181920212'));

クエリ:

SELECT comment, hex(secret) FROM encryption_test;

結果:

┌─comment──────────────────────────┬─hex(secret)──────────────────────┐
│ aes-256-ofb no IV                │ B4972BDC4459                     │
│ aes-256-ofb no IV, different key │ 2FF57C092DC9                     │
│ aes-256-ofb with IV              │ 5E6CB398F653                     │
│ aes-256-cbc no IV                │ 1BC0629A92450D9E73A00E7D02CF4142 │
└──────────────────────────────────┴──────────────────────────────────┘

-gcmでの例:

クエリ:

INSERT INTO encryption_test VALUES('aes-256-gcm', encrypt('aes-256-gcm', 'Secret', '12345678910121314151617181920212', 'iviviviviviviviv')), \
('aes-256-gcm with AAD', encrypt('aes-256-gcm', 'Secret', '12345678910121314151617181920212', 'iviviviviviviviv', 'aad'));

SELECT comment, hex(secret) FROM encryption_test WHERE comment LIKE '%gcm%';

結果:

┌─comment──────────────┬─hex(secret)──────────────────────────────────┐
│ aes-256-gcm          │ A8A3CCBC6426CFEEB60E4EAE03D3E94204C1B09E0254 │
│ aes-256-gcm with AAD │ A8A3CCBC6426D9A1017A0A932322F1852260A4AD6837 │
└──────────────────────┴──────────────────────────────────────────────┘

aes_encrypt_mysql

MySQLの暗号化と互換があり、結果として得られる暗号文はAES_DECRYPT関数で復号化できます。

同じ入力でencryptと同じ暗号文を生成します。ただし、keyまたはivが通常よりも長い場合、aes_encrypt_mysqlはMySQLのaes_encryptに従い、keyを折りたたんで余分なビットを無視します。

サポートされている暗号化モード:

  • aes-128-ecb, aes-192-ecb, aes-256-ecb
  • aes-128-cbc, aes-192-cbc, aes-256-cbc
  • aes-128-ofb, aes-192-ofb, aes-256-ofb

構文

aes_encrypt_mysql('mode', 'plaintext', 'key' [, iv])

引数

  • mode — 暗号化モード。String
  • plaintext — 暗号化されるべきテキスト。String
  • key — 暗号化キー。モードが要求するよりも長い場合、MySQL固有のキーの折りたたみが行われます。String
  • iv — 初期化ベクトル。オプションで、最初の16バイトのみが考慮されます。String

戻り値

  • 暗号文バイナリ文字列。String

等しい入力でencryptaes_encrypt_mysqlは同じ暗号文を生成します:

クエリ:

SELECT encrypt('aes-256-ofb', 'Secret', '12345678910121314151617181920212', 'iviviviviviviviv') = aes_encrypt_mysql('aes-256-ofb', 'Secret', '12345678910121314151617181920212', 'iviviviviviviviv') AS ciphertexts_equal;

結果:

┌─ciphertexts_equal─┐
│                 1 │
└───────────────────┘

しかし、encryptkeyまたはivが予想よりも長い場合に失敗します:

クエリ:

SELECT encrypt('aes-256-ofb', 'Secret', '123456789101213141516171819202122', 'iviviviviviviviv123');

結果:

Received exception from server (version 22.6.1):
Code: 36. DB::Exception: Received from localhost:9000. DB::Exception: Invalid key size: 33 expected 32: While processing encrypt('aes-256-ofb', 'Secret', '123456789101213141516171819202122', 'iviviviviviviviv123').

一方、aes_encrypt_mysqlはMySQL互換の出力を生成します

クエリ:

SELECT hex(aes_encrypt_mysql('aes-256-ofb', 'Secret', '123456789101213141516171819202122', 'iviviviviviviviv123')) AS ciphertext;

結果:

┌─ciphertext───┐
│ 24E9E4966469 │
└──────────────┘

さらに長いIVを提供しても同じ結果が得られることに注意してください。

クエリ:

SELECT hex(aes_encrypt_mysql('aes-256-ofb', 'Secret', '123456789101213141516171819202122', 'iviviviviviviviv123456')) AS ciphertext

結果:

┌─ciphertext───┐
│ 24E9E4966469 │
└──────────────┘

これは、同じ入力でMySQLが生成するものとバイナリで等しいです

mysql> SET  block_encryption_mode='aes-256-ofb';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT aes_encrypt('Secret', '123456789101213141516171819202122', 'iviviviviviviviv123456') as ciphertext;
+------------------------+
| ciphertext             |
+------------------------+
| 0x24E9E4966469         |
+------------------------+
1 row in set (0.00 sec)

decrypt

この関数は、以下のモードで暗号文を平文に復号します:

  • aes-128-ecb, aes-192-ecb, aes-256-ecb
  • aes-128-cbc, aes-192-cbc, aes-256-cbc
  • aes-128-ofb, aes-192-ofb, aes-256-ofb
  • aes-128-gcm, aes-192-gcm, aes-256-gcm
  • aes-128-ctr, aes-192-ctr, aes-256-ctr

構文

decrypt('mode', 'ciphertext', 'key' [, iv, aad])

引数

  • mode — 復号化モード。String
  • ciphertext — 復号化されるべき暗号化テキスト。String
  • key — 復号化キー。String
  • iv — 初期化ベクトル。-gcmモードで必要、他のモードではオプション。String
  • aad — 追加の認証データ。この値が正しくないと復号化できません。-gcmモードでのみ動作し、他のモードでは例外をスローします。String

戻り値

  • 復号化された文字列。String

encryptのテーブルを再利用します。

クエリ:

SELECT comment, hex(secret) FROM encryption_test;

結果:

┌─comment──────────────┬─hex(secret)──────────────────────────────────┐
│ aes-256-gcm          │ A8A3CCBC6426CFEEB60E4EAE03D3E94204C1B09E0254 │
│ aes-256-gcm with AAD │ A8A3CCBC6426D9A1017A0A932322F1852260A4AD6837 │
└──────────────────────┴──────────────────────────────────────────────┘
┌─comment──────────────────────────┬─hex(secret)──────────────────────┐
│ aes-256-ofb no IV                │ B4972BDC4459                     │
│ aes-256-ofb no IV, different key │ 2FF57C092DC9                     │
│ aes-256-ofb with IV              │ 5E6CB398F653                     │
│ aes-256-cbc no IV                │ 1BC0629A92450D9E73A00E7D02CF4142 │
└──────────────────────────────────┴──────────────────────────────────┘

次に、このデータをすべて復号化してみましょう。

クエリ:

SELECT comment, decrypt('aes-256-cfb128', secret, '12345678910121314151617181920212') as plaintext FROM encryption_test

結果:

┌─comment──────────────┬─plaintext──┐
│ aes-256-gcm          │ OQ<4F>E
                             <20>t<EFBFBD>7T<37>\<5C><><EFBFBD>\<5C>   │
│ aes-256-gcm with AAD │ OQ<4F>E
                             <20>\<5C><>si<73><69><EFBFBD><EFBFBD>;<3B>o<EFBFBD><6F> │
└──────────────────────┴────────────┘
┌─comment──────────────────────────┬─plaintext─┐
│ aes-256-ofb no IV                │ Secret    │
│ aes-256-ofb no IV, different key │ <20>4<EFBFBD>
                                        <20>         │
│ aes-256-ofb with IV              │ <20><><EFBFBD>6<EFBFBD>~        │
 │aes-256-cbc no IV                │ <20>2*4<>h3c<33>4w<34><77>@
└──────────────────────────────────┴───────────┘

モード、キー、またはIVが暗号化時に異なっていたため、データの一部のみが適切に復号化され、残りは意味不明な文字となっています。

tryDecrypt

decryptと似ていますが、不正なキーを使用したために復号化に失敗した場合、NULLを返します。

user_idがユニークなユーザーIDであり、encryptedが暗号化された文字列フィールド、ivが暗号化・復号化の初期ベクトルのテーブルを作成してみましょう。ユーザーは自分のIDと暗号化されたフィールドを復号化するためのキーを知っていると仮定します

CREATE TABLE decrypt_null (
  dt DateTime,
  user_id UInt32,
  encrypted String,
  iv String
) ENGINE = Memory;

データの挿入:

INSERT INTO decrypt_null VALUES
    ('2022-08-02 00:00:00', 1, encrypt('aes-256-gcm', 'value1', 'keykeykeykeykeykeykeykeykeykey01', 'iv1'), 'iv1'),
    ('2022-09-02 00:00:00', 2, encrypt('aes-256-gcm', 'value2', 'keykeykeykeykeykeykeykeykeykey02', 'iv2'), 'iv2'),
    ('2022-09-02 00:00:01', 3, encrypt('aes-256-gcm', 'value3', 'keykeykeykeykeykeykeykeykeykey03', 'iv3'), 'iv3');

クエリ:

SELECT
    dt,
    user_id,
    tryDecrypt('aes-256-gcm', encrypted, 'keykeykeykeykeykeykeykeykeykey02', iv) AS value
FROM decrypt_null
ORDER BY user_id ASC

結果:

┌──────────────────dt─┬─user_id─┬─value──┐
│ 2022-08-02 00:00:00 │       1 │ ᴺᵁᴸᴸ   │
│ 2022-09-02 00:00:00 │       2 │ value2 │
│ 2022-09-02 00:00:01 │       3 │ ᴺᵁᴸᴸ   │
└─────────────────────┴─────────┴────────┘

aes_decrypt_mysql

MySQLの暗号化と互換性があり、データをAES_ENCRYPTで暗号化されたデータを復号化します。

等しい入力でdecryptと同じ平文を生成します。ただし、keyまたはivが通常よりも長い場合、aes_decrypt_mysqlはMySQLのaes_decryptに従い、keyを折りたたんで余分なビットを無視します。

サポートされている復号化モード:

  • aes-128-ecb, aes-192-ecb, aes-256-ecb
  • aes-128-cbc, aes-192-cbc, aes-256-cbc
  • aes-128-cfb128
  • aes-128-ofb, aes-192-ofb, aes-256-ofb

構文

aes_decrypt_mysql('mode', 'ciphertext', 'key' [, iv])

引数

  • mode — 復号化モード。String
  • ciphertext — 復号化されるべき暗号化テキスト。String
  • key — 復号化キー。String
  • iv — 初期化ベクトル。オプション。String

戻り値

  • 復号化された文字列。String

以前MySQLで暗号化したデータを復号化してみましょう

mysql> SET  block_encryption_mode='aes-256-ofb';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT aes_encrypt('Secret', '123456789101213141516171819202122', 'iviviviviviviviv123456') as ciphertext;
+------------------------+
| ciphertext             |
+------------------------+
| 0x24E9E4966469         |
+------------------------+
1 row in set (0.00 sec)

クエリ:

SELECT aes_decrypt_mysql('aes-256-ofb', unhex('24E9E4966469'), '123456789101213141516171819202122', 'iviviviviviviviv123456') AS plaintext

結果:

┌─plaintext─┐
│ Secret    │
└───────────┘