Encapsuler et décapsuler à l'aide de KEM

Ce document décrit l'utilisation de mécanismes d'encapsulation de clés (KEM) avec des clés Cloud KMS pour établir des codes secrets partagés.

L'encapsulation utilise la clé publique de la paire de clés KEM, et la décapsulation utilise la clé privée de la paire de clés. Cloud KMS vous permet de récupérer la clé publique, que vous pouvez ensuite utiliser avec des bibliothèques standards pour encapsuler votre code secret partagé. Pour décapsuler le code secret partagé, utilisez les méthodes de décapsulation Cloud KMS. Vous ne pouvez pas utiliser le matériel de clé privée en dehors de Cloud KMS.

Avant de commencer

  • Cette rubrique fournit des exemples qui s'exécutent sur la ligne de commande. Pour simplifier l'utilisation des exemples, utilisez Cloud Shell. L'exemple de chiffrement utilise OpenSSL, pré-installé sur Cloud Shell. Sinon, installez OpenSSL sur votre ordinateur.
  • Créez une clé KEM avec l'objectif de clé de KEY_ENCAPSULATION. Pour savoir quels algorithmes sont compatibles avec l'objectif de clé KEY_ENCAPSULATION, consultez la page Algorithmes d'encapsulation de clés.

Accorder des autorisations sur la clé

  • Accordez le roles/cloudkms.publicKeyViewer rôle sur la clé à chaque utilisateur ou principal qui doit récupérer la clé publique pour encapsuler le code secret.
  • Accordez le 'roles/cloudkms.decapsulator' rôle sur la clé à chaque utilisateur ou principal qui doit décapsuler des codes secrets avec cette clé.

Pour en savoir plus sur les autorisations et les rôles dans Cloud KMS, consultez la page Autorisations et rôles.

Encapsulation

Pour encapsuler à l'aide d'une clé KEM, récupérez la clé publique et utilisez-la pour encapsuler.

gcloud

Dans cet exemple, OpenSSL doit être installé sur votre système local.

Télécharger la clé publique

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

Remplacez les éléments suivants :

  • KEY_VERSION: numéro de version de la clé que vous souhaitez utiliser pour l'encapsulation, par exemple 2.
  • KEY_NAME: nom de la clé que vous souhaitez utiliser pour l'encapsulation.
  • KEY_RING : nom du trousseau de clés qui inclut la clé
  • LOCATION : emplacement Cloud KMS du trousseau de clés
  • PUBLIC_KEY_FILE: chemin d'accès au fichier local dans lequel la clé publique sera enregistrée
  • PUBLIC_KEY_FORMAT: format cible de la clé publique, par exemple nist-pqc. Le format par défaut est pem.

Reformater la clé publique

La commande d'encapsulation nécessite que la clé publique soit au format PEM. Si vous avez téléchargé la clé publique dans un autre format, tel que nist-pqc, vous devez la convertir au format PEM. Si votre clé publique est déjà au format PEM, passez à la section Encapsuler.

Utilisez la commande suivante pour convertir la clé publique d'une clé ML-KEM-768 :

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

Utilisez la commande suivante pour convertir la clé publique d'une clé ML-KEM-1024 :

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

Remplacez les éléments suivants :

  • PUBLIC_KEY_FILE: chemin d'accès au fichier de clé publique téléchargé au format brut
  • PEM_PUBLIC_KEY_FILE: chemin d'accès et nom de fichier pour enregistrer la clé publique au format PEM

Encapsuler

Pour créer un code secret partagé et un texte chiffré, vous pouvez utiliser la commande suivante :

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

Remplacez les éléments suivants :

  • PEM_PUBLIC_KEY_FILE: chemin d'accès au fichier de clé publique téléchargé au format PEM
  • CIPHERTEXT_FILE: chemin d'accès où vous souhaitez enregistrer le texte chiffré résultant
  • SHARED_SECRET_FILE: chemin d'accès où vous souhaitez enregistrer le code secret partagé résultant

Go

Pour exécuter ce code, commencez par configurer un environnement de développement Go, puis installez le SDK Cloud KMS pour Go.

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
}

Décapsulation

Utilisez Cloud KMS pour décapsuler un texte chiffré.

gcloud

Pour utiliser Cloud KMS sur la ligne de commande, commencez par installer ou mettre à jour la dernière version de Google Cloud CLI.

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

Remplacez les éléments suivants :

  • KEY_VERSION : version de la clé à utiliser pour la décapsulation, par exemple 3
  • KEY_NAME : nom de la clé à utiliser pour la décapsulation
  • KEY_RING : nom du trousseau de clés dans lequel se trouve la clé
  • LOCATION : emplacement Cloud KMS du trousseau de clés
  • CIPHERTEXT_FILE: chemin d'accès au fichier local pour le texte chiffré d'entrée
  • SHARED_SECRET_FILE: chemin d'accès au fichier local pour enregistrer le code secret partagé de sortie

Go

Pour exécuter ce code, commencez par configurer un environnement de développement Go, puis installez le SDK Cloud KMS pour Go.

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

Ces exemples utilisent curl comme client HTTP pour démontrer l'utilisation de l'API. Pour en savoir plus sur le contrôle des accès, consultez la page Accéder à l'API Cloud KMS.

Utilisez la CryptoKeyVersions.decapsulate méthode.

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"}'

Remplacez les éléments suivants :

  • PROJECT_ID : ID du projet contenant le trousseau de clés
  • LOCATION : emplacement Cloud KMS du trousseau de clés
  • KEY_RING : nom du trousseau de clés qui inclut la clé
  • KEY_NAME : nom de la clé à utiliser pour le chiffrement
  • KEY_VERSION : ID de la version de clé à utiliser pour le chiffrement
  • CIPHERTEXT: texte chiffré encodé en base64 que vous souhaitez décapsuler