跳到主要内容
跳到主要内容

加密函数

这些函数使用 AES(高级加密标准)算法实现数据的加密和解密。

密钥长度取决于加密模式:-128--196--256- 模式分别为 162432 字节长。

初始化向量的长度始终为 16 字节(超过 16 字节的字节将被忽略)。

aes_decrypt_mysql

引入于:v20.12

解密由 MySQL 的 AES_ENCRYPT 函数加密的数据。

对于相同的输入,产生与 decrypt 相同的明文。 当 keyiv 长度超过正常情况时,aes_decrypt_mysql 将遵循 MySQL 的 aes_decrypt 所做的,即“折叠” key 并忽略 IV 的多余位。

支持以下解密模式:

  • 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 数据

-- Let's decrypt data we've previously encrypted with 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    │
└───────────┘

aes_encrypt_mysql

引入于:v20.12

以与 MySQL 的 AES_ENCRYPT 函数相同的方式加密文本。 生成的密文可以使用 MySQL 的 AES_DECRYPT 函数解密。 对于相同的输入,产生与 encrypt 函数相同的密文。 当 keyiv 长度超过正常情况时,aes_encrypt_mysql 将遵循 MySQL 的 aes_encrypt 所做的,即“折叠” key 并忽略 iv 的多余位。

支持的加密模式包括:

  • 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 — 加密密钥。如果密钥长度超过 mode 的要求,将执行 MySQL 特定的密钥折叠。 String
  • iv — 可选。初始化向量。仅考虑前 16 个字节。 String

返回值

密文二进制字符串。 String

示例

相等输入比较

-- Given equal input encrypt and aes_encrypt_mysql produce the same ciphertext:
SELECT encrypt('aes-256-ofb', 'Secret', '12345678910121314151617181920212', 'iviviviviviviviv') = aes_encrypt_mysql('aes-256-ofb', 'Secret', '12345678910121314151617181920212', 'iviviviviviviviv') AS ciphertexts_equal;
┌─ciphertexts_equal─┐
│                 1 │
└───────────────────┘

使用长密钥时加密失败

-- But encrypt fails when key or iv is longer than expected:
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').

MySQL 兼容性

-- aes_encrypt_mysql produces MySQL-compatible output:
SELECT hex(aes_encrypt_mysql('aes-256-ofb', 'Secret', '123456789101213141516171819202122', 'iviviviviviviviv123')) AS ciphertext;
┌─ciphertext───┐
│ 24E9E4966469 │
└──────────────┘

较长的 IV 产生相同的结果

-- Notice how supplying even longer IV produces the same result
SELECT hex(aes_encrypt_mysql('aes-256-ofb', 'Secret', '123456789101213141516171819202122', 'iviviviviviviviv123456')) AS ciphertext
┌─ciphertext───┐
│ 24E9E4966469 │
└──────────────┘

decrypt

引入于:v20.12

该函数使用以下模式解密 AES 加密的二进制字符串:

  • 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
  • aes-128-cfb, aes-128-cfb1, aes-128-cfb8

语法

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

参数

  • mode — 解密模式。 String
  • ciphertext — 需要解密的加密文本。 String
  • key — 解密密钥。 String
  • iv — 初始化向量。对于 -gcm 模式是必需的,其他模式为可选。 String
  • aad — 附加认证数据。如果此值不正确,则不会解密。仅在 -gcm 模式中有效,其他模式抛出异常。 String

返回值

返回解密后的明文。 String

示例

正确解密加密数据

-- Re-using the table from the encrypt function example
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
-- Notice how only a portion of the data was properly decrypted, and the rest is gibberish since either `mode`, `key`, or `iv` were different upon encryption.
┌─comment──────────────┬─plaintext──┐
│ aes-256-gcm          │ OQ�E
                             �t�7T�\���\�   │
│ aes-256-gcm with AAD │ OQ�E
                             �\��si����;�o�� │
└──────────────────────┴────────────┘
┌─comment──────────────────────────┬─plaintext─┐
│ aes-256-ofb no IV                │ Secret    │
│ aes-256-ofb no IV, different key │ �4�
                                        �         │
│ aes-256-ofb with IV              │ ���6�~        │
│aes-256-cbc no IV                │ �2*4�h3c�4w��@
└──────────────────────────────────┴───────────┘

encrypt

引入于:v20.12

使用 AES 以以下模式之一将明文加密为密文:

  • 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
  • aes-128-cfb, aes-128-cfb1, aes-128-cfb8

语法

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 = MergeTree;

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 │
└──────────────────────┴──────────────────────────────────────────────┘

tryDecrypt

引入于:v22.10

类似于 decrypt 函数,但当使用错误的密钥时,如果解密失败则返回 NULL

语法

tryDecrypt(mode, ciphertext, key[, iv, aad])

参数

  • mode — 解密模式。 String
  • ciphertext — 需要解密的加密文本。 String
  • key — 解密密钥。 String
  • iv — 可选。初始化向量。对于 -gcm 模式是必需的,其他模式为可选。 String
  • aad — 可选。附加认证数据。如果此值不正确,则不会解密。仅在 -gcm 模式中有效,对于其他模式抛出异常。 String

返回值

返回解密后的字符串,如果解密失败则返回 NULLNullable(String)

示例

创建表并插入数据

-- Let's create a table where user_id is the unique user id, encrypted is an encrypted string field, iv is an initial vector for decrypt/encrypt.
-- Assume that users know their id and the key to decrypt the encrypted field:
CREATE TABLE decrypt_null
(
    dt DateTime,
    user_id UInt32,
    encrypted String,
    iv String
)
ENGINE = MergeTree;

-- Insert some data:
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');

-- Try decrypt with one key
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 │ ᴺᵁᴸᴸ   │
└─────────────────────┴─────────┴────────┘