הצפנה ופענוח באמצעות KEM

במסמך הזה מתואר שימוש במנגנוני אריזת מפתחות (KEM) עם מפתחות Cloud KMS כדי ליצור סודות משותפים.

ההצפנה נעשית באמצעות המפתח הציבורי של זוג מפתחות KEM, והפענוח נעשה באמצעות המפתח הפרטי של זוג המפתחות. בעזרת Cloud KMS אפשר לאחזר את המפתח הציבורי, ואז להשתמש בו עם ספריות רגילות כדי להצפין את הסוד המשותף. כדי לבטל את האריזה של הסוד המשותף, משתמשים בשיטות ביטול האריזה של Cloud KMS. אי אפשר להשתמש בחומר המפתח הפרטי מחוץ ל-Cloud KMS.

לפני שמתחילים

  • במסמך הזה מובאות דוגמאות להרצה בשורת הפקודה. כדי לפשט את השימוש בדוגמאות, אפשר להשתמש ב-Cloud Shell. בדוגמה להצפנה נעשה שימוש ב-OpenSSL, שמותקן מראש ב-Cloud Shell. אחרת, צריך להתקין את OpenSSL במחשב.
  • יוצרים מפתח KEM עם key purposeKEY_ENCAPSULATION. כדי לראות אילו אלגוריתמים נתמכים למטרת המפתח KEY_ENCAPSULATION, אפשר לעיין באלגוריתמים של אנקפסולציית מפתחות.

מתן הרשאות למפתח

  • מקצים את התפקיד roles/cloudkms.publicKeyViewer במפתח לכל משתמש או חשבון ראשי שצריך לאחזר את המפתח הציבורי כדי להצפין את הסוד.
  • צריך להעניק את התפקיד roles/cloudkms.decapsulator במפתח לכל משתמש או חשבון ראשי שצריך לבטל את האנקפסולציה של סודות באמצעות המפתח הזה.

מידע נוסף על הרשאות ותפקידים ב-Cloud KMS זמין במאמר הרשאות ותפקידים.

אנקפסולציה

כדי לבצע אנקפסולציה באמצעות מפתח KEM, מאחזרים את המפתח הציבורי ומשתמשים בו לאנקפסולציה.

gcloud

כדי להשתמש בדוגמה הזו, צריך להתקין את OpenSSL במערכת המקומית.

הורדת המפתח הציבורי

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

מחליפים את מה שכתוב בשדות הבאים:

  • KEY_VERSION: מספר הגרסה של המפתח שרוצים להשתמש בו לאנקפסולציה, לדוגמה 2.
  • KEY_NAME: השם של המפתח שרוצים להשתמש בו לאנקפסולציה.
  • KEY_RING: השם של אוסף המפתחות שמכיל את המפתח.
  • LOCATION: המיקום ב-Cloud KMS שבו נמצא אוסף המפתחות.
  • PUBLIC_KEY_FILE: הנתיב המקומי של הקובץ שבו יישמר המפתח הציבורי.
  • PUBLIC_KEY_FORMAT: פורמט היעד של המפתח הציבורי, לדוגמה nist-pqc. פורמט ברירת המחדל הוא pem.

שינוי הפורמט של המפתח הציבורי

הפקודה encapsulate מחייבת שהמפתח הציבורי יהיה בפורמט PEM. אם הורדתם את המפתח הציבורי בפורמט אחר, כמו nist-pqc, אתם צריכים להמיר את המפתח לפורמט PEM. אם המפתח הציבורי כבר בפורמט PEM, אפשר להמשיך לשלב Encapsulate.

משתמשים בפקודה הבאה כדי להמיר את המפתח הציבורי למפתח ML-KEM-768:

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

משתמשים בפקודה הבאה כדי להמיר את המפתח הציבורי למפתח ML-KEM-1024:

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

מחליפים את מה שכתוב בשדות הבאים:

  • PUBLIC_KEY_FILE: הנתיב לקובץ המפתח הציבורי שהורד בפורמט גולמי.
  • PEM_PUBLIC_KEY_FILE: הנתיב ושם הקובץ שבו יישמר המפתח הציבורי בפורמט PEM.

הוספת אנקפסולציה

כדי ליצור סוד לשימוש עם טוקן צרכן ומידע מוצפן (ciphertext), אפשר להשתמש בפקודה הבאה:

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

מחליפים את מה שכתוב בשדות הבאים:

  • PEM_PUBLIC_KEY_FILE: הנתיב לקובץ המפתח הציבורי שהורד בפורמט PEM.
  • CIPHERTEXT_FILE: הנתיב שבו רוצים לשמור את הטקסט המוצפן שמתקבל.
  • SHARED_SECRET_FILE: הנתיב שבו רוצים לשמור את סוד לשימוש עם טוקן צרכן שנוצר.

Go

כדי להריץ את הקוד הזה, קודם צריך להגדיר סביבת פיתוח של Go ולהתקין את Cloud KMS Go SDK.

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