在 Linux 上使用 OpenSSL 封装密钥

本主题介绍如何在导入密钥到 Cloud KMS 之前手动封装密钥。如果您不想在导入密钥前使用 Google Cloud CLI 自动封装密钥,只需按照本主题中的说明操作。如需简要了解差异,请参阅密钥导入的工作原理

您可以在 5 至 10 分钟内完成本主题中的步骤,但不包括准备工作步骤。

准备工作

在封装密钥之前,您必须先满足以下要求。

  1. 创建目标密钥环和密钥,然后创建导入作业
  2. 验证您的密钥是否在本地可用且格式正确,以导入到 Cloud KMS 中。
  3. 修补并重新编译 OpenSSL

检索封装密钥

本部分介绍了如何从您在准备工作中创建的导入作业中检索封装密钥。建议使用 Google Cloud 控制台。

控制台

  1. 转到 Google Cloud 控制台中的密钥管理页面。

    转到“密钥管理”页面

  2. 点击包含导入作业的密钥环的名称。

  3. 点击页面顶部的导入作业标签页。

  4. 点击更多 ,然后点击弹出式菜单中的下载封装密钥

gcloud CLI

要验证导入作业是否处于活动状态,请运行 gcloud kms import-jobs describe 命令:

gcloud kms import-jobs describe IMPORT_JOB \
  --location LOCATION \
  --keyring KEY_RING \
  --format="value(state)"
state: ACTIVE

运行以下命令,将导入作业中的公钥保存到 ${HOME}/wrapping-key.pem

gcloud kms import-jobs describe \
  --location=LOCATION \
  --keyring=KEY_RING \
  --format="value(publicKey.pem)" \
  IMPORT_JOB > ${HOME}/wrapping-key.pem

API

  1. 调用 ImportJob.get 方法。

  2. 通过 ImportJob.get 响应的 publicKey 字段检索公钥。此值的类型为 WrappingPublicKeyWrappingPublicKey 类型的 pem 字段是以保密增强邮件 (PEM) 格式编码的公钥。

如需详细了解 PEM 编码格式,请参阅 RFC 7468,尤其是一般注意事项主体公钥信息的文本编码部分。

设置环境变量

OpenSSL 命令需要多个文件路径作为输入值。为文件路径定义环境变量,以便更轻松地运行这些命令。 确保您有权向下面定义的目录写入。

  1. PUB_WRAPPING_KEY 变量设置为您从导入作业下载的封装密钥的完整路径。封装密钥以 .pem 结尾。

    PUB_WRAPPING_KEY="WRAPPING_KEY_PATH"
    

  2. TARGET_KEY 变量设置为指向解封装(目标)键的完整路径。

    TARGET_KEY=TARGET_KEY_PATH
    

    TARGET_KEY_PATH 替换为对称密钥的 .bin 文件的路径,或者非对称密钥的 .der 文件的路径。

  3. 如果使用 RSA-AES 封装,请将 TEMP_AES_KEY 变量设置为临时 AES 密钥的完整路径。

    TEMP_AES_KEY=TEMP_AES_KEY_PATH
    

  4. WRAPPED_KEY 变量设置为完整路径,以便保存可供导入的封装目标密钥。

    WRAPPED_KEY=WRAPPED_KEY_PATH
    

  5. 使用以下命令验证是否正确设置了所有环境变量:

    echo "PUB_WRAPPING_KEY: " ${PUB_WRAPPING_KEY}; \
    echo "TARGET_KEY: " ${TARGET_KEY}; \
    echo "TEMP_AES_KEY: " ${TEMP_AES_KEY}; \
    echo "WRAPPED_KEY: " ${WRAPPED_KEY}
    

正确设置变量后,您就可以封装密钥了。有两种方法,如下所述:仅使用 RSA 或采用 RSA-AES

封装密钥

使用 RSA 封装密钥

在此方法中,目标密钥封装在 RSA 块中。因此,目标密钥大小有限。例如,您无法使用此方法封装另一个 RSA 密钥。支持的导入方法包括 rsa-oaep-3072-sha256rsa-oaep-4096-sha256

  • 通过 CKM_RSA_PKCS_OAEP 算法使用封装公钥来封装目标密钥:

    openssl pkeyutl \
      -encrypt \
      -pubin \
      -inkey ${PUB_WRAPPING_KEY} \
      -in ${TARGET_KEY} \
      -out ${WRAPPED_KEY} \
      -pkeyopt rsa_padding_mode:oaep \
      -pkeyopt rsa_oaep_md:sha256 \
      -pkeyopt rsa_mgf1_md:sha256
    

使用 RSA-AES 封装密钥

在此方法中,目标密钥使用临时 AES 密钥进行封装。然后,使用 RSA 密钥封装临时 AES 密钥。这两个封装密钥会串联并导入。由于目标密钥使用 AES 而非 RSA 进行封装,因此这种方法可用于封装大型密钥。支持的导入方法包括 rsa-oaep-3072-sha1-aes-256rsa-oaep-4096-sha1-aes-256rsa-oaep-3072-sha256-aes-256rsa-oaep-4096-sha256-aes-256

  1. 生成一个长度为 32 个字节的临时随机 AES 密钥,并将其保存到 ${TEMP_AES_KEY} 标识的位置:

    openssl rand -out "${TEMP_AES_KEY}" 32
    

  2. 使用 CKM_RSA_PKCS_OAEP 算法使用封装公钥来封装临时 AES 密钥。如果导入方法是 rsa-oaep-3072-sha1-aes-256rsa-oaep-4096-sha1-aes-256,请对 rsa_oaep_mdrsa_mgf1_md 使用 sha1。将 sha256 用于 rsa-oaep-3072-sha256-aes-256rsa-oaep-4096-sha256-aes-256

    openssl pkeyutl \
      -encrypt \
      -pubin \
      -inkey ${PUB_WRAPPING_KEY} \
      -in ${TEMP_AES_KEY} \
      -out ${WRAPPED_KEY} \
      -pkeyopt rsa_padding_mode:oaep \
      -pkeyopt rsa_oaep_md:{sha1|sha256} \
      -pkeyopt rsa_mgf1_md:{sha1|sha256}
    

  3. OpenSSL_V110 变量设置为 openssl.sh 脚本的路径。如果您完全按照修补并重新编译 OpenSSL 的说明进行操作,则可以使用此命令,而无需修改变量的值。

    OPENSSL_V110="${HOME}/local/bin/openssl.sh"
    

  4. 采用 CKM_AES_KEY_WRAP_PAD 算法,使用临时 AES 密钥封装目标密钥,并将其附加到 WRAPPED_KEY

    "${OPENSSL_V110}" enc \
      -id-aes256-wrap-pad \
      -iv A65959A6 \
      -K $( hexdump -v -e '/1 "%02x"' < "${TEMP_AES_KEY}" ) \
      -in "${TARGET_KEY}" >> "${WRAPPED_KEY}"
    

    -iv A65959A6 标志将 A65959A6 设置为备用初始值。这是 RFC 5649 规范的要求。

后续步骤

  • 保存在 WRAPPED_KEY 的封装密钥现在即可导入。如需导入密钥,请按照导入手动封装的密钥中的说明操作。