#### 6.4.4.14 通用密钥环密钥管理功能

[](<>)[](<>)[](<>)

MySQL 服务器支持密钥环服务，使内部组件和插件能够安全地存储敏感信息以供以后检索。

MySQL 服务器还包括一个用于密钥环密钥管理的 SQL 接口，实现为一组通用功能，可访问内部密钥环服务提供的功能。密钥环函数包含在一个插件库文件中，该文件还包含一个`密钥环_udf`必须在函数调用之前启用的插件。要使用这些功能，请使用密钥环插件，例如`密钥环文件`要么`密钥环_okv`必须启用。

此处描述的功能是通用的，旨在与任何密钥环插件一起使用。给定的密​​钥环插件可能具有自己的功能，仅用于该插件；看[第 6.4.4.15 节，“插件特定的密钥环密钥管理功能”](keyring-functions-plugin-specific.html).

以下部分提供密钥环功能的安装说明并演示如何使用它们。有关这些函数调用的密钥环服务函数的信息，请参阅[第 5.6.9.2 节，“密钥环服务”](keyring-service.html).有关一般密钥环信息，请参阅[第 6.4.4 节，“MySQL 密钥环”](keyring.html).

-   [安装或卸载通用密钥环功能](keyring-functions-general-purpose.html#keyring-function-installation)

-   [使用通用密钥环函数](keyring-functions-general-purpose.html#keyring-function-usage)

-   [通用密钥环函数参考](keyring-functions-general-purpose.html#keyring-function-reference)

##### 安装或卸载通用密钥环功能

[](<>)[](<>)[](<>)[](<>)[](<>)[](<>)

本节介绍如何安装或卸载密钥环功能，这些功能在一个插件库文件中实现，该文件还包含一个`密钥环_udf`插入。有关安装或卸载插件和可加载函数的一般信息，请参阅[第 5.6.1 节，“安装和卸载插件”](plugin-loading.html)， 和[第 5.7.1 节，“安装和卸载可加载函数”](function-loading.html).

密钥环功能启用密钥环密钥管理操作，但`密钥环_udf`还必须安装插件，因为没有它功能无法正常工作。尝试在没有`密钥环_udf`插件导致错误。

要被服务器使用，插件库文件必须位于 MySQL 插件目录（由[`插件目录`](server-system-variables.html#sysvar_plugin_dir)系统变量）。如有必要，通过设置值来配置插件目录位置[`插件目录`](server-system-variables.html#sysvar_plugin_dir)在服务器启动时。

插件库文件的基本名称是`密钥环_udf`.文件名后缀因平台而异（例如，`。所以`对于 Unix 和类 Unix 系统，`.dll`对于 Windows）。

安装`密钥环_udf`插件和密钥环功能，使用[`安装插件`](install-plugin.html)和[`创建函数`](create-function.html)声明，调整`。所以`根据需要为您的平台添加后缀：

```
INSTALL PLUGIN keyring_udf SONAME 'keyring_udf.so';
CREATE FUNCTION keyring_key_generate RETURNS INTEGER
  SONAME 'keyring_udf.so';
CREATE FUNCTION keyring_key_fetch RETURNS STRING
  SONAME 'keyring_udf.so';
CREATE FUNCTION keyring_key_length_fetch RETURNS INTEGER
  SONAME 'keyring_udf.so';
CREATE FUNCTION keyring_key_type_fetch RETURNS STRING
  SONAME 'keyring_udf.so';
CREATE FUNCTION keyring_key_store RETURNS INTEGER
  SONAME 'keyring_udf.so';
CREATE FUNCTION keyring_key_remove RETURNS INTEGER
  SONAME 'keyring_udf.so';
```

如果在源复制服务器上使用插件和功能，请将它们安装在所有副本上以避免复制问题。

如前所述安装后，插件和功能将保持安装状态，直到卸载。要删除它们，请使用[`卸载插件`](uninstall-plugin.html)和[`拖放功能`](drop-function.html)声明：

```
UNINSTALL PLUGIN keyring_udf;
DROP FUNCTION keyring_key_generate;
DROP FUNCTION keyring_key_fetch;
DROP FUNCTION keyring_key_length_fetch;
DROP FUNCTION keyring_key_type_fetch;
DROP FUNCTION keyring_key_store;
DROP FUNCTION keyring_key_remove;
```

##### 使用通用密钥环函数

[](<>)

在使用钥匙圈通用功能之前，请按照中提供的说明进行安装[安装或卸载通用密钥环功能](keyring-functions-general-purpose.html#keyring-function-installation).

密钥环功能受以下约束：

-   要使用任何密钥环功能，`密钥环_udf`插件必须启用。否则，会发生错误：

    ```
    ERROR 1123 (HY000): Can't initialize function 'keyring_key_generate';
    This function requires keyring_udf plugin which is not installed.
    Please install
    ```

    安装`密钥环_udf`插件，见[安装或卸载通用密钥环功能](keyring-functions-general-purpose.html#keyring-function-installation).

-   密钥环函数调用密钥环服务函数（参见[第 5.6.9.2 节，“密钥环服务”](keyring-service.html)）。服务功能依次使用安装的任何密钥环插件（例如，`密钥环文件`要么`密钥环_okv`）。因此，要使用任何密钥环功能，必须启用一些底层密钥环插件。否则，会发生错误：

    ```
    ERROR 3188 (HY000): Function 'keyring_key_generate' failed because
    underlying keyring service returned an error. Please check if a
    keyring plugin is installed and that provided arguments are valid
    for the keyring you are using.
    ```

    要安装密钥环插件，请参阅[第 6.4.4.3 节，“密钥环插件安装”](keyring-plugin-installation.html).

-   用户必须拥有全局[`执行`](privileges-provided.html#priv_execute)使用任何密钥环功能的特权。否则，会发生错误：

    ```
    ERROR 1123 (HY000): Can't initialize function 'keyring_key_generate';
    The user is not privileged to execute this function. User needs to
    have EXECUTE
    ```

    授予全球[`执行`](privileges-provided.html#priv_execute)用户的特权，使用以下语句：

    ```
    GRANT EXECUTE ON *.* TO user;
    ```

    或者，您是否希望避免授予全局[`执行`](privileges-provided.html#priv_execute)特权，同时仍然允许用户访问特定的密钥管理操作，可以定义“包装”存储程序（本节后面描述的技术）。

-   由给定用户存储在密钥环中的密钥以后只能由同一用户操作。也就是说，价值[`当前用户（）`](information-functions.html#function_current-user)密钥操作时的函数必须与密钥存储在密钥环中时的值相同。（此约束排除了使用密钥环函数来操作实例范围的密钥，例如由`InnoDB`支持表空间加密。）

    为了使多个用户能够对同一个键执行操作，可以定义“包装”存储程序（本节稍后将介绍的技术）。

-   密钥环函数支持底层密钥环插件支持的密钥类型和长度。有关特定于特定密钥环插件的密钥的信息，请参阅[第 6.4.4.12 节，“支持的密钥环密钥类型和长度”](keyring-key-types.html).

    要创建一个新的随机密钥并将其存储在密钥环中，请调用[`keyring_key_generate()`](keyring-functions-general-purpose.html#function_keyring-key-generate)，将密钥的 ID 以及密钥类型（加密方法）及其长度（以字节为单位）传递给它。以下调用创建了一个 2,048 位 DSA 加密密钥，名为`我的钥匙`：


```
mysql> SELECT keyring_key_generate('MyKey', 'DSA', 256);
+-------------------------------------------+
| keyring_key_generate('MyKey', 'DSA', 256) |
+-------------------------------------------+
|                                         1 |
+-------------------------------------------+
```

返回值 1 表示成功。如果无法创建密钥，则返回值为`空值`并发生错误。原因之一可能是底层密钥环插件不支持指定的密钥类型和密钥长度组合；看[第 6.4.4.12 节，“支持的密钥环密钥类型和长度”](keyring-key-types.html).

为了能够检查返回类型而不管是否发生错误，请使用`选择...进入@*`变量名`*`并测试变量值：

```
mysql> SELECT keyring_key_generate('', '', -1) INTO @x;
ERROR 3188 (HY000): Function 'keyring_key_generate' failed because
underlying keyring service returned an error. Please check if a
keyring plugin is installed and that provided arguments are valid
for the keyring you are using.
mysql> SELECT @x;
+------+
| @x   |
+------+
| NULL |
+------+
mysql> SELECT keyring_key_generate('x', 'AES', 16) INTO @x;
mysql> SELECT @x;
+------+
| @x   |
+------+
|    1 |
+------+
```

这种技术也适用于失败返回值和错误的其他密钥环函数。

传递给的 ID[`keyring_key_generate()`](keyring-functions-general-purpose.html#function_keyring-key-generate)提供了一种在后续函数调用中引用键的方法。例如，使用键 ID 将其类型检索为字符串或将其长度（以字节为单位）检索为整数：

```
mysql> SELECT keyring_key_type_fetch('MyKey');
+---------------------------------+
| keyring_key_type_fetch('MyKey') |
+---------------------------------+
| DSA                             |
+---------------------------------+
mysql> SELECT keyring_key_length_fetch('MyKey');
+-----------------------------------+
| keyring_key_length_fetch('MyKey') |
+-----------------------------------+
|                               256 |
+-----------------------------------+
```

要检索键值，请将键 ID 传递给[`keyring_key_fetch()`](keyring-functions-general-purpose.html#function_keyring-key-fetch).以下示例使用[`十六进制（）`](string-functions.html#function_hex)显示键值，因为它可能包含不可打印的字符。为了简洁起见，该示例还使用了短密钥，但请注意，较长的密钥可提供更好的安全性：

```
mysql> SELECT keyring_key_generate('MyShortKey', 'DSA', 8);
+----------------------------------------------+
| keyring_key_generate('MyShortKey', 'DSA', 8) |
+----------------------------------------------+
|                                            1 |
+----------------------------------------------+
mysql> SELECT HEX(keyring_key_fetch('MyShortKey'));
+--------------------------------------+
| HEX(keyring_key_fetch('MyShortKey')) |
+--------------------------------------+
| 1DB3B0FC3328A24C                     |
+--------------------------------------+
```

Keyring 函数将键 ID、类型和值视为二进制字符串，因此比较区分大小写。例如，ID`我的钥匙`和`我的钥匙`指不同的键。

要删除密钥，请将密钥 ID 传递给[`keyring_key_remove()`](keyring-functions-general-purpose.html#function_keyring-key-remove)：

```
mysql> SELECT keyring_key_remove('MyKey');
+-----------------------------+
| keyring_key_remove('MyKey') |
+-----------------------------+
|                           1 |
+-----------------------------+
```

要混淆和存储您提供的密钥，请将密钥 ID、类型和值传递给[`keyring_key_store()`](keyring-functions-general-purpose.html#function_keyring-key-store)：

```
mysql> SELECT keyring_key_store('AES_key', 'AES', 'Secret string');
+------------------------------------------------------+
| keyring_key_store('AES_key', 'AES', 'Secret string') |
+------------------------------------------------------+
|                                                    1 |
+------------------------------------------------------+
```

如前所述，用户必须拥有全局[`执行`](privileges-provided.html#priv_execute)调用密钥环函数的权限，并且最初将密钥存储在密钥环中的用户必须是稍后对密钥执行后续操作的同一用户，由[`当前用户（）`](information-functions.html#function_current-user)每个函数调用的有效值。允许没有全局权限的用户进行关键操作[`执行`](privileges-provided.html#priv_execute)特权或可能不是关键“所有者”的人，请使用以下技术：

1.  定义“包装”存储程序，封装所需的关键操作并具有`定义者`值等于密钥所有者。

2.  授予[`执行`](privileges-provided.html#priv_execute)将特定存储程序的特权授予应该能够调用它们的个人用户。

3.  如果包装存储程序实现的操作不包括密钥创建，请使用名为`定义者`在存储的程序定义中。

    这种技术可以在用户之间共享密钥，并为 DBA 提供更细粒度的控制，以控制谁可以使用密钥做什么，而无需授予全局权限。

    下面的例子展示了如何设置一个名为`共享密钥`由 DBA 拥有，以及`get_shared_key()`提供对当前键值的访问的存储函数。任何用户都可以使用[`执行`](privileges-provided.html#priv_execute)该功能的特权，它是在`key_schema`架构。

    从 MySQL 管理帐户 (`'根'@'本地主机'`在这个例子中），创建管理模式和存储函数来访问密钥：


```
mysql> CREATE SCHEMA key_schema;

mysql> CREATE DEFINER = 'root'@'localhost'
       FUNCTION key_schema.get_shared_key()
       RETURNS BLOB READS SQL DATA
       RETURN keyring_key_fetch('SharedKey');
```

在管理帐户中，确保共享密钥存在：

```
mysql> SELECT keyring_key_generate('SharedKey', 'DSA', 8);
+---------------------------------------------+
| keyring_key_generate('SharedKey', 'DSA', 8) |
+---------------------------------------------+
|                                           1 |
+---------------------------------------------+
```

从管理帐户创建一个普通用户帐户，授予其密钥访问权限：

```
mysql> CREATE USER 'key_user'@'localhost'
       IDENTIFIED BY 'key_user_pwd';
```

来自`key_user`帐户，验证，没有适当的[`执行`](privileges-provided.html#priv_execute)权限，新帐户无法访问共享密钥：

```
mysql> SELECT HEX(key_schema.get_shared_key());
ERROR 1370 (42000): execute command denied to user 'key_user'@'localhost'
for routine 'key_schema.get_shared_key'
```

从管理帐户，授予[`执行`](privileges-provided.html#priv_execute)到`key_user`对于存储的功能：

```
mysql> GRANT EXECUTE ON FUNCTION key_schema.get_shared_key
       TO 'key_user'@'localhost';
```

来自`key_user`帐户，验证密钥现在是否可以访问：

```
mysql> SELECT HEX(key_schema.get_shared_key());
+----------------------------------+
| HEX(key_schema.get_shared_key()) |
+----------------------------------+
| 9BAFB9E75CEEB013                 |
+----------------------------------+
```

##### 通用密钥环函数参考

对于每个通用密钥环函数，本节描述其用途、调用顺序和返回值。有关可以调用这些函数的条件的信息，请参阅[使用通用密钥环函数](keyring-functions-general-purpose.html#keyring-function-usage).

-   [](<>) [`keyring_key_fetch(*`key_id`*)`](keyring-functions-general-purpose.html#function_keyring-key-fetch)

    [](<>)[](<>)

    给定一个键 ID，去混淆并返回键值。

    论据：

    -   *`key_id`*：指定密钥 ID 的字符串。

        返回值：

        将键值作为字符串返回成功，`空值`如果密钥不存在，或者`空值`和失败的错误。

    笔记

    使用检索的键值[`keyring_key_fetch()`](keyring-functions-general-purpose.html#function_keyring-key-fetch)受制于中所述的一般密钥环功能限制[第 6.4.4.12 节，“支持的密钥环密钥类型和长度”](keyring-key-types.html).可以使用密钥环服务功能存储比该长度更长的密钥值（请参阅[第 5.6.9.2 节，“密钥环服务”](keyring-service.html))，但如果使用检索[`keyring_key_fetch()`](keyring-functions-general-purpose.html#function_keyring-key-fetch)被截断为一般密钥环功能限制。

    例子：

    ```
    mysql> SELECT keyring_key_generate('RSA_key', 'RSA', 16);
    +--------------------------------------------+
    | keyring_key_generate('RSA_key', 'RSA', 16) |
    +--------------------------------------------+
    |                                          1 |
    +--------------------------------------------+
    mysql> SELECT HEX(keyring_key_fetch('RSA_key'));
    +-----------------------------------+
    | HEX(keyring_key_fetch('RSA_key')) |
    +-----------------------------------+
    | 91C2253B696064D3556984B6630F891A  |
    +-----------------------------------+
    mysql> SELECT keyring_key_type_fetch('RSA_key');
    +-----------------------------------+
    | keyring_key_type_fetch('RSA_key') |
    +-----------------------------------+
    | RSA                               |
    +-----------------------------------+
    mysql> SELECT keyring_key_length_fetch('RSA_key');
    +-------------------------------------+
    | keyring_key_length_fetch('RSA_key') |
    +-------------------------------------+
    |                                  16 |
    +-------------------------------------+
    ```

    该示例使用[`十六进制（）`](string-functions.html#function_hex)显示键值，因为它可能包含不可打印的字符。为简洁起见，该示例还使用了短密钥，但请注意，较长的密钥可提供更好的安全性。

-   [](<>) [`keyring_key_generate(*`key_id`*, *`键类型`*, *`密钥长度`*)`](keyring-functions-general-purpose.html#function_keyring-key-generate)

    [](<>)[](<>)

    生成具有给定 ID、类型和长度的新随机密钥，并将其存储在密钥环中。类型和长度值必须与底层密钥环插件支持的值一致。看[第 6.4.4.12 节，“支持的密钥环密钥类型和长度”](keyring-key-types.html).

    论据：

    -   *`key_id`*：指定密钥 ID 的字符串。

    -   *`键类型`*：指定密钥类型的字符串。

    -   *`密钥长度`*：一个整数，以字节为单位指定密钥长度。

        返回值：

        返回 1 表示成功，或者`空值`和失败的错误。

        例子：

    ```
    mysql> SELECT keyring_key_generate('RSA_key', 'RSA', 384);
    +---------------------------------------------+
    | keyring_key_generate('RSA_key', 'RSA', 384) |
    +---------------------------------------------+
    |                                           1 |
    +---------------------------------------------+
    ```

-   [](<>) [`keyring_key_length_fetch(*`key_id`*)`](keyring-functions-general-purpose.html#function_keyring-key-length-fetch)

    [](<>)[](<>)

    给定一个密钥 ID，返回密钥长度。

    论据：

    -   *`key_id`*：指定密钥 ID 的字符串。

        返回值：

        以整数形式返回密钥长度（以字节为单位）表示成功，`空值`如果密钥不存在，或者`空值`和失败的错误。

        例子：

        见描述[`keyring_key_fetch()`](keyring-functions-general-purpose.html#function_keyring-key-fetch).

-   [](<>) [`keyring_key_remove(*`key_id`*)`](keyring-functions-general-purpose.html#function_keyring-key-remove)

    [](<>)[](<>)

    从密钥环中删除具有给定 ID 的密钥。

    论据：

    -   *`key_id`*：指定密钥 ID 的字符串。

        返回值：

        返回 1 表示成功，或者`空值`为失败。

        例子：

    ```
    mysql> SELECT keyring_key_remove('AES_key');
    +-------------------------------+
    | keyring_key_remove('AES_key') |
    +-------------------------------+
    |                             1 |
    +-------------------------------+
    ```

-   [](<>) [`keyring_key_store(*`key_id`*, *`键类型`*, *`钥匙`*)`](keyring-functions-general-purpose.html#function_keyring-key-store)

    [](<>)[](<>)

    混淆密钥并将密钥存储在密钥环中。

    论据：

    -   *`key_id`*：指定密钥 ID 的字符串。

    -   *`键类型`*：指定密钥类型的字符串。

    -   *`钥匙`*：指定键值的字符串。

        返回值：

        返回 1 表示成功，或者`空值`和失败的错误。

        例子：

    ```
    mysql> SELECT keyring_key_store('new key', 'DSA', 'My key value');
    +-----------------------------------------------------+
    | keyring_key_store('new key', 'DSA', 'My key value') |
    +-----------------------------------------------------+
    |                                                   1 |
    +-----------------------------------------------------+
    ```

-   [](<>) [`keyring_key_type_fetch(*`key_id`*)`](keyring-functions-general-purpose.html#function_keyring-key-type-fetch)

    [](<>)[](<>)

    给定密钥 ID，返回密钥类型。

    论据：

    -   *`key_id`*：指定密钥 ID 的字符串。

        返回值：

        将键类型作为成功的字符串返回，`空值`如果密钥不存在，或者`空值`和失败的错误。

        例子：

        见描述[`keyring_key_fetch()`](keyring-functions-general-purpose.html#function_keyring-key-fetch).
