Incapsulamento e decapsulamento utilizzando KEM

Questo documento descrive l'utilizzo dei meccanismi di incapsulamento delle chiavi (KEM) con le chiavi Cloud KMS per stabilire secret condivisi.

L'incapsulamento utilizza la chiave pubblica della coppia di chiavi KEM, mentre il decapsulamento utilizza la chiave privata della coppia di chiavi. Cloud KMS ti consente di recuperare la chiave pubblica, che puoi quindi utilizzare con le librerie standard per incapsulare il secret condiviso. Per decapsulare il secret condiviso, utilizza i metodi di decapsulamento di Cloud KMS. Non puoi utilizzare il materiale della chiave privata al di fuori di Cloud KMS.

Prima di iniziare

Concedi le autorizzazioni per la chiave

Per ulteriori informazioni su autorizzazioni e ruoli in Cloud KMS, consulta Autorizzazioni e ruoli.

Incapsulamento

Per eseguire l'incapsulamento utilizzando una chiave KEM, recupera la chiave pubblica e utilizzala per l'incapsulamento.

gcloud

Questo esempio richiede l'installazione di OpenSSL sul sistema locale.

Scarica la chiave pubblica

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

Sostituisci quanto segue:

  • KEY_VERSION: il numero di versione della chiave che vuoi utilizzare per l'incapsulamento, ad esempio 2.
  • KEY_NAME: il nome della chiave che vuoi utilizzare per l'incapsulamento.
  • KEY_RING: il nome delle chiavi automatizzate che contiene la chiave.
  • LOCATION: la posizione di Cloud KMS delle chiavi automatizzate.
  • PUBLIC_KEY_FILE: il percorso del file locale in cui verrà salvata la chiave pubblica.
  • PUBLIC_KEY_FORMAT: il formato di destinazione per la chiave pubblica, ad esempio nist-pqc. Il formato predefinito è pem.

Riformatta la chiave pubblica

Il comando di incapsulamento richiede che la chiave pubblica sia in formato PEM. Se hai scaricato la chiave pubblica in un altro formato, ad esempio nist-pqc, devi convertirla in formato PEM. Se la chiave pubblica è già in formato PEM, continua da Incapsula.

Utilizza il seguente comando per convertire la chiave pubblica per una chiave ML-KEM-768:

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

Utilizza il seguente comando per convertire la chiave pubblica per una chiave ML-KEM-1024:

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

Sostituisci quanto segue:

  • PUBLIC_KEY_FILE: il percorso del file della chiave pubblica scaricata in formato non elaborato.
  • PEM_PUBLIC_KEY_FILE: il percorso e il nome del file in cui salvare la chiave pubblica in formato PEM.

Incapsula

Per creare un secret condiviso e un testo crittografato, puoi utilizzare il seguente comando:

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

Sostituisci quanto segue:

  • PEM_PUBLIC_KEY_FILE: il percorso del file della chiave pubblica scaricata in formato PEM.
  • CIPHERTEXT_FILE: il percorso in cui vuoi salvare il testo crittografato risultante.
  • SHARED_SECRET_FILE: il percorso in cui vuoi salvare il secret condiviso risultante.

Go

Per eseguire questo codice, devi innanzitutto configurare un ambiente di sviluppo Go e installare l'SDK Go di Cloud KMS.

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
}

Decapsulamento

Utilizza Cloud KMS per decapsulare un testo crittografato.

gcloud

Per utilizzare Cloud KMS dalla riga di comando, devi prima installare o eseguire l'upgrade all'ultima versione di 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

Sostituisci quanto segue:

  • KEY_VERSION: la versione della chiave da utilizzare per il decapsulamento, ad esempio 3.
  • KEY_NAME: il nome della chiave da utilizzare per il decapsulamento.
  • KEY_RING: il nome delle chiavi automatizzate in cui si trova la chiave.
  • LOCATION: la posizione di Cloud KMS per le chiavi automatizzate.
  • CIPHERTEXT_FILE: il percorso del file locale per il testo crittografato di input.
  • SHARED_SECRET_FILE: il percorso del file locale per salvare il secret condiviso di output.

Go

Per eseguire questo codice, devi innanzitutto configurare un ambiente di sviluppo Go e installare l'SDK Go di Cloud KMS.

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

Questi esempi utilizzano curl come client HTTP per mostrare l'utilizzo dell'API. Per ulteriori informazioni sul controllo dell'accesso, consulta Accesso all'API Cloud KMS.

Utilizza il CryptoKeyVersions.decapsulate metodo.

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

Sostituisci quanto segue:

  • PROJECT_ID: l'ID del progetto che contiene le chiavi automatizzate.
  • LOCATION: la posizione di Cloud KMS delle chiavi automatizzate.
  • KEY_RING: il nome delle chiavi automatizzate che contiene la chiave.
  • KEY_NAME: il nome della chiave da utilizzare per la crittografia.
  • KEY_VERSION: l'ID della versione della chiave da utilizzare per la crittografia.
  • CIPHERTEXT: il testo crittografato codificato in Base64 che vuoi decapsulare.