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

func encryptRSA(ctx context.Context, client *cloudkms.Service, keyPath string, plaintext []byte) ([]byte, error) {
	abstractKey, err := getAsymmetricPublicKey(ctx, client, keyPath)
	if err != nil {
		return nil, err
	}

	// Perform type assertion to get the RSA key.
	rsaKey := abstractKey.(*rsa.PublicKey)

	ciphertext, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, rsaKey, plaintext, nil)
	if err != nil {
		return nil, fmt.Errorf("encryption failed: %+v", err)
	}
	return ciphertext, nil
}

Java

/**
 * Encrypt message locally using an 'RSA_DECRYPT_OAEP_2048_SHA256' public key 
 * retrieved from Cloud KMS 
 */
public static String encryptRSA(String message, CloudKMS client, String keyPath)
    throws IOException, IllegalBlockSizeException, NoSuchPaddingException,
           InvalidKeySpecException, NoSuchProviderException, BadPaddingException,
           NoSuchAlgorithmException, InvalidKeyException {
  Security.addProvider(new BouncyCastleProvider());
  PublicKey rsaKey = getAsymmetricPublicKey(client, keyPath);

  Cipher cipher = Cipher.getInstance("RSA/NONE/OAEPWITHSHA256ANDMGF1PADDING", "BC");
  cipher.init(Cipher.ENCRYPT_MODE, rsaKey);
  byte[] ciphertext = cipher.doFinal(message.getBytes(StandardCharsets.UTF_8));
  return Base64.getEncoder().encodeToString(ciphertext);
}

Python

def encryptRSA(plaintext, client, key_path):
    """
    Encrypt the input plaintext (bytes) locally using an
    'RSA_DECRYPT_OAEP_2048_SHA256' public key retrieved from Cloud KMS
    """
    public_key = getAsymmetricPublicKey(client, key_path)
    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 alpha 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

func decryptRSA(ctx context.Context, client *cloudkms.Service, keyPath string, ciphertext []byte) ([]byte, error) {
	decryptRequest := &cloudkms.AsymmetricDecryptRequest{
		Ciphertext: base64.StdEncoding.EncodeToString(ciphertext),
	}
	response, err := client.Projects.Locations.KeyRings.CryptoKeys.CryptoKeyVersions.
		AsymmetricDecrypt(keyPath, decryptRequest).Context(ctx).Do()
	if err != nil {
		return nil, fmt.Errorf("decryption request failed: %+v", err)
	}
	plaintext, err := base64.StdEncoding.DecodeString(response.Plaintext)
	if err != nil {
		return nil, fmt.Errorf("failed to decode decryted string: %+v", err)

	}
	return plaintext, nil
}

Java

/**
 * Decrypt a given ciphertext using an 'RSA_DECRYPT_OAEP_2048_SHA256' private key 
 * stored on Cloud KMS
 */
public static String decryptRSA(String ciphertext, CloudKMS client, String keyPath) 
    throws IOException {
  AsymmetricDecryptRequest request = new AsymmetricDecryptRequest().setCiphertext(ciphertext);
  AsymmetricDecryptResponse response = client.projects()
                                             .locations()
                                             .keyRings()
                                             .cryptoKeys()
                                             .cryptoKeyVersions()
                                             .asymmetricDecrypt(keyPath, request)
                                             .execute();
  return new String(response.decodePlaintext());
}

Python

def decryptRSA(ciphertext, client, key_path):
    """
    Decrypt the input ciphertext (bytes) using an
    'RSA_DECRYPT_OAEP_2048_SHA256' private key stored on Cloud KMS
    """
    request_body = {'ciphertext': base64.b64encode(ciphertext).decode('utf-8')}
    request = client.projects() \
                    .locations() \
                    .keyRings() \
                    .cryptoKeys() \
                    .cryptoKeyVersions() \
                    .asymmetricDecrypt(name=key_path,
                                       body=request_body)
    response = request.execute()
    plaintext = base64.b64decode(response['plaintext'])
    return plaintext

Was this page helpful? Let us know how we did:

Send feedback about...

Cloud KMS Documentation