PingKai Logo下载

加密与压缩函数

TiDB 支持大多数 MySQL 8.0 中的 加密与压缩函数。

支持的函数

名称描述
AES_DECRYPT()使用 AES 解密
AES_ENCRYPT()使用 AES 加密
COMPRESS()压缩并以二进制字符串返回结果
MD5()计算 MD5 校验和
PASSWORD()计算并返回密码字符串
RANDOM_BYTES()返回一个随机字节向量
SHA()计算 SHA-1 160 位校验和
SHA1()计算 SHA-1 160 位校验和
SHA2()计算 SHA-2 校验和
SM3()计算 SM3 校验和
UNCOMPRESS()解压缩已压缩的字符串
UNCOMPRESSED_LENGTH()返回压缩前字符串的长度
VALIDATE_PASSWORD_STRENGTH()校验密码强度

AES_DECRYPT()

AES_DECRYPT(data, key [,iv]) 函数用于解密之前使用相同 key 通过 AES_ENCRYPT() 函数加密的 data。

你可以通过 block_encryption_mode 系统变量选择 高级加密标准(AES) 的加密模式。

对于需要初始化向量的加密模式,可以通过 iv 参数设置。默认值为 NULL。

SELECT AES_DECRYPT(0x28409970815CD536428876175F1A4923, 'secret');
+----------------------------------------------------------------------------------------------------------------------+
| AES_DECRYPT(0x28409970815CD536428876175F1A4923, 'secret')                                                            |
+----------------------------------------------------------------------------------------------------------------------+
| 0x616263                                                                                                             |
+----------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

AES_ENCRYPT()

AES_ENCRYPT(data, key [,iv]) 函数使用 高级加密标准(AES) 算法,通过 key 对 data 进行加密。

你可以通过 block_encryption_mode 系统变量选择 AES 加密模式。

对于需要初始化向量的加密模式,可以通过 iv 参数设置。默认值为 NULL。

SELECT AES_ENCRYPT(0x616263,'secret');
+----------------------------------------------------------------+
| AES_ENCRYPT(0x616263,'secret')                                 |
+----------------------------------------------------------------+
| 0x28409970815CD536428876175F1A4923                             |
+----------------------------------------------------------------+
1 row in set (0.00 sec)

COMPRESS()

COMPRESS(expr) 函数返回输入数据 expr 的压缩版本。

  • 如果参数为 NULL,函数返回 NULL。
  • 如果参数为空字符串,函数返回长度为零的值。

对于非零长度的参数,函数返回一个具有以下结构的二进制字符串:

  • 字节 0 到 3:未压缩前的长度
  • 字节 4 到末尾:zlib 压缩后的数据
SELECT COMPRESS(0x414243);
+------------------------------------------+
| COMPRESS(0x414243)                       |
+------------------------------------------+
| 0x03000000789C72747206040000FFFF018D00C7 |
+------------------------------------------+
1 row in set (0.00 sec)

在上述输出中,0x03000000 表示未压缩前的长度(3),0x789C72747206040000FFFF018D00C7 是 zlib 压缩后的数据。

以下是在 TiDB 之外使用 Python 解码的示例:

import codecs
import zlib

data = codecs.decode('03000000789C72747206040000FFFF018D00C7','hex')
print(int.from_bytes(data[:4], byteorder='little'))  # 3
print(zlib.decompress(data[4:]))  # b'ABC'

对于较短的字符串,COMPRESS() 可能返回的字节数比输入还多。以下示例显示 100 个 a 字符的字符串被压缩为 19 字节。

WITH x AS (SELECT REPEAT('a',100) 'a')
SELECT LENGTH(a),LENGTH(COMPRESS(a)) FROM x;
+-----------+---------------------+
| LENGTH(a) | LENGTH(COMPRESS(a)) |
+-----------+---------------------+
|       100 |                  19 |
+-----------+---------------------+
1 row in set (0.00 sec)

MD5()

MD5(expr) 函数为给定参数 expr 计算 128 位的 MD5 哈希值。

SELECT MD5('abc');
+----------------------------------+
| MD5('abc')                       |
+----------------------------------+
| 900150983cd24fb0d6963f7d28e17f72 |
+----------------------------------+
1 row in set (0.00 sec)

PASSWORD()

PASSWORD(str) 函数计算一个可用于 mysql_native_password 认证方式的密码哈希。

SELECT PASSWORD('secret');
+-------------------------------------------+
| PASSWORD('secret')                        |
+-------------------------------------------+
| *14E65567ABDB5135D0CFD9A70B3032C179A49EE7 |
+-------------------------------------------+
1 row in set, 1 warning (0.00 sec)

Warning (Code 1681): PASSWORD is deprecated and will be removed in a future release.

RANDOM_BYTES()

RANDOM_BYTES(n) 函数返回 n 个随机字节。

SELECT RANDOM_BYTES(3);
+----------------------------------+
| RANDOM_BYTES(3)                  |
+----------------------------------+
| 0x1DBC0D                         |
+----------------------------------+
1 row in set (0.00 sec)

SHA()

SHA() 函数是 SHA1 的别名。

SHA1()

SHA1(expr) 函数为给定参数 expr 计算 160 位的 SHA-1 哈希值。

SELECT SHA1('abc');
+------------------------------------------+
| SHA1('abc')                              |
+------------------------------------------+
| a9993e364706816aba3e25717850c26c9cd0d89d |
+------------------------------------------+
1 row in set (0.00 sec)

SHA2()

SHA2(str, n) 函数使用 SHA-2 家族中的算法计算哈希值。参数 n 用于选择具体的算法。如果任一参数为 NULL,或 n 选择的算法未知或不支持,则 SHA2() 返回 NULL。

以下为支持的算法列表:

