Encrypting and decrypting data with an asymmetric key

This topic provides information about creating and using a key for asymmetric encryption using an RSA key. If you want to use asymmetric keys for creating and validating signatures, see Creating and validating digital signatures. If you want to use symmetric keys for encryption and decryption, see Encrypting and decrypting data.

Asymmetric encryption uses the public key portion of the asymmetric key and decryption uses the private key portion of the key. Cloud KMS provides functionality to retrieve the public key and functionality to decrypt ciphertext that was encrypted with the public key. Cloud KMS does not allow direct access to the private key.

Before you begin

Access control to the key

  • For a user or service that will retrieve the public key, grant the cloudkms.cryptoKeyVersions.viewPublicKey permission on the asymmetric key. The public key is required for encrypting data.

  • For a user or service that will decrypt data that was encrypted with the public key, grant the cloudkms.cryptoKeyVersions.useToDecrypt permission on the asymmetric key.

Learn about permissions and roles in Cloud KMS at Permissions and Roles.

Encrypt data

If you don't already have the public key, retrieve the public key.

Command-line

This example assumes the public key is in a file named rsa-decrypt-key.pub.

  1. Click the Activate Cloud Shell button at the top of the console window. Activate Cloud Shell A Cloud Shell session opens inside a new frame at the bottom of the console and displays a command-line prompt. It can take a few seconds for the shell session to be initialized. Cloud Shell session

  2. At the Cloud Shell command-line prompt, create a plaintext file.

    echo "my secret message" > ~/my-secret-file
    
  3. Use OpenSSL to encrypt the file. The example uses the SHA-256 digest. Currently all asymmetric encryption algorithms use the SHA-256 digest.

    openssl pkeyutl -in ~/my-secret-file \
      -encrypt -pubin \
      -inkey ~/rsa-decrypt-key.pub \
      -pkeyopt rsa_padding_mode:oaep \
      -pkeyopt rsa_oaep_md:sha256 \
      -pkeyopt rsa_mgf1_md:sha256 > ~/my-secret-file.enc
    

Go

import (
	"context"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/x509"
	"encoding/pem"
	"fmt"

	cloudkms "cloud.google.com/go/kms/apiv1"
	kmspb "google.golang.org/genproto/googleapis/cloud/kms/v1"
)

// encryptRSA will encrypt data locally using an 'RSA_DECRYPT_OAEP_2048_SHA256'
// public key retrieved from Cloud KMS.
func encryptRSA(name string, plaintext []byte) ([]byte, error) {
	// name: "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys/KEY_ID/cryptoKeyVersions/1"
	// plaintext := []byte("Sample message")
	ctx := context.Background()
	client, err := cloudkms.NewKeyManagementClient(ctx)
	if err != nil {
		return nil, fmt.Errorf("cloudkms.NewKeyManagementClient: %v", err)
	}

	// Retrieve the public key from KMS.
	response, err := client.GetPublicKey(ctx, &kmspb.GetPublicKeyRequest{Name: name})
	if err != nil {
		return nil, fmt.Errorf("GetPublicKey: %v", err)
	}
	// Parse the key.
	block, _ := pem.Decode([]byte(response.Pem))
	abstractKey, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return nil, fmt.Errorf("x509.ParsePKIXPublicKey: %+v", err)
	}
	rsaKey, ok := abstractKey.(*rsa.PublicKey)
	if !ok {
		return nil, fmt.Errorf("key %q is not RSA", name)
	}
	// Encrypt data using the RSA public key.
	ciphertext, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, rsaKey, plaintext, nil)
	if err != nil {
		return nil, fmt.Errorf("rsa.EncryptOAEP: %v", err)
	}
	return ciphertext, nil
}

Java

/**
 * Encrypt data locally using an 'RSA_DECRYPT_OAEP_2048_SHA256' public key
 * retrieved from Cloud KMS
 *
 * Example keyName:
 *   "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys/KEY_ID/cryptoKeyVersions/1"
 */
