Mit KEMs kapseln und entkapseln

In diesem Dokument wird beschrieben, wie Sie Schlüsselkapselungsmechanismen (Key Encapsulation Mechanisms, KEMs) mit Cloud KMS-Schlüsseln verwenden, um gemeinsame Secrets zu erstellen.

Bei der Kapselung wird der öffentliche Schlüssel des KEM-Schlüsselpaars und bei der Entkapselung der private Schlüssel des Schlüsselpaars verwendet. Mit Cloud KMS können Sie den öffentlichen Schlüssel abrufen, den Sie dann mit Standardbibliotheken verwenden können, um Ihr gemeinsames Secret zu kapseln. Verwenden Sie Cloud KMS-Decapsulation-Methoden, um das gemeinsame Secret zu decapsulieren. Sie können das Material des privaten Schlüssels nicht außerhalb von Cloud KMS verwenden.

Hinweise

  • In diesem Dokument finden Sie Beispiele, bei denen die Befehlszeile verwendet wird. Wenn Sie die Anwendung der Beispiele vereinfachen möchten, können Sie Cloud Shell verwenden. Für das Verschlüsselungsbeispiel wird OpenSSL verwendet, das in Cloud Shell vorinstalliert ist. Andernfalls installieren Sie OpenSSL auf Ihrem Computer.
  • Erstellen Sie einen KEM-Schlüssel mit dem Schlüsselzweck KEY_ENCAPSULATION. Unter Schlüsselkapselungsalgorithmen finden Sie Informationen dazu, welche Algorithmen für den Schlüsselzweck KEY_ENCAPSULATION unterstützt werden.

Berechtigungen für den Schlüssel erteilen

  • Weisen Sie jedem Nutzer oder Prinzipal, der den öffentlichen Schlüssel zum Kapseln des Secrets abrufen muss, die Rolle roles/cloudkms.publicKeyViewer für den Schlüssel zu.
  • Weisen Sie jedem Nutzer oder Hauptkonto, das Secrets mit diesem Schlüssel entkapseln muss, die Rolle roles/cloudkms.decapsulator für den Schlüssel zu.

Weitere Informationen zu Berechtigungen und Rollen in Cloud KMS finden Sie unter Berechtigungen und Rollen.

Datenkapselung

Wenn Sie einen KEM-Schlüssel verwenden möchten, um Daten zu kapseln, rufen Sie den öffentlichen Schlüssel ab und verwenden Sie ihn zum Kapseln.

gcloud

Für dieses Beispiel muss OpenSSL auf Ihrem lokalen System installiert sein.

Öffentlichen Schlüssel herunterladen

gcloud kms keys versions get-public-key KEY_VERSION \
    --key KEY_NAME \
    --keyring KEY_RING \
    --location LOCATION  \
    --output-file PUBLIC_KEY_FILE \
    --public-key-format PUBLIC_KEY_FORMAT

Ersetzen Sie Folgendes:

  • KEY_VERSION: Die Versionsnummer des Schlüssels, den Sie für die Kapselung verwenden möchten, z. B. 2.
  • KEY_NAME: Der Name des Schlüssels, den Sie für die Kapselung verwenden möchten.
  • KEY_RING: der Name des Schlüsselbunds, der den Schlüssel enthält
  • LOCATION: der Cloud KMS-Speicherort des Schlüsselbunds.
  • PUBLIC_KEY_FILE: Der lokale Dateipfad, in dem der öffentliche Schlüssel gespeichert wird.
  • PUBLIC_KEY_FORMAT: Das Zielformat für den öffentlichen Schlüssel, z. B. nist-pqc. Das Standardformat ist pem.

Öffentlichen Schlüssel neu formatieren

Für den Befehl „encapsulate“ muss der öffentliche Schlüssel im PEM-Format vorliegen. Wenn Sie den öffentlichen Schlüssel in einem anderen Format wie nist-pqc heruntergeladen haben, müssen Sie ihn in das PEM-Format konvertieren. Wenn Ihr öffentlicher Schlüssel bereits im PEM-Format vorliegt, fahren Sie mit Encapsulate fort.

Verwenden Sie den folgenden Befehl, um den öffentlichen Schlüssel für einen ML-KEM-768-Schlüssel zu konvertieren:

{ echo -n "MIIEsjALBglghkgBZQMEBAIDggShAA==" | base64 -d ; cat PUBLIC_KEY_FILE; } | \
openssl pkey -inform DER -pubin -pubout -out PEM_PUBLIC_KEY_FILE

Verwenden Sie den folgenden Befehl, um den öffentlichen Schlüssel für einen ML-KEM-1024-Schlüssel zu konvertieren:

