本指南介绍如何使用量子安全导入方法将加密密钥作为新密钥版本导入到 Cloud Key Management Service 中。这种方法有助于保护密钥在传输过程中免受未来量子计算机的“现在收集,日后解密”(HNDL) 攻击。
量子安全密钥导入使用标准的后量子密码学 (PQC) 工具(包括密钥封装机制 (KEM) 和混合公钥加密 (HPKE))来保护密钥在传输过程中的安全。
量子安全密钥导入适用于软件支持的密钥(SOFTWARE 保护级别)。
准备工作
在导入密钥之前,您需要准备项目、本地系统和密钥材料本身。
准备创建项目
- 登录您的 Google Cloud 账号。如果您是 Google Cloud的新用户, 请创建一个账号,以评估我们的产品在 实际场景中的表现。新客户还可获享 $300 赠金,用于 运行、测试和部署工作负载。
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
Roles required to select or create a project
- Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
-
Create a project: To create a project, you need the Project Creator role
(
roles/resourcemanager.projectCreator), which contains theresourcemanager.projects.createpermission. Learn how to grant roles.
-
Verify that billing is enabled for your Google Cloud project.
Enable the required API.
Roles required to enable APIs
To enable APIs, you need the
serviceusage.services.enablepermission. If you created the project, then you likely already have this permission through the Owner role (roles/owner). Otherwise, you can get this permission through the Service Usage Admin role (roles/serviceusage.serviceUsageAdmin). Learn how to grant roles.-
安装 Google Cloud CLI。
-
如果您使用的是外部身份提供方 (IdP),则必须先使用联合身份登录 gcloud CLI。
-
如需初始化 gcloud CLI,请运行以下命令:
gcloud init -
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
Roles required to select or create a project
- Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
-
Create a project: To create a project, you need the Project Creator role
(
roles/resourcemanager.projectCreator), which contains theresourcemanager.projects.createpermission. Learn how to grant roles.
-
Verify that billing is enabled for your Google Cloud project.
Enable the required API.
Roles required to enable APIs
To enable APIs, you need the
serviceusage.services.enablepermission. If you created the project, then you likely already have this permission through the Owner role (roles/owner). Otherwise, you can get this permission through the Service Usage Admin role (roles/serviceusage.serviceUsageAdmin). Learn how to grant roles.-
安装 Google Cloud CLI。
-
如果您使用的是外部身份提供方 (IdP),则必须先使用联合身份登录 gcloud CLI。
-
如需初始化 gcloud CLI,请运行以下命令:
gcloud init
所需的角色
如需获得导入密钥所需的权限,请让您的管理员向您授予密钥环的以下 IAM 角色:
-
仅导入到现有密钥:
Cloud KMS Importer (
roles/cloudkms.importer) -
导入到新密钥:
Cloud KMS Admin (
roles/cloudkms.admin)
如需详细了解如何授予角色,请参阅管理对项目、文件夹和组织的访问权限。
您也可以通过自定义 角色或其他预定义 角色来获取所需的权限。
准备本地系统
您需要在本地系统上安装一个加密库,该库支持后量子密码学 (PQC) 工具,包括密钥封装机制 (KEM) 和混合公钥加密 (HPKE)。您可以使用 Tink、OpenSSL 或支持以下功能的其他加密库:
- 混合公钥加密 (HPKE)
- 以下 KEM 算法之一:
ML-KEM-768ML-KEM-1024X-WING(ML-KEM-768和X25519的混合体)
HKDF-SHA256密钥推导函数 (KDF)- 使用
AES-256-GCM算法的关联数据加密的身份验证 (AEAD)
准备密钥
验证密钥的 算法和长度 是否
受支持。密钥的所有版本都必须具有相同的保护级别 (SOFTWARE)。
创建目标密钥和密钥环
导入密钥材料时,它会成为现有密钥的新密钥版本。 此密钥称为目标密钥。在导入密钥材料之前,目标密钥环和目标密钥必须已存在。
按照以下步骤使用 Google Cloud CLI 或 Google Cloud 控制台在新密钥环上创建空软件支持的密钥 。
控制台
在 Google Cloud 控制台中,前往 密钥管理 页面。
点击创建密钥环。
在密钥环名称 字段中,输入密钥环的名称。
在位置类型 下,选择位置类型和位置。
点击创建 。此时会打开创建密钥 页面。
在密钥名称 字段中,输入密钥的名称。
对于保护级别,请选择软件。
对于密钥材料,请选择导入的密钥,然后点击继续。 这样做可以防止创建初始密钥版本。
为密钥设置用途 和算法 ,然后点击继续 。
可选:如果您希望此密钥仅包含导入的密钥版本,请选择将密钥版本限制为仅供导入 。这可防止您在 Cloud KMS 中意外创建新密钥版本。
可选:对于导入的密钥,自动轮替在默认情况下处于停用状态。 如需启用自动轮替,请从密钥轮替周期 字段中选择一个值。
如果启用自动轮替,则新密钥版本将在 Cloud KMS 中生成,并且导入的密钥版本将不再是轮替之后的默认密钥版本。
点击创建 。
gcloud
如需在命令行上使用 Cloud KMS,请先 安装或升级到最新版本的 Google Cloud CLI。
创建目标密钥环。选择与您要使用的保护级别兼容的位置。如需详细了解支持的 位置,请参阅 Cloud KMS 位置。
gcloud kms keyrings create KEY_RING \ --location LOCATION
您可以详细了解如何 创建密钥环。
使用
kms keys create命令和--skip-initial-version-creation标志创建目标密钥。这会创建一个没有初始密钥版本的密钥,以便导入的密钥材料为版本1。使用--import-only标志可防止 Cloud KMS 为新密钥版本生成密钥材料。设置此标志后,必须为此密钥导入新密钥版本。以--import-only形式创建的密钥必须手动轮替。gcloud kms keys create KEY_NAME \ --location LOCATION \ --keyring KEY_RING \ --purpose PURPOSE \ --protection-level SOFTWARE \ --skip-initial-version-creation \ --import-only
替换以下内容:
KEY_NAME:您要用于密钥的名称。LOCATION:密钥环的位置。KEY_RING:您要在其中创建密钥的密钥环。PURPOSE:您要用于密钥的用途,
API
这些示例使用 curl 作为 HTTP 客户端来演示如何使用 API。如需详细了解访问权限控制,请参阅 访问 Cloud KMS API。
创建新的密钥环:
curl "https://cloudkms.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/keyRings?keyRingId=KEY_RING" \ --request "POST" \ --header "authorization: Bearer TOKEN" \ --header "content-type: application/json" \ --header "x-goog-user-project: PROJECT_ID" \ --data "{}"如需了解详情,请参阅
KeyRing.createAPI 文档 。创建仅供导入的空密钥:
curl "https://cloudkms.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys?cryptoKeyId=KEY_NAME&skipInitialVersionCreation=true" \ --request "POST" \ --header "authorization: Bearer TOKEN" \ --header "content-type: application/json" \ --header "x-goog-user-project: PROJECT_ID" \ --data "{"purpose":"PURPOSE", "importOnly": "true", "versionTemplate":{"protectionLevel":"PROTECTION_LEVEL","algorithm":"ALGORITHM"}}"如需了解详情,请参阅
CryptoKey.createAPI 文档 。
密钥环和密钥现在已存在,但密钥不包含密钥材料,没有版本,且处于无效状态。接下来创建导入作业。
创建导入作业
导入作业定义其导入的密钥的特性,包括保护级别和导入方法。
量子安全密钥导入仅适用于 SOFTWARE 保护级别。
选择以下量子安全导入方法之一:
HPKE_KEM_XWING_HKDF_SHA256_AES_256_GCMHPKE_KEM_ML_KEM_768_HKDF_SHA256_AES_256_GCMHPKE_KEM_ML_KEM_1024_HKDF_SHA256_AES_256_GCM
gcloud
运行以下命令,使用量子安全导入方法创建导入作业:
gcloud kms import-jobs create IMPORT_JOB \
--location LOCATION \
--keyring KEY_RING \
--import-method IMPORT_METHOD \
--protection-level software
替换以下内容:
IMPORT_JOB:用于导入作业的唯一名称。LOCATION:您在其中创建目标密钥的密钥环的位置。KEY_RING:您在其中创建目标密钥的密钥环的名称。IMPORT_METHOD:您要使用的量子安全导入方法,例如hpke-kem-xwing-hkdf-sha256-aes-256-gcm。
REST
调用 keyRings.importJobs.create 方法:
curl "https://cloudkms.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/importJobs?import_job_id=IMPORT_JOB" \
--request "POST" \
--header "authorization: Bearer TOKEN" \
--header "content-type: application/json" \
--data '{"import_method": "IMPORT_METHOD", "protection_level": "SOFTWARE"}'
替换以下内容:
PROJECT_ID:Cloud KMS 项目的标识符。LOCATION:您在其中创建目标密钥的密钥环的位置。KEY_RING:您在其中创建目标密钥的密钥环的名称。IMPORT_JOB:用于导入作业的唯一名称。TOKEN:用于对请求进行身份验证的令牌。IMPORT_METHOD:您要使用的量子安全导入方法,例如HPKE_KEM_XWING_HKDF_SHA256_AES_256_GCM。
检查导入作业的状态
导入作业的初始状态为 PENDING_GENERATION。当状态为 ACTIVE 时,您可以使用它导入密钥。
导入作业将在三天后过期。如果导入作业已过期,则必须创建新导入作业。
您可以使用 Google Cloud CLI、 Google Cloud 控制台或 Cloud Key Management Service API 来检查导入作业的状态。
控制台
在 Google Cloud 控制台中,前往密钥管理 页面。
点击包含导入作业的密钥环的名称。
点击页面顶部的导入作业标签页。
状态将会显示在导入作业名称旁边的状态 下。
gcloud
如需在命令行上使用 Cloud KMS,请先 安装或升级到最新版本的 Google Cloud CLI。
当导入作业处于有效状态时,您可以使用它来导入密钥。这可能需要几分钟的时间。使用此命令验证导入作业是否处于有效状态。使用创建导入作业的位置和密钥环。
gcloud kms import-jobs describe IMPORT_JOB \ --location LOCATION \ --keyring KEY_RING \ --format="value(state)"
输出类似于以下内容:
state: ACTIVE
Go
要运行此代码,请先设置 Go 开发环境并 安装 Cloud KMS Go SDK。
Java
要运行此代码,请先设置 Java 开发环境并 安装 Cloud KMS Java SDK。
Node.js
要运行此代码,请先 设置 Node.js 开发环境 并 安装 Cloud KMS Node.js SDK。
Python
要运行此代码,请先设置 Python 开发环境并 安装 Cloud KMS Python SDK。
API
这些示例使用 curl 作为 HTTP 客户端来演示如何使用 API。如需详细了解访问权限控制,请参阅 访问 Cloud KMS API。
如需检查导入作业的状态,请使用
ImportJobs.get
方法:
curl "https://cloudkms.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/importJobs/IMPORT_JOB_ID" \
--request "GET" \
--header "authorization: Bearer TOKEN"
导入作业处于活动状态时,您可以 发出导入密钥的请求。
检索公开封装密钥
导入作业处于 ACTIVE 状态后,检索与其关联的公钥。您将在本地系统上使用此公钥来封装要导入的密钥材料。
gcloud
运行以下命令下载公钥:
gcloud kms import-jobs describe IMPORT_JOB
--location LOCATION
--keyring KEY_RING
--format="value(publicKey.data)"
替换以下内容:
IMPORT_JOB:导入作业的名称。LOCATION:您在其中创建导入作业的密钥环的位置。KEY_RING:您在其中创建导入作业的密钥环的名称。
公钥采用 base64 编码。
REST
- 调用
keyRings.importJobs.get方法。 - 从响应的
publicKey.data字段检索公钥,并将其另存为本地文件public_key.data。
准备和封装密钥材料
在本地系统上使用受支持的外部加密库,使用检索到的公开封装密钥来封装密钥材料。
封装过程必须执行 HPKE.Seal() (RFC 9180) 以生成封装的密钥。这会完成以下步骤:
- 封装检索到的公钥,以生成共享密钥令牌和封装密钥。
- 使用 HKDF-SHA256 从共享密钥令牌派生临时对称密钥。
- 使用 AES-256-GCM 通过临时密钥加密密钥材料。
- 连接封装密钥和加密为密文的密钥材料。这是生成的封装密钥,您将使用它来导入密钥。将其另存为
wrapped_key.bin。
以下 Go 代码示例演示了如何使用 tink-go 库封装密钥材料:
package main
import (
"bytes"
"encoding/base64"
"flag"
"fmt"
"log"
"google.golang.org/protobuf/proto"
"github.com/tink-crypto/tink-go/v2/hybrid"
"github.com/tink-crypto/tink-go/v2/keyset"
hpkepb "github.com/tink-crypto/tink-go/v2/proto/hpke_go_proto"
tinkpb "github.com/tink-crypto/tink-go/v2/proto/tink_go_proto"
)
var (
publicKeyB64Flag = flag.String("public_key", "", "Base64 encoded public key for wrapping.")
targetKeyB64Flag = flag.String("target_key", "", "Base64 encoded 32-byte target key to be wrapped.")
)
func main() {
flag.Parse()
if *publicKeyB64Flag == "" {
log.Fatal("-public_key is required")
}
if *targetKeyB64Flag == "" {
log.Fatal("-target_key is required")
}
pkBytes, err := base64.StdEncoding.DecodeString(*publicKeyB64Flag)
if err != nil {
log.Fatalf("failed to decode public key: %v", err)
}
targetKey, err := base64.StdEncoding.DecodeString(*targetKeyB64Flag)
if err != nil {
log.Fatalf("failed to decode target key: %v", err)
}
hpkePubKey := &hpkepb.HpkePublicKey{
Version: 0,
Params: &hpkepb.HpkeParams{
Kem: hpkepb.HpkeKem_ML_KEM768,
Kdf: hpkepb.HpkeKdf_HKDF_SHA256,
Aead: hpkepb.HpkeAead_AES_256_GCM,
},
PublicKey: pkBytes,
}
serializedPubKey, err := proto.Marshal(hpkePubKey)
if err != nil {
log.Fatalf("failed to marshal HPKE public key: %v", err)
}
ks := &tinkpb.Keyset{
PrimaryKeyId: 1,
Key: []*tinkpb.Keyset_Key{
{
KeyData: &tinkpb.KeyData{
TypeUrl: "type.googleapis.com/google.crypto.tink.HpkePublicKey",
Value: serializedPubKey,
KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PUBLIC,
},
Status: tinkpb.KeyStatusType_ENABLED,
KeyId: 1,
OutputPrefixType: tinkpb.OutputPrefixType_RAW,
},
},
}
serializedKeyset, err := proto.Marshal(ks)
if err != nil {
log.Fatalf("failed to marshal keyset: %v", err)
}
// Create a KeysetHandle and retrieve the HybridEncrypt primitive.
reader := keyset.NewBinaryReader(bytes.NewReader(serializedKeyset))
handle, err := keyset.ReadWithNoSecrets(reader)
if err != nil {
log.Fatalf("failed to create keyset handle: %v", err)
}
enc, err := hybrid.NewHybridEncrypt(handle)
if err != nil {
log.Fatalf("failed to create hybrid encrypt primitive: %v", err)
}
// Perform the wrapping operation. Tink's HPKE implementation handles the
// 'enc || ciphertext' concatenation automatically.
wrappedKey, err := enc.Encrypt(targetKey, nil)
if err != nil {
log.Fatalf("failed to wrap key: %v", err)
}
fmt.Printf("Final wrappedKey (base64):\n%s\n", base64.StdEncoding.EncodeToString(wrappedKey))
}
保存输出 base64 字符串或将其解码为二进制文件:
bash
echo "BASE64_WRAPPED_KEY" | base64 --decode > wrapped_key.bin
导入封装的密钥
将准备好的封装密钥作为目标密钥的新密钥版本导入。
gcloud
运行 kms keys versions import 命令:
gcloud kms keys versions import \
--location LOCATION \
--keyring KEY_RING \
--key KEY_NAME \
--import-job IMPORT_JOB \
--algorithm ALGORITHM \
--wrapped-key-file wrapped_key.bin
替换以下内容:
LOCATION:包含目标密钥的密钥环的位置。KEY_RING:包含目标密钥的密钥环的名称。KEY_NAME:目标密钥的名称。IMPORT_JOB:导入作业的名称。ALGORITHM:要导入的密钥材料的算法。
REST
调用 cryptoKeyVersions.import 方法:
curl "https://cloudkms.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY_NAME/cryptoKeyVersions:import" \
--request "POST" \
--header "authorization: Bearer TOKEN" \
--header "content-type: application/json" \
--data '{"importJob": "IMPORT_JOB", "algorithm": "ALGORITHM", "wrappedKey": "PATH_TO_WRAPPED_KEY"}'
替换以下内容:
PROJECT_ID:Cloud KMS 项目的标识符。LOCATION:包含目标密钥的密钥环的位置。KEY_RING:包含目标密钥的密钥环的名称。KEY_NAME:目标密钥的名称。TOKEN:用于对请求进行身份验证的令牌。IMPORT_JOB:相应导入作业的标识符。ALGORITHM:要导入的密钥材料的算法。PATH_TO_WRAPPED_KEY:手动封装的 base64 格式密钥的路径。
检查导入的密钥版本的状态
导入的密钥版本的初始状态为 PENDING_IMPORT。当状态为 ENABLED 时,表示密钥版本已成功导入。如果导入失败,则状态为 IMPORT_FAILED。
您可以使用 Google Cloud CLI、 Google Cloud 控制台或 Cloud Key Management Service API 来检查导入请求的状态。
控制台
在 Google Cloud 控制台中,打开密钥管理 页面。
点击包含导入作业的密钥环的名称。
点击页面顶部的导入作业标签页。
状态将会显示在导入作业名称旁边的状态 下。
gcloud
如需在命令行上使用 Cloud KMS,请先 安装或升级到最新版本的 Google Cloud CLI。
使用 versions list 命令检查状态。使用您在本主题前面创建的同一个位置、目标密钥环和目标密钥。
gcloud kms keys versions list \ --keyring KEY_RING \ --location LOCATION \ --key KEY_NAME
Go
要运行此代码,请先设置 Go 开发环境并 安装 Cloud KMS Go SDK。
Java
要运行此代码,请先设置 Java 开发环境并 安装 Cloud KMS Java SDK。
Node.js
要运行此代码,请先 设置 Node.js 开发环境 并 安装 Cloud KMS Node.js SDK。
Python
要运行此代码,请先设置 Python 开发环境并 安装 Cloud KMS Python SDK。
API
这些示例使用 curl 作为 HTTP 客户端来演示如何使用 API。如需详细了解访问权限控制,请参阅 访问 Cloud KMS API。
调用 ImportJob.get 方法并检查
[state][api_importjob_fields_state] 字段。如果 state 为
PENDING_GENERATION,表示导入作业仍在创建中。
定期重新检查状态,直到状态变为 ACTIVE。
导入初始密钥版本后,密钥的状态会更改为 ENABLED。对于对称密钥,您必须先将导入的密钥版本设置为
主要版本,然后才能使用该密钥。
重新导入先前销毁的密钥
如果您需要将先前导入的处于 DESTROYED 或 IMPORT_FAILED 状态的密钥版本恢复为 ENABLED 状态,可以重新导入完全相同的密钥材料。
重新导入已销毁的密钥版本与初始导入使用相同的过程,使用原始导入作业或新的导入作业(具有相同的 SOFTWARE 保护级别)。