n算法
0SHA-256
224SHA-224
256SHA-256
384SHA-384
512SHA-512
SELECT SHA2('abc',224);
+----------------------------------------------------------+
| SHA2('abc',224)                                          |
+----------------------------------------------------------+
| 23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 |
+----------------------------------------------------------+
1 row in set (0.00 sec)

SM3()

SM3(str) 函数为给定参数 str 计算 256 位的 商密 3(SM3) 哈希值。

SELECT SM3('abc');
+------------------------------------------------------------------+
| SM3('abc')                                                       |
+------------------------------------------------------------------+
| 66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0 |
+------------------------------------------------------------------+
1 row in set (0.00 sec)

UNCOMPRESS()

UNCOMPRESS(data) 函数用于解压通过 COMPRESS() 函数压缩的数据。

SELECT UNCOMPRESS(0x03000000789C72747206040000FFFF018D00C7);
+------------------------------------------------------------------------------------------------------------+
| UNCOMPRESS(0x03000000789C72747206040000FFFF018D00C7)                                                       |
+------------------------------------------------------------------------------------------------------------+
| 0x414243                                                                                                   |
+------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

UNCOMPRESSED_LENGTH()

UNCOMPRESSED_LENGTH(data) 函数返回压缩数据的前 4 个字节,这 4 个字节存储了通过 COMPRESS() 函数压缩前的字符串长度。

SELECT UNCOMPRESSED_LENGTH(0x03000000789C72747206040000FFFF018D00C7);
+---------------------------------------------------------------+
| UNCOMPRESSED_LENGTH(0x03000000789C72747206040000FFFF018D00C7) |
+---------------------------------------------------------------+
|                                                             3 |
+---------------------------------------------------------------+
1 row in set (0.00 sec)

VALIDATE_PASSWORD_STRENGTH()

VALIDATE_PASSWORD_STRENGTH(str) 函数作为密码管理的一部分使用。它会计算密码的强度,并返回 0 到 100 之间的数值。

validate_password.* 系统变量会影响 VALIDATE_PASSWORD_STRENGTH() 函数的行为。

示例:

  • 若要启用密码复杂度检查,请将 validate_password.enable 系统变量设置为 ON:

    SET GLOBAL validate_password.enable=ON;
  • 查看与密码校验相关的系统变量:

    SHOW VARIABLES LIKE 'validate_password.%';
    +--------------------------------------+--------+
    | Variable_name                        | Value  |
    +--------------------------------------+--------+
    | validate_password.check_user_name    | ON     |
    | validate_password.dictionary         |        |
    | validate_password.enable             | ON     |
    | validate_password.length             | 8      |
    | validate_password.mixed_case_count   | 1      |
    | validate_password.number_count       | 1      |
    | validate_password.policy             | MEDIUM |
    | validate_password.special_char_count | 1      |
    +--------------------------------------+--------+
    8 rows in set (0.01 sec)
  • 检查空字符串的密码强度,返回 0:

    SELECT VALIDATE_PASSWORD_STRENGTH('');
    +--------------------------------+
    | VALIDATE_PASSWORD_STRENGTH('') |
    +--------------------------------+
    |                              0 |
    +--------------------------------+
    1 row in set (0.00 sec)
  • 检查短字符串 abcdef 的密码强度,返回 25:

    SELECT VALIDATE_PASSWORD_STRENGTH('abcdef');
    +--------------------------------------+
    | VALIDATE_PASSWORD_STRENGTH('abcdef') |
    +--------------------------------------+
    |                                   25 |
    +--------------------------------------+
    1 row in set (0.00 sec)
  • 检查较长字符串 abcdefghi 的密码强度,返回 50。该字符串长度大于 validate_password.length 的默认值:

    SELECT VALIDATE_PASSWORD_STRENGTH('abcdefghi');
    +-----------------------------------------+
    | VALIDATE_PASSWORD_STRENGTH('abcdefghi') |
    +-----------------------------------------+
    |                                      50 |
    +-----------------------------------------+
    1 row in set (0.00 sec)
  • 在字符串中添加一个大写字母不会提升密码强度:

    SELECT VALIDATE_PASSWORD_STRENGTH('Abcdefghi');
    +-----------------------------------------+
    | VALIDATE_PASSWORD_STRENGTH('Abcdefghi') |
    +-----------------------------------------+
    |                                      50 |
    +-----------------------------------------+
    1 row in set (0.01 sec)
  • 在字符串中添加数字也不会提升密码强度:

    SELECT VALIDATE_PASSWORD_STRENGTH('Abcdefghi123');
    +--------------------------------------------+
    | VALIDATE_PASSWORD_STRENGTH('Abcdefghi123') |
    +--------------------------------------------+
    |                                         50 |
    +--------------------------------------------+
    1 row in set (0.00 sec)
  • 最后,在字符串中添加特殊字符后,密码强度提升到 100,表示密码强度高:

    SELECT VALIDATE_PASSWORD_STRENGTH('Abcdefghi123%$#');
    +-----------------------------------------------+
    | VALIDATE_PASSWORD_STRENGTH('Abcdefghi123%$#') |
    +-----------------------------------------------+
    |                                           100 |
    +-----------------------------------------------+
    1 row in set (0.00 sec)

不支持的函数

  • TiDB 不支持仅在 MySQL Enterprise 中提供的函数 Issue #2632。

MySQL 兼容性

  • TiDB 不支持 STATEMENT_DIGEST() 和 STATEMENT_DIGEST_TEXT() 函数。
  • TiDB 不支持 MySQL 8.0.30 新增的 AES_ENCRYPT() 和 AES_DECRYPT 的 kdf_name、salt 和 iterations 参数。
  • MySQL 未实现 SM3() 函数。