{ echo -n "MIIGMjALBglghkgBZQMEBAMDggYhAA==" | base64 -d ; cat PUBLIC_KEY_FILE; } | \
openssl pkey -inform DER -pubin -pubout -out PEM_PUBLIC_KEY_FILE

Ersetzen Sie Folgendes:

  • PUBLIC_KEY_FILE: Der Pfad zur heruntergeladenen Datei mit dem öffentlichen Schlüssel im Rohformat.
  • PEM_PUBLIC_KEY_FILE: Der Pfad und der Dateiname, unter dem der öffentliche Schlüssel im PEM-Format gespeichert werden soll.

Kapseln

Mit dem folgenden Befehl können Sie ein gemeinsames Secret und einen Chiffretext erstellen:

openssl pkeyutl \
    -encap \
    -pubin \
    -inkey PEM_PUBLIC_KEY_FILE \
    -out CIPHERTEXT_FILE \
    -secret SHARED_SECRET_FILE

Ersetzen Sie Folgendes:

  • PEM_PUBLIC_KEY_FILE: Der Pfad zur heruntergeladenen Datei mit dem öffentlichen Schlüssel im PEM-Format.
  • CIPHERTEXT_FILE: Der Pfad, unter dem Sie den resultierenden Chiffretext speichern möchten.
  • SHARED_SECRET_FILE: Der Pfad, unter dem Sie das resultierende gemeinsame Secret speichern möchten.

Go

Um diesen Code auszuführen, müssen Sie zuerst eine Go-Entwicklungsumgebung einrichten und das Cloud KMS Go SDK installieren.

import (
	"context"
	"crypto/mlkem"
	"fmt"
	"hash/crc32"
	"io"

	kms "cloud.google.com/go/kms/apiv1"
	"cloud.google.com/go/kms/apiv1/kmspb"
)

// encapsulateMLKEM demonstrates how to encapsulate a shared secret using an ML-KEM-768 public key
// from Cloud KMS.
func encapsulateMLKEM(w io.Writer, keyVersionName string) error {
	// keyVersionName := "projects/my-project/locations/us-east1/keyRings/my-key-ring/cryptoKeys/my-key/cryptoKeyVersions/1"

	// Create the client.
	ctx := context.Background()
	client, err := kms.NewKeyManagementClient(ctx)
	if err != nil {
		return fmt.Errorf("failed to create kms client: %w", err)
	}
	defer client.Close()

	// crc32c calculates the CRC32C checksum of the given data.
	crc32c := func(data []byte) uint32 {
		t := crc32.MakeTable(crc32.Castagnoli)
		return crc32.Checksum(data, t)
	}

	// Build the request to get the public key in NIST PQC format.
	req := &kmspb.GetPublicKeyRequest{
		Name:            keyVersionName,
		PublicKeyFormat: kmspb.PublicKey_NIST_PQC,
	}

	// Call the API to get the public key.
	response, err := client.GetPublicKey(ctx, req)
	if err != nil {
		return fmt.Errorf("failed to get public key: %w", err)
	}

	// Optional, but recommended: perform integrity verification on the response.
	// For more details on ensuring E2E in-transit integrity to and from Cloud KMS visit:
	// https://cloud.google.com/kms/docs/data-integrity-guidelines
	if response.GetName() != req.GetName() {
		return fmt.Errorf("GetPublicKey: request corrupted in-transit")
	}
	if response.GetPublicKeyFormat() != req.GetPublicKeyFormat() {
		return fmt.Errorf("GetPublicKey: request corrupted in-transit")
	}
	if int64(crc32c(response.GetPublicKey().GetData())) != response.GetPublicKey().GetCrc32CChecksum().GetValue() {
		return fmt.Errorf("GetPublicKey: response corrupted in-transit")
	}

	// Use the public key with crypto/mlkem to encapsulate a shared secret.
	ek, err := mlkem.NewEncapsulationKey768(response.GetPublicKey().GetData())
	if err != nil {
		return fmt.Errorf("NewEncapsulationKey768: %w", err)
	}
	sharedSecret, ciphertext := ek.Encapsulate()

	fmt.Fprintf(w, "Encapsulated ciphertext: %x\n", ciphertext)
	fmt.Fprintf(w, "Shared secret: %x\n", sharedSecret)
	return nil
}

Entkapselung

Cloud KMS zum Entkapseln eines Geheimtexts verwenden

gcloud

Wenn Sie Cloud KMS in der Befehlszeile verwenden möchten, müssen Sie zuerst Google Cloud CLI installieren oder ein Upgrade ausführen.

