在 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 字段检索公钥。此值的类型为 WrappingPublicKey。类型为 WrappingPublicKeypem 字段是以保密增强邮件 (PEM) 格式编码的公钥。

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

设置环境变量

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

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

    PUB_WRAPPING_KEY="WRAPPING_KEY_PATH"
    

  2. TARGET_KEY 变量设置为未封装(目标)密钥的完整路径。

    TARGET_KEY=TARGET_KEY_PATH
    

    对于对称密钥,将 TARGET_KEY_PATH 替换为 .bin 文件的路径;对于非对称密钥,将 TARGET_KEY_PATH 替换为 .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 密钥进行封装。然后,临时 AES 密钥由 RSA 密钥封装。这两个封装的密钥会连接并导入。由于目标密钥是使用 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。对 rsa-oaep-3072-sha256-aes-256rsa-oaep-4096-sha256-aes-256 使用 sha256

    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 的封装密钥现在可以导入了。如需导入密钥,请按照导入手动封装的密钥中的说明操作。