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 poi utilizzare con le librerie standard per incapsulare il segreto condiviso. Per decapsulare il segreto 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

  • Questo documento fornisce esempi che vengono eseguiti dalla riga di comando. Per semplificare l'utilizzo degli esempi, utilizza Cloud Shell. L'esempio di crittografia utilizza OpenSSL, che è preinstallato su Cloud Shell. In caso contrario, installa OpenSSL sulla tua macchina.
  • Crea una chiave KEM con scopo della chiave KEY_ENCAPSULATION. Per vedere quali algoritmi sono supportati per lo scopo della chiave KEY_ENCAPSULATION, consulta Algoritmi di incapsulamento delle chiavi.

Concedi le autorizzazioni per la chiave

Per saperne di più 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 contengono 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.

Riformattare la chiave pubblica

Il comando encapsulate 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 tua 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 segreto condiviso e un testo cifrato, 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 scaricato in formato PEM.
  • CIPHERTEXT_FILE: il percorso in cui vuoi salvare il testo cifrato 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
}

Decapsulation

Utilizza Cloud KMS per decapsulare un testo cifrato.

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 la decapsulamento, ad esempio 3.
  • KEY_NAME: il nome della chiave da utilizzare per la decapsulamento.
  • KEY_RING: il nome del portachiavi 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 cifrato 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 dimostrare l'utilizzo dell'API. Per saperne di più sul controllo dell'accesso, consulta Accesso all'API Cloud KMS.

Utilizza il metodo 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"}'

Sostituisci quanto segue:

  • PROJECT_ID: l'ID del progetto che contiene il portachiavi.
  • LOCATION: la posizione di Cloud KMS delle chiavi automatizzate.
  • KEY_RING: il nome delle chiavi automatizzate che contengono 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 cifrato codificato in base64 che vuoi decapsulare.