public static byte[] encryptRSA(String keyName, byte[] plaintext)
    throws IOException, GeneralSecurityException {
  // Create the Cloud KMS client.
  try (KeyManagementServiceClient client = KeyManagementServiceClient.create()) {
    // Get the public key
    com.google.cloud.kms.v1.PublicKey pub = client.getPublicKey(keyName);
    String pemKey = pub.getPem();
    pemKey = pemKey.replaceFirst("-----BEGIN PUBLIC KEY-----", "");
    pemKey = pemKey.replaceFirst("-----END PUBLIC KEY-----", "");
    pemKey = pemKey.replaceAll("\\s", "");
    byte[] derKey = BaseEncoding.base64().decode(pemKey);
    X509EncodedKeySpec keySpec = new X509EncodedKeySpec(derKey);
    PublicKey rsaKey = KeyFactory.getInstance("RSA").generatePublic(keySpec);

    // Encrypt plaintext for the 'RSA_DECRYPT_OAEP_2048_SHA256' key.
    // For other key algorithms:
    // https://docs.oracle.com/javase/7/docs/api/javax/crypto/Cipher.html
    Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
    OAEPParameterSpec oaepParams = new OAEPParameterSpec(
        "SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT);
    cipher.init(Cipher.ENCRYPT_MODE, rsaKey, oaepParams);

    return cipher.doFinal(plaintext);
  }
}

Python

def encrypt_rsa(plaintext, key_name):
    """
    Encrypt the input plaintext (bytes) locally using an
    'RSA_DECRYPT_OAEP_2048_SHA256' public key retrieved from Cloud KMS

    Example key_name:
      "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys\
              /KEY_ID/cryptoKeyVersions/1"

    Requires:
      cryptography.hazmat.primitives.asymmetric.padding
      cryptography.hazmat.primitives.hashes
    """
    # get the public key
    client = kms_v1.KeyManagementServiceClient()
    response = client.get_public_key(key_name)
    key_txt = response.pem.encode('ascii')
    public_key = serialization.load_pem_public_key(key_txt, default_backend())

    # encrypt plaintext
    pad = padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()),
                       algorithm=hashes.SHA256(),
                       label=None)
    return public_key.encrypt(plaintext, pad)

Decrypt data

Use Cloud KMS to perform the decryption.

Command-line

gcloud kms asymmetric-decrypt \
  --location [LOCATION] \
  --keyring [KEYRING_NAME] \
  --key [KEY_NAME] \
  --version [KEY_VERSION] \
  --ciphertext-file ~/my-secret-file.enc \
  --plaintext-file ~/my-secret-file.dec

Display the contents of the decrypted file.

cat ~/my-secret-file.dec

You should see the same text that you created for your plaintext file.

my secret message

API

Use the CryptoKeyVersions.asymmetricDecrypt method.

  • Set the request's ciphertext value to the ciphertext that was created when you encrypted the plaintext.

The CryptoKeyVersions.asymmetricDecrypt response contains the decrypted data.

Go

import (
	"context"
	"fmt"

	cloudkms "cloud.google.com/go/kms/apiv1"
	kmspb "google.golang.org/genproto/googleapis/cloud/kms/v1"
)

// decryptRSA will attempt to decrypt a given ciphertext with an
// 'RSA_DECRYPT_OAEP_2048_SHA256' private key stored on Cloud KMS.
func decryptRSA(name string, ciphertext []byte) ([]byte, error) {
	// name := "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys/KEY_ID/cryptoKeyVersions/1"
	// ciphertext, err := encryptRSA(rsaDecryptPath, []byte("Sample message"))
	// if err != nil {
	//   return nil, fmt.Errorf("encryptRSA: %v", err)
	// }
	ctx := context.Background()
	client, err := cloudkms.NewKeyManagementClient(ctx)
	if err != nil {
		return nil, fmt.Errorf("cloudkms.NewKeyManagementClient: %v", err)
	}

	// Build the request.
	req := &kmspb.AsymmetricDecryptRequest{
		Name:       name,
		Ciphertext: ciphertext,
	}
	// Call the API.
	response, err := client.AsymmetricDecrypt(ctx, req)
	if err != nil {
		return nil, fmt.Errorf("AsymmetricDecrypt: %v", err)
	}
	return response.Plaintext, nil
}

Java

/**
 * Decrypt a given ciphertext using an 'RSA_DECRYPT_OAEP_2048_SHA256' private key
 * stored on Cloud KMS
 *
 * Example keyName:
 *   "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys/KEY_ID/cryptoKeyVersions/1"
 */
public static byte[] decryptRSA(String keyName, byte[] ciphertext) throws IOException {
  // Create the Cloud KMS client.
  try (KeyManagementServiceClient client = KeyManagementServiceClient.create()) {
    AsymmetricDecryptResponse response = client.asymmetricDecrypt(
        keyName, ByteString.copyFrom(ciphertext));
    return response.getPlaintext().toByteArray();
  }
}

Python

def decrypt_rsa(ciphertext, key_name):
    """
    Decrypt the input ciphertext (bytes) using an
    'RSA_DECRYPT_OAEP_2048_SHA256' private key stored on Cloud KMS

    Example key_name:
      "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys\
              /KEY_ID/cryptoKeyVersions/1"
    """

    client = kms_v1.KeyManagementServiceClient()
    response = client.asymmetric_decrypt(key_name, ciphertext)
    return response.plaintext

Bu sayfayı yararlı buldunuz mu? Lütfen görüşünüzü bildirin:

Şunun hakkında geri bildirim gönderin...