gcloud kms decapsulate \
    --version KEY_VERSION \
    --key KEY_NAME \
    --keyring KEY_RING \
    --location LOCATION  \
    --ciphertext-file CIPHERTEXT_FILE \
    --shared-secret-file SHARED_SECRET_FILE

Ersetzen Sie Folgendes:

  • KEY_VERSION: Die Schlüsselversion, die für die Entkapselung verwendet werden soll, z. B. 3.
  • KEY_NAME: Der Name des Schlüssels, der für die Entkapselung verwendet werden soll.
  • KEY_RING: der Name des Schlüsselbunds, in dem sich der Schlüssel befindet
  • LOCATION: der Cloud KMS-Speicherort für den Schlüsselbund.
  • CIPHERTEXT_FILE: Der lokale Dateipfad für den Eingabe-Chiffretext.
  • SHARED_SECRET_FILE: der lokale Dateipfad zum Speichern des ausgegebenen gemeinsamen Secrets.

Go

Um diesen Code auszuführen, müssen Sie zuerst eine Go-Entwicklungsumgebung einrichten und das Cloud KMS Go SDK installieren.

import (
	"context"
	"fmt"
	"hash/crc32"
	"io"

	kms "cloud.google.com/go/kms/apiv1"
	"cloud.google.com/go/kms/apiv1/kmspb"
	"google.golang.org/protobuf/types/known/wrapperspb"
)

// decapsulate decapsulates the given ciphertext using a saved private key of purpose
// KEY_ENCAPSULATION stored in KMS.
func decapsulate(w io.Writer, keyVersionName string, ciphertext []byte) error {
	// keyVersionName := "projects/my-project/locations/us-east1/keyRings/my-key-ring/cryptoKeys/my-key/cryptoKeyVersions/1"
	// ciphertext := []byte("...")

	// Create the client.
	ctx := context.Background()
	client, err := kms.NewKeyManagementClient(ctx)
	if err != nil {
		return fmt.Errorf("failed to create kms client: %w", err)
	}
	defer client.Close()

	// crc32c calculates the CRC32C checksum of the given data.
	crc32c := func(data []byte) uint32 {
		t := crc32.MakeTable(crc32.Castagnoli)
		return crc32.Checksum(data, t)
	}

	// Optional but recommended: Compute ciphertext's CRC32C.
	ciphertextCRC32C := crc32c(ciphertext)

	// Build the request.
	req := &kmspb.DecapsulateRequest{
		Name:             keyVersionName,
		Ciphertext:       ciphertext,
		CiphertextCrc32C: wrapperspb.Int64(int64(ciphertextCRC32C)),
	}

	// Call the API.
	result, err := client.Decapsulate(ctx, req)
	if err != nil {
		return fmt.Errorf("failed to decapsulate: %w", err)
	}

	// Optional, but recommended: perform integrity verification on the response.
	// For more details on ensuring E2E in-transit integrity to and from Cloud KMS visit:
	// https://cloud.google.com/kms/docs/data-integrity-guidelines
	if !result.GetVerifiedCiphertextCrc32C() {
		return fmt.Errorf("Decapsulate: request corrupted in-transit")
	}
	if result.GetName() != req.GetName() {
		return fmt.Errorf("Decapsulate: request corrupted in-transit")
	}
	if int64(crc32c(result.GetSharedSecret())) != result.GetSharedSecretCrc32C() {
		return fmt.Errorf("Decapsulate: response corrupted in-transit")
	}

	fmt.Fprintf(w, "Decapsulated plaintext: %x", result.GetSharedSecret())
	return nil
}

API

In diesen Beispielen wird curl als HTTP-Client verwendet, um die Verwendung der API zu demonstrieren. Weitere Informationen zur Zugriffssteuerung finden Sie unter Auf die Cloud KMS API zugreifen.

Verwenden Sie die Methode CryptoKeyVersions.decapsulate.

curl "https://cloudkms.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY_NAME/cryptoKeyVersions/KEY_VERSION:decapsulate" \
  --request "POST" \
  --header "authorization: Bearer TOKEN" \
  --header "content-type: application/json" \
  --data '{"ciphertext": "CIPHERTEXT"}'

Ersetzen Sie Folgendes:

  • PROJECT_ID: die ID des Projekts, das den Schlüsselbund enthält.
  • LOCATION: der Cloud KMS-Speicherort des Schlüsselbunds.
  • KEY_RING: der Name des Schlüsselbunds, der den Schlüssel enthält
  • KEY_NAME: Der Name des Schlüssels, der für die Verschlüsselung verwendet werden soll.
  • KEY_VERSION: Die ID der Schlüsselversion, die für die Verschlüsselung verwendet werden soll.
  • CIPHERTEXT: Der base64-codierte Chiffretext, den Sie entkapseln möchten.