这些函数使用 AES (高级加密标准) 算法对数据进行加密和解密。
密钥长度取决于加密模式:-128-、-196- 和 -256- 模式分别对应 16、24 和 32 字节。
初始化向量的长度始终为 16 字节 (超过 16 字节的部分将被忽略) 。
HMAC
引入版本:v25.12.0
使用指定的哈希算法和密钥,为给定消息计算 HMAC (基于哈希的消息认证码) 。
支持的哈希算法:
- blake2b512
- blake2s256
- md4
- md5
- md5-sha1
- mdc2
- ripemd (别名:RIPEMD160、ripemd)
- ripemd160
- rmd160 (别名:RIPEMD160、rmd160)
- sha1
- sha224
- sha256
- sha3-224
- sha3-256
- sha3-384
- sha3-512
- sha384
- sha512
- sha512-224
- sha512-256
- shake128
- shake256
- sm3
- ssl3-md5 (别名:MD5、ssl3-md5)
- ssl3-sha1 (别名:SHA1、ssl3-sha1)
- whirlpool
语法
HMAC(mode, message, key)参数
mode— 哈希算法名称 (不区分大小写) 。支持:md5、sha1、sha224、sha256、sha384、sha512。Stringmessage— 待认证的消息。Stringkey— 用于 HMAC 的密钥。String
返回值
返回包含 HMAC 摘要的二进制字符串。String
示例
基本 HMAC-SHA256
SELECT hex(HMAC('sha256', 'The quick brown fox jumps over the lazy dog', 'secret_key'));┌─hex(HMAC('sha256', 'The quick brown fox jumps over the lazy dog', [HIDDEN id: 1]))─┐
│ 31FD15FA0F61FD40DC09D919D4AA5B4141A0B27C1D51E74A6789A890AAAA187C │
└────────────────────────────────────────────────────────────────────────────────────┘不同的哈希算法
SELECT
hex(HMAC('md5', 'message', 'key')) AS hmac_md5,
hex(HMAC('sha1', 'message', 'key')) AS hmac_sha1,
hex(HMAC('sha256', 'message', 'key')) AS hmac_sha256;┌─hmac_md5─────────────────────────┬─hmac_sha1────────────────────────────────┬─hmac_sha256──────────────────────────────────────────────────────┐
│ 4E4748E62B463521F6775FBF921234B5 │ 2088DF74D5F2146B48146CAF4965377E9D0BE3A4 │ 6E9EF29B75FFFC5B7ABAE527D58FDADB2FE42E7219011976917343065F58ED4A │
└──────────────────────────────────┴──────────────────────────────────────────┴──────────────────────────────────────────────────────────────────┘不区分大小写模式
SELECT
hmac('SHA256', 'message', 'key') = HMAC('sha256', 'message', 'key') AS same_result,
HMAC('SHA256', 'message', 'key') = Hmac('Sha256', 'message', 'key') AS also_same;┌─same_result─┬─also_same─┐
│ 1 │ 1 │
└─────────────┴───────────┘aes_decrypt_mysql
版本引入:v20.12.0
用于解密由 MySQL 的 AES_ENCRYPT 函数加密的数据。
对于相同的输入,它生成的明文与 decrypt 相同。
当 key 或 iv 的长度超过正常应有的长度时,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])参数
返回值
返回解密后的 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.0
以与 MySQL 的 AES_ENCRYPT 函数相同的方式加密文本。
生成的密文可使用 MySQL 的 AES_DECRYPT 函数解密。
对于相同的输入,它生成的密文与 encrypt 函数相同。
当 key 或 iv 的长度超过其通常应有的长度时,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— 加密模式。Stringplaintext— 要加密的明文。Stringkey— 加密密钥。如果密钥长度超过mode要求的长度,则会执行 MySQL 特有的密钥折叠。Stringiv— 可选。初始化向量。只有前 16 个字节会被使用。String
返回值
密文二进制字符串。String
示例
相同输入的比较
-- 在输入相同的情况下,encrypt 和 aes_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 │
└───────────────────┘长密钥会导致加密失败
-- 但当 key 或 iv 超过预期长度时,encrypt 会失败:
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 生成与 MySQL 兼容的输出:
SELECT hex(aes_encrypt_mysql('aes-256-ofb', 'Secret', '123456789101213141516171819202122', 'iviviviviviviviv123')) AS ciphertext;┌─ciphertext───┐
│ 24E9E4966469 │
└──────────────┘更长的 IV 也会得到相同的结果
-- 注意,即使提供更长的 IV,结果也相同
SELECT hex(aes_encrypt_mysql('aes-256-ofb', 'Secret', '123456789101213141516171819202122', 'iviviviviviviviv123456')) AS ciphertext┌─ciphertext───┐
│ 24E9E4966469 │
└──────────────┘decrypt
引入版本:v20.12.0
此函数使用以下模式对经 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— 解密模式。Stringciphertext— 待解密的密文。Stringkey— 解密密钥。Stringiv— 初始化向量。在-gcm模式下为必填项,其他模式下可选。Stringaad— 附加认证数据。若此值不正确,则无法解密。仅适用于-gcm模式;用于其他模式时会抛出异常。String
返回值
返回解密后的明文。String
示例
正确解密已加密的数据
CREATE TABLE encryption_test
(
`comment` String,
`secret` String
)
ENGINE = MergeTree
ORDER BY tuple();
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 │
└──────────────────────────────────┴──────────────────────────────────┘错误解密已加密数据
SELECT comment, hex(decrypt('aes-256-cfb8', secret, '12345678910121314151617181920212')) AS plaintext FROM encryption_testaes-256-ofb no IV 53A69A28E815
aes-256-ofb no IV, different key C86BD2404D8A
aes-256-ofb with IV B9658159142A
aes-256-cbc no IV FC552E5096F1455997B2732FB31DCFEBencrypt
引入版本:v20.12.0
使用以下任一 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— 加密模式。Stringplaintext— 要加密的文本。Stringkey— 加密密钥。Stringiv— 初始化向量。在-gcm模式下为必填项,其他模式下可选。Stringaad— 附加认证数据。它不会被加密,但会影响解密结果。仅在-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.0
与 decrypt 函数类似,但在使用错误的密钥导致解密失败时,会返回 NULL。
语法
tryDecrypt(mode, ciphertext, key[, iv, aad])参数
mode— 解密模式。Stringciphertext— 需要解密的密文。Stringkey— 解密密钥。Stringiv— 可选。初始化向量。-gcm模式下必需,其他模式下可选。Stringaad— 可选。附加认证数据。如果该值不正确,则无法解密。仅适用于-gcm模式;用于其他模式时会抛出异常。String
返回值
返回解密后的 String;如果解密失败,则返回 NULL。Nullable(String)
示例
创建表并插入数据
-- 创建一个表,其中 user_id 是唯一用户 ID,encrypted 是加密字符串字段,iv 是用于解密/加密的初始向量。
-- 假设用户知道自己的 ID 以及用于解密 encrypted 字段的密钥:
CREATE TABLE decrypt_null
(
dt DateTime,
user_id UInt32,
encrypted String,
iv String
)
ENGINE = MergeTree;
-- 插入一些数据:
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 │ ᴺᵁᴸᴸ │
└─────────────────────┴─────────┴